'+
-b.replace(/\n/g,"
")+"
"))};this.print_debug_hexstr_dump=function(b,a){openpgp.config.debug&&(b+=this.hexstrdump(a),b=openpgp_encoding_html_encode(b),showMessages(''+b.replace(/\n/g,"
")+"
"))};this.print_error=function(b){b=openpgp_encoding_html_encode(b);showMessages('ERROR:\t'+
-b.replace(/\n/g,"
")+"
")};this.print_info=function(b){b=openpgp_encoding_html_encode(b);showMessages('INFO:\t'+b.replace(/\n/g,"
")+"
")};this.print_warning=function(b){b=openpgp_encoding_html_encode(b);showMessages('WARNING:\t'+
-b.replace(/\n/g,"
")+"
")};this.getLeftNBits=function(b,a){var c=a%8;return 0==c?b.substring(0,a/8):this.shiftRight(b.substring(0,(a-c)/8+1),8-c)};this.shiftRight=function(b,a){var c=util.str2bin(b);if(0!=a%8)for(var d=c.length-1;0<=d;d--)c[d]>>=a%8,0this.count&&(c=c.substr(0,this.count));return a&&(24==a||32==a)?openpgp_crypto_hashData(this.hashAlgorithm,c)+openpgp_crypto_hashData(this.hashAlgorithm,String.fromCharCode(0)+c):
+openpgp_crypto_hashData(this.hashAlgorithm,c)}return null}}
+var Util=function(){this.emailRegEx=/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;this.hexdump=function(a){for(var b=[],e=a.length,f=0,g,h=0;fg.length;)g="0"+g;b.push(" "+g);h++;0==h%32&&b.push("\n ")}return b.join("")};this.hexstrdump=function(a){if(null==a)return"";for(var b=[],e=a.length,f=0,g;fg.length;)g=
+"0"+g;b.push(""+g)}return b.join("")};this.hex2bin=function(a){for(var b="",e=0;eg.length;)g="0"+g;b.push(""+g)}return b.join("")};this.encode_utf8=function(a){return unescape(encodeURIComponent(a))};this.decode_utf8=function(a){return decodeURIComponent(escape(a))};var b=function(a,b){for(var e=0;e'+a.replace(/\n/g,"
")+"
"))};this.print_debug_hexstr_dump=function(a,b){openpgp.config.debug&&(a+=this.hexstrdump(b),a=openpgp_encoding_html_encode(a),showMessages(''+a.replace(/\n/g,"
")+"
"))};this.print_error=
+function(a){a=openpgp_encoding_html_encode(a);showMessages('ERROR:\t'+a.replace(/\n/g,"
")+"
")};this.print_info=function(a){a=openpgp_encoding_html_encode(a);showMessages('INFO:\t'+
+a.replace(/\n/g,"
")+"
")};this.print_warning=function(a){a=openpgp_encoding_html_encode(a);showMessages('WARNING:\t'+a.replace(/\n/g,"
")+"
")};this.getLeftNBits=function(a,b){var e=b%8;return 0==e?a.substring(0,b/8):this.shiftRight(a.substring(0,(b-e)/8+1),8-e)};this.shiftRight=function(a,b){var e=
+util.str2bin(a);if(0!=b%8)for(var f=e.length-1;0<=f;f--)e[f]>>=b%8,0"
+ * @param {String} passphrase The passphrase used to encrypt the resulting private key
* @return {Object} {privateKey: [openpgp_msg_privatekey],
* privateKeyArmored: [string], publicKeyArmored: [string]}
*/
diff --git a/src/packet/openpgp.packet.literaldata.js b/src/packet/openpgp.packet.literaldata.js
index 1deaa88e..4dfecd19 100644
--- a/src/packet/openpgp.packet.literaldata.js
+++ b/src/packet/openpgp.packet.literaldata.js
@@ -25,6 +25,47 @@
function openpgp_packet_literaldata() {
this.tagType = 11;
+
+ /**
+ * Set the packet data to a javascript native string or a squence of
+ * bytes. Conversion to a proper utf8 encoding takes place when the
+ * packet is written.
+ * @param {String} str Any native javascript string
+ * @param {openpgp_packet_literaldata.formats} format
+ */
+ this.set_data = function(str, format) {
+ this.format = format;
+ this.data = str;
+ }
+
+ /**
+ * Set the packet data to value represented by the provided string
+ * of bytes together with the appropriate conversion format.
+ * @param {String} bytes The string of bytes
+ * @param {openpgp_packet_literaldata.formats} format
+ */
+ this.set_data_bytes = function(bytes, format) {
+ this.format = format;
+
+ if(format == openpgp_packet_literaldata.formats.utf8)
+ bytes = util.decode_utf8(bytes);
+
+ this.data = bytes;
+ }
+
+ /**
+ * Get the byte sequence representing the literal packet data
+ * @returns {String} A sequence of bytes
+ */
+ this.get_data_bytes = function() {
+ if(this.format == openpgp_packet_literaldata.formats.utf8)
+ return util.encode_utf8(this.data);
+ else
+ return this.data;
+ }
+
+
+
/**
* Parsing function for a literal data packet (tag 11).
*
@@ -36,17 +77,22 @@ function openpgp_packet_literaldata() {
* input at position
* @return {openpgp_packet_encrypteddata} object representation
*/
- function read_packet(input, position, len) {
+ this.read_packet = function(input, position, len) {
this.packetLength = len;
// - A one-octet field that describes how the data is formatted.
- this.format = input[position];
- this.filename = input.substr(position + 2, input
- .charCodeAt(position + 1));
+ var format = input[position];
+
+ this.filename = util.decode_utf8(input.substr(position + 2, input
+ .charCodeAt(position + 1)));
+
this.date = new Date(parseInt(input.substr(position + 2
+ input.charCodeAt(position + 1), 4)) * 1000);
- this.data = input.substring(position + 6
+
+ var bytes = input.substring(position + 6
+ input.charCodeAt(position + 1));
+
+ this.set_data_bytes(bytes, format);
return this;
}
@@ -56,11 +102,13 @@ function openpgp_packet_literaldata() {
* @param {String} data The data to be inserted as body
* @return {String} string-representation of the packet
*/
- function write_packet(data) {
- data = data.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n");
- this.filename = "msg.txt";
+ this.write_packet = function(data) {
+ this.set_data(data, openpgp_packet_literaldata.formats.utf8);
+ this.filename = util.encode_utf8("msg.txt");
this.date = new Date();
- this.format = 't';
+
+ data = this.get_data_bytes();
+
var result = openpgp_packet.write_packet_header(11, data.length + 6
+ this.filename.length);
result += this.format;
@@ -75,7 +123,6 @@ function openpgp_packet_literaldata() {
result += String
.fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF);
result += data;
- this.data = data;
return result;
}
@@ -84,15 +131,25 @@ function openpgp_packet_literaldata() {
*
* @return {String} String which gives some information about the keymaterial
*/
- function toString() {
+ this.toString = function() {
return '5.9. Literal Data Packet (Tag 11)\n' + ' length: '
+ this.packetLength + '\n' + ' format: ' + this.format
+ '\n' + ' filename:' + this.filename + '\n'
+ ' date: ' + this.date + '\n' + ' data: |'
+ this.data + '|\n' + ' rdata: |' + this.real_data + '|\n';
}
-
- this.read_packet = read_packet;
- this.toString = toString;
- this.write_packet = write_packet;
}
+
+/**
+ * Data types in the literal packet
+ * @readonly
+ * @enum {String}
+ */
+openpgp_packet_literaldata.formats = {
+ /** Binary data */
+ binary: 'b',
+ /** Text data */
+ text: 't',
+ /** Utf8 data */
+ utf8: 'u'
+};
diff --git a/src/packet/openpgp.packet.userid.js b/src/packet/openpgp.packet.userid.js
index e7a0b7aa..dadab892 100644
--- a/src/packet/openpgp.packet.userid.js
+++ b/src/packet/openpgp.packet.userid.js
@@ -26,38 +26,71 @@
*/
function openpgp_packet_userid() {
+ this.text = ''
this.tagType = 13;
this.certificationSignatures = new Array();
this.certificationRevocationSignatures = new Array();
this.revocationSignatures = new Array();
this.parentNode = null;
+
+ /**
+ * Set the packet text field to a native javascript string
+ * Conversion to a proper utf8 encoding takes place when the
+ * packet is written.
+ * @param {String} str Any native javascript string
+ */
+ this.set_text = function(str) {
+ this.text = str;
+ }
/**
- * parsing function for a user id packet (tag 13).
+ * Set the packet text to value represented by the provided string
+ * of bytes.
+ * @param {String} bytes A string of bytes
+ */
+ this.set_text_bytes = function(bytes) {
+ this.text = util.decode_utf8(bytes);
+ }
+
+ /**
+ * Get the byte sequence representing the text of this packet.
+ * @returns {String} A sequence of bytes
+ */
+ this.get_text_bytes = function() {
+ return util.encode_utf8(this.text);
+ }
+
+
+ /**
+ * Parsing function for a user id packet (tag 13).
* @param {String} input payload of a tag 13 packet
* @param {Integer} position position to start reading from the input string
* @param {Integer} len length of the packet or the remaining length of input at position
* @return {openpgp_packet_encrypteddata} object representation
*/
- function read_packet(input, position, len) {
- this.text = '';
+ this.read_packet = function(input, position, len) {
this.packetLength = len;
+ var bytes = '';
for ( var i = 0; i < len; i++) {
- this.text += input[position + i];
+ bytes += input[position + i];
}
+
+ this.set_text_bytes(bytes);
return this;
}
/**
- * creates a string representation of the user id packet
+ * Creates a string representation of the user id packet
* @param {String} user_id the user id as string ("John Doe
this.certificationSignatures[i].creationTime) {
+
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
publicKeyPacket.data+String.fromCharCode(0xB4)+
- String.fromCharCode((this.text.length >> 24) & 0xFF)+
- String.fromCharCode((this.text.length >> 16) & 0xFF)+
- String.fromCharCode((this.text.length >> 8) & 0xFF)+
- String.fromCharCode((this.text.length) & 0xFF)+
- this.text;
+ String.fromCharCode((bytes.length >> 24) & 0xFF)+
+ String.fromCharCode((bytes.length >> 16) & 0xFF)+
+ String.fromCharCode((bytes.length >> 8) & 0xFF)+
+ String.fromCharCode((bytes.length) & 0xFF)+
+ bytes;
if (revocation.verify(signaturedata, signingKey)) {
if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
result[i] = 6;
@@ -250,13 +285,14 @@ function openpgp_packet_userid() {
continue;
}
}
+
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
publicKeyPacket.data+String.fromCharCode(0xB4)+
- String.fromCharCode((this.text.length >> 24) & 0xFF)+
- String.fromCharCode((this.text.length >> 16) & 0xFF)+
- String.fromCharCode((this.text.length >> 8) & 0xFF)+
- String.fromCharCode((this.text.length) & 0xFF)+
- this.text;
+ String.fromCharCode((bytes.length >> 24) & 0xFF)+
+ String.fromCharCode((bytes.length >> 16) & 0xFF)+
+ String.fromCharCode((bytes.length >> 8) & 0xFF)+
+ String.fromCharCode((bytes.length) & 0xFF)+
+ bytes;
if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
result[i] = 4;
} else
@@ -281,7 +317,7 @@ function openpgp_packet_userid() {
if (revocation != null && revocation.creationTime >
this.certificationSignatures[i].creationTime) {
var signaturedata = String.fromCharCode(0x99)+ this.publicKeyPacket.header.substring(1)+
- this.publicKeyPacket.data+this.text;
+ this.publicKeyPacket.data+bytes;
if (revocation.verify(signaturedata, signingKey)) {
if (revocation.keyId == publicKeyPacket.getKeyId())
result[i] = 6;
@@ -291,7 +327,7 @@ function openpgp_packet_userid() {
}
}
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
- publicKeyPacket.data+this.text;
+ publicKeyPacket.data + bytes;
if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
result[i] = 4;
} else
@@ -307,7 +343,7 @@ function openpgp_packet_userid() {
* verifies the signatures of the user id
* @return 0 if the userid is valid; 1 = userid expired; 2 = userid revoked
*/
- function verify(publicKeyPacket) {
+ this.verify = function(publicKeyPacket) {
var result = this.verifyCertificationSignatures(publicKeyPacket);
if (result.indexOf(6) != -1)
return 2;
@@ -317,20 +353,12 @@ function openpgp_packet_userid() {
}
// TODO: implementation missing
- function addCertification(publicKeyPacket, privateKeyPacket) {
+ this.addCertification = function(publicKeyPacket, privateKeyPacket) {
}
// TODO: implementation missing
- function revokeCertification(publicKeyPacket, privateKeyPacket) {
+ this.revokeCertification = function(publicKeyPacket, privateKeyPacket) {
}
-
- this.hasCertificationRevocationSignature = hasCertificationRevocationSignature;
- this.verifyCertificationSignatures = verifyCertificationSignatures;
- this.verify = verify;
- this.read_packet = read_packet;
- this.write_packet = write_packet;
- this.toString = toString;
- this.read_nodes = read_nodes;
}
diff --git a/src/type/openpgp.type.s2k.js b/src/type/openpgp.type.s2k.js
index 3147a8bb..b0d35afa 100644
--- a/src/type/openpgp.type.s2k.js
+++ b/src/type/openpgp.type.s2k.js
@@ -114,6 +114,7 @@ function openpgp_type_s2k() {
* hashAlgorithm hash length
*/
function produce_key(passphrase, numBytes) {
+ passphrase = util.encode_utf8(passphrase);
if (this.type == 0) {
return openpgp_crypto_hashData(this.hashAlgorithm,passphrase);
} else if (this.type == 1) {
diff --git a/src/util/util.js b/src/util/util.js
index 9d6e3f6d..be9cf037 100644
--- a/src/util/util.js
+++ b/src/util/util.js
@@ -85,45 +85,68 @@ var Util = function() {
}
return r.join('');
};
+
+
+ /**
+ * Convert a native javascript string to a string of utf8 bytes
+ * @param {String} str The string to convert
+ * @return {String} A valid squence of utf8 bytes
+ */
+ this.encode_utf8 = function(str) {
+ return unescape(encodeURIComponent(str));
+ };
+
+ /**
+ * Convert a string of utf8 bytes to a native javascript string
+ * @param {String} utf8 A valid squence of utf8 bytes
+ * @return {String} A native javascript string
+ */
+ this.decode_utf8 = function(utf8) {
+ return decodeURIComponent(escape(utf8));
+ };
+
+ var str2bin = function(str, result) {
+ for (var i = 0; i < str.length; i++) {
+ result[i] = str.charCodeAt(i);
+ }
+
+ return result;
+ };
+ var bin2str = function(bin) {
+ var result = [];
+
+ for (var i = 0; i < bin.length; i++) {
+ result.push(String.fromCharCode(bin[i]));
+ }
+
+ return result.join('');
+ };
+
/**
* Convert a string to an array of integers(0.255)
* @param {String} str String to convert
* @return {Integer[]} An array of (binary) integers
*/
- this.str2bin = function(str) {
- var result = new Array();
- for (var i = 0; i < str.length; i++) {
- result[i] = str.charCodeAt(i);
- }
-
- return result;
+ this.str2bin = function(str) {
+ return str2bin(str, new Array(str.length));
};
-
+
+
/**
* Convert an array of integers(0.255) to a string
* @param {Integer[]} bin An array of (binary) integers to convert
* @return {String} The string representation of the array
*/
- this.bin2str = function(bin) {
- var result = [];
- for (var i = 0; i < bin.length; i++) {
- result.push(String.fromCharCode(bin[i]));
- }
- return result.join('');
- };
+ this.bin2str = bin2str;
/**
* Convert a string to a Uint8Array
* @param {String} str String to convert
* @return {Uint8Array} The array of (binary) integers
*/
- this.str2Uint8Array = function(str){
- var uintArray = new Uint8Array(new ArrayBuffer(str.length));
- for(var n = 0; n < str.length; n++){
- uintArray[n] = str.charCodeAt(n);
- }
- return uintArray;
+ this.str2Uint8Array = function(str) {
+ return str2bin(str, new Uint8Array(new ArrayBuffer(str.length)));
};
/**
@@ -132,13 +155,7 @@ var Util = function() {
* @param {Uint8Array} bin An array of (binary) integers to convert
* @return {String} String representation of the array
*/
- this.Uint8Array2str = function(bin) {
- var result = [];
- for(n = 0; n< bin.length; n++){
- result[n] = String.fromCharCode(bin[n]);
- }
- return result.join('');
- };
+ this.Uint8Array2str = bin2str;
/**
* Calculates a 16bit sum of a string by adding each character
diff --git a/test/general/openpgp.basic.js b/test/general/openpgp.basic.js
new file mode 100644
index 00000000..3d2e27ef
--- /dev/null
+++ b/test/general/openpgp.basic.js
@@ -0,0 +1,69 @@
+
+unittests.register("Encryption/decryption", function() {
+
+openpgp.init();
+
+
+
+function test(passphrase, userid, message) {
+ var key = openpgp.generate_key_pair(1, 512, userid, passphrase),
+ priv_key = key.privateKey,
+ pub_key = openpgp.read_publicKey(key.publicKeyArmored);
+
+ var info = '\npassphrase: ' + passphrase + '\n'
+ + 'userid: ' + userid + '\n'
+ + 'message: ' + message;
+
+ if(!priv_key.decryptSecretMPIs(passphrase)) {
+ return new test_result('Generating a decryptable private key failed'
+ + info,
+ false);
+ }
+
+ var encrypted = openpgp.write_signed_and_encrypted_message(priv_key,
+ pub_key, message);
+
+ openpgp.keyring.importPublicKey(key.publicKeyArmored)
+
+
+ var msg = openpgp.read_message(encrypted);
+ var keymat = null;
+ var sesskey = null;
+
+ // Find the private (sub)key for the session key of the message
+ for (var i = 0; i< msg[0].sessionKeys.length; i++) {
+ if (priv_key.privateKeyPacket.publicKey.getKeyId() == msg[0].sessionKeys[i].keyId.bytes) {
+ keymat = { key: priv_key, keymaterial: priv_key.privateKeyPacket};
+ sesskey = msg[0].sessionKeys[i];
+ break;
+ }
+ for (var j = 0; j < priv_key.subKeys.length; j++) {
+ if (priv_key.subKeys[j].publicKey.getKeyId() == msg[0].sessionKeys[i].keyId.bytes) {
+ keymat = { key: priv_key, keymaterial: priv_key.subKeys[j]};
+ sesskey = msg[0].sessionKeys[i];
+ break;
+ }
+ }
+ }
+
+ var decrypted = ''
+ if (keymat != null) {
+ if (!keymat.keymaterial.decryptSecretMPIs(passphrase)) {
+ return new test_result("Password for secrect key was incorrect!",
+ + info, false)
+ }
+
+ decrypted = msg[0].decrypt(keymat, sesskey);
+ } else {
+ return new test_result("No private key found!" + info, false);
+ }
+
+ return new test_result(message + ' == ' + decrypted + info, message == decrypted);
+}
+
+var result = []
+result.push(test('password', 'Test McTestington ', 'hello world'));
+result.push(test('●●●●', '♔♔♔♔ ', 'łäóć'));
+
+return result
+});
diff --git a/test/index.html b/test/index.html
index 20a979e2..1c4e0f14 100644
--- a/test/index.html
+++ b/test/index.html
@@ -76,10 +76,9 @@
+
OpenPGP.js testpage
-
-