

importPackage (java.security);
importPackage (java.io);


var LAM_PASSWORD_CHALLENGE = 0;
var LAM_SIGNATURE_CHALLENGE = 1;

var RESULT_OK = 0;
var RESULT_ERROR = 2;

var ASSET_AUTH_CERT = "auth_cert";

var SIGNATURE_ALGO = "SHA1withRSA";


function getPasswordResponse (password, challenge) {
	var md = MessageDigest.getInstance ("SHA-256");
	
	md.reset();
	md.update (stringToBytes (password));
	md.update (challenge);
	
	return md.digest();
}

function readPrivateKey(path) {
	var privateKeyBytes = readFile (path);
	var keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
	var keyFactory = KeyFactory.getInstance ("RSA");
	
	return keyFactory.generatePrivate (keySpec);
}

function readPublicKey(path) {
	var publicKeyBytes = readFile (path);
	var keySpec = new X509EncodedKeySpec(publicKeyBytes);
	var keyFactory = KeyFactory.getInstance ("RSA");
	
	return keyFactory.generatePublic (keySpec);
}

function encodeArray (array) {
	var size = 0;

	for (i = 0; i < array.length; i++) {
		size += 4;
		size += array[i].length;
	}

	bytes = newByteArray (size);
	size = 0;

	for (i = 0; i < array.length; i++) {
		for (j = 0; j < 4; j++) {
			var x = (array[i].length >> (8*j)) & 0xFF;

			if ((x & 0x80) != 0)
				x -= 256;

			bytes[size] = x;
			size++;
		}

		java.lang.System.arraycopy (array[i], 0, bytes, size, array[i].length);
		size += array[i].length;
	}

	return bytes;
}

function decodeArray (bytes) {
	var array = new java.util.ArrayList();
	var pos = 0;

	while (pos < bytes.length) {
		var size = 0;
		
		for (j = 0; j < 4; j++) {
			size |= ((bytes[pos] & 0xFF) << (8*j));
			pos++;
		}

		var innerArray = newByteArray (size);
		java.lang.System.arraycopy (bytes, pos, innerArray, 0, size);

		pos += size;

		array.add (innerArray);
	}

	return array.toArray();
}

function updateSignature (signature, array) {
	var bytes = encodeArray (array);
	signature.update (bytes);
}

function signArray (privateKey, array) {
	var signer = Signature.getInstance (SIGNATURE_ALGO);
	signer.initSign (privateKey);

	updateSignature (signer, array);

	return signer.sign();	
}

function checkArraySignature (publicKey, signature, array) {
	var signer = Signature.getInstance (SIGNATURE_ALGO);
	signer.initVerify (publicKey);

	updateSignature (signer, array);

	return signer.verify (signature);
}

function createCertificate (privateKey, array) {
	var signature = signArray (privateKey, array);
	var dataBytes = encodeArray (array);
	var certificate = new Array (dataBytes, signature);

	return encodeArray (certificate);
}

function decodeCertificate (publicKey, certificateBytes) {
	var certificate = decodeArray (certificateBytes);
	var dataArray = decodeArray (certificate[0]);

	if (checkArraySignature (publicKey, certificate[1], dataArray)) {
		return dataArray;
	}
	else {
		return null;   // Neplatny podpis
	}	
}

function getSignatureResponse (privateKey, challenge, info) {
	return signArray (privateKey, new Array (challenge, info));
}

function checkSignatureResponse (publicKey, signature, challenge, info) {
	return checkArraySignature (publicKey, signature, new Array (challenge, info));
}

function newByteArray (length) {
	return Packages.java.lang.reflect.Array.newInstance (java.lang.Byte.TYPE, length);
}

function byteToArray (value) {
	var array = newByteArray(1);
	array[0] = value;

	return array;
}

function stringToBytes (str) {
  var bytes = newByteArray (str.length);
  
  for (i = 0; i < str.length; i++) {
  	bytes[i] = str.charCodeAt (i);
  }
  
  return bytes;
}

function bytesToString (bytes) {
	var str = '';
  
	for (i = 0; i < bytes.length; i++) {
		str += String.fromCharCode (bytes[i]);
	}
  
	return str;
}

function readFile(name) {
	var file = new FileInputStream(name);
	var memoryStream = new ByteArrayOutputStream();
	var buf = newByteArray (1024);
	var length;

	while ((length = file.read (buf)) >= 0) {
		memoryStream.write (buf, 0, length);
	}

	file.close();

	return memoryStream.toByteArray();
}

