Cleaning mpi.js; TODO: store MPI.data as Uint8Array instead of BN
Also improved asynchronousity in packet tests
This commit is contained in:
parent
d40e8fe428
commit
3b912d2fae
|
@ -95,8 +95,7 @@ export default {
|
||||||
* @return {String} message, an octet string
|
* @return {String} message, an octet string
|
||||||
*/
|
*/
|
||||||
decode: function(EM) {
|
decode: function(EM) {
|
||||||
// FIXME
|
// leading zeros truncated by bn.js
|
||||||
// leading zeros truncated by jsbn
|
|
||||||
if (EM.charCodeAt(0) !== 0) {
|
if (EM.charCodeAt(0) !== 0) {
|
||||||
EM = String.fromCharCode(0) + EM;
|
EM = String.fromCharCode(0) + EM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,8 @@ export default {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new random private key B bits long with public exponent E
|
* Generate a new random private key B bits long with public exponent E
|
||||||
|
* @param {Integer} B RSA bit length
|
||||||
|
* @param {String} E RSA public exponent in hex
|
||||||
*/
|
*/
|
||||||
generate: async function(B, E) {
|
generate: async function(B, E) {
|
||||||
let key;
|
let key;
|
||||||
|
|
|
@ -42,7 +42,7 @@ import util from '../util';
|
||||||
*/
|
*/
|
||||||
export default function MPI(data) {
|
export default function MPI(data) {
|
||||||
/** An implementation dependent integer */
|
/** An implementation dependent integer */
|
||||||
if (data instanceof BN) {
|
if (BN.isBN(data)) {
|
||||||
this.fromBN(data);
|
this.fromBN(data);
|
||||||
} else if (util.isUint8Array(data)) {
|
} else if (util.isUint8Array(data)) {
|
||||||
this.fromUint8Array(data);
|
this.fromUint8Array(data);
|
||||||
|
@ -54,35 +54,27 @@ export default function MPI(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parsing function for a mpi ({@link https://tools.ietf.org/html/rfc4880#section3.2|RFC 4880 3.2}).
|
* Parsing function for a MPI ({@link https://tools.ietf.org/html/rfc4880#section-3.2|RFC 4880 3.2}).
|
||||||
* @param {Uint8Array} input Payload of mpi data
|
* @param {Uint8Array} input Payload of MPI data
|
||||||
* @param {String} endian Endianness of the payload; 'be' for big-endian or 'le' for little-endian
|
* @param {String} endian Endianness of the data; 'be' for big-endian or 'le' for little-endian
|
||||||
* @return {Integer} Length of data read
|
* @return {Integer} Length of data read
|
||||||
*/
|
*/
|
||||||
MPI.prototype.read = function (bytes, endian='be') {
|
MPI.prototype.read = function (bytes, endian='be') {
|
||||||
if (util.isString(bytes)) {
|
if (util.isString(bytes)) {
|
||||||
bytes = util.str2Uint8Array(bytes);
|
bytes = util.str2Uint8Array(bytes);
|
||||||
|
} else {
|
||||||
|
bytes = util.copyUint8Array(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bits = (bytes[0] << 8) | bytes[1];
|
const bits = (bytes[0] << 8) | bytes[1];
|
||||||
|
|
||||||
// Additional rules:
|
|
||||||
//
|
|
||||||
// The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
|
|
||||||
//
|
|
||||||
// The length field of an MPI describes the length starting from its
|
|
||||||
// most significant non-zero bit. Thus, the MPI [00 02 01] is not
|
|
||||||
// formed correctly. It should be [00 01 01].
|
|
||||||
|
|
||||||
// TODO: Verification of this size method! This size calculation as
|
|
||||||
// specified above is not applicable in JavaScript
|
|
||||||
const bytelen = Math.ceil(bits / 8);
|
const bytelen = Math.ceil(bits / 8);
|
||||||
let payload = bytes.subarray(2, 2 + bytelen);
|
const payload = bytes.subarray(2, 2 + bytelen);
|
||||||
|
|
||||||
if (endian === 'le') {
|
if (endian === 'le') {
|
||||||
payload = Uint8Array.from(payload).reverse();
|
payload.reverse();
|
||||||
}
|
}
|
||||||
const raw = util.Uint8Array2str(payload);
|
|
||||||
this.fromBytes(raw);
|
this.fromUint8Array(payload);
|
||||||
|
|
||||||
return 2 + bytelen;
|
return 2 + bytelen;
|
||||||
};
|
};
|
||||||
|
@ -118,9 +110,6 @@ MPI.prototype.fromString = function (str) {
|
||||||
this.data = new BN(util.str2Uint8Array(str));
|
this.data = new BN(util.str2Uint8Array(str));
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO remove this
|
|
||||||
MPI.prototype.fromBytes = MPI.prototype.fromString;
|
|
||||||
|
|
||||||
MPI.prototype.toBN = function () {
|
MPI.prototype.toBN = function () {
|
||||||
return this.data.clone();
|
return this.data.clone();
|
||||||
};
|
};
|
||||||
|
|
|
@ -378,10 +378,10 @@ describe('API functional testing', function() {
|
||||||
|
|
||||||
it('Asymmetric using RSA with eme_pkcs1 padding', function () {
|
it('Asymmetric using RSA with eme_pkcs1 padding', function () {
|
||||||
const symmKey = util.Uint8Array2str(crypto.generateSessionKey('aes256'));
|
const symmKey = util.Uint8Array2str(crypto.generateSessionKey('aes256'));
|
||||||
const RSAUnencryptedData = new openpgp.MPI();
|
const RSAUnencryptedData = crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength())
|
||||||
RSAUnencryptedData.fromBytes(crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength()));
|
const RSAUnencryptedMPI = new openpgp.MPI(RSAUnencryptedData);
|
||||||
return crypto.publicKeyEncrypt(
|
return crypto.publicKeyEncrypt(
|
||||||
1, RSApubMPIs, RSAUnencryptedData
|
1, RSApubMPIs, RSAUnencryptedMPI
|
||||||
).then(RSAEncryptedData => {
|
).then(RSAEncryptedData => {
|
||||||
|
|
||||||
return crypto.publicKeyDecrypt(
|
return crypto.publicKeyDecrypt(
|
||||||
|
@ -398,11 +398,11 @@ describe('API functional testing', function() {
|
||||||
|
|
||||||
it('Asymmetric using Elgamal with eme_pkcs1 padding', function () {
|
it('Asymmetric using Elgamal with eme_pkcs1 padding', function () {
|
||||||
const symmKey = util.Uint8Array2str(crypto.generateSessionKey('aes256'));
|
const symmKey = util.Uint8Array2str(crypto.generateSessionKey('aes256'));
|
||||||
const ElgamalUnencryptedData = new openpgp.MPI();
|
const ElgamalUnencryptedData = crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength());
|
||||||
ElgamalUnencryptedData.fromBytes(crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength()));
|
const ElgamalUnencryptedMPI = new openpgp.MPI(ElgamalUnencryptedData);
|
||||||
|
|
||||||
return crypto.publicKeyEncrypt(
|
return crypto.publicKeyEncrypt(
|
||||||
16, ElgamalpubMPIs, ElgamalUnencryptedData
|
16, ElgamalpubMPIs, ElgamalUnencryptedMPI
|
||||||
).then(ElgamalEncryptedData => {
|
).then(ElgamalEncryptedData => {
|
||||||
|
|
||||||
return crypto.publicKeyDecrypt(
|
return crypto.publicKeyDecrypt(
|
||||||
|
|
|
@ -5,13 +5,6 @@ chai.use(require('chai-as-promised'));
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
const bin2bi = function (bytes) {
|
|
||||||
const mpi = new openpgp.MPI();
|
|
||||||
bytes = openpgp.util.bin2str(bytes);
|
|
||||||
mpi.fromBytes(bytes);
|
|
||||||
return mpi.toUint8Array(); // FIXME
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Elliptic Curve Cryptography', function () {
|
describe('Elliptic Curve Cryptography', function () {
|
||||||
const elliptic_curves = openpgp.crypto.publicKey.elliptic;
|
const elliptic_curves = openpgp.crypto.publicKey.elliptic;
|
||||||
const key_data = {
|
const key_data = {
|
||||||
|
@ -219,9 +212,9 @@ describe('Elliptic Curve Cryptography', function () {
|
||||||
return ecdsa.verify(
|
return ecdsa.verify(
|
||||||
oid,
|
oid,
|
||||||
hash,
|
hash,
|
||||||
{r: bin2bi(r), s: bin2bi(s)},
|
{r: new Uint8Array(r), s: new Uint8Array(s)},
|
||||||
message,
|
message,
|
||||||
bin2bi(pub)
|
new Uint8Array(pub)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const secp256k1_dummy_value = new Uint8Array([
|
const secp256k1_dummy_value = new Uint8Array([
|
||||||
|
@ -297,8 +290,8 @@ describe('Elliptic Curve Cryptography', function () {
|
||||||
it('Sign and verify message', function () {
|
it('Sign and verify message', function () {
|
||||||
const curve = elliptic_curves.get('p521');
|
const curve = elliptic_curves.get('p521');
|
||||||
return curve.genKeyPair().then(keyPair => {
|
return curve.genKeyPair().then(keyPair => {
|
||||||
const keyPublic = bin2bi(keyPair.getPublic());
|
const keyPublic = new Uint8Array(keyPair.getPublic());
|
||||||
const keyPrivate = bin2bi(keyPair.getPrivate());
|
const keyPrivate = new Uint8Array(keyPair.getPrivate());
|
||||||
const oid = curve.oid;
|
const oid = curve.oid;
|
||||||
const message = p384_message;
|
const message = p384_message;
|
||||||
return elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate).then(signature => {
|
return elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate).then(signature => {
|
||||||
|
@ -321,9 +314,9 @@ describe('Elliptic Curve Cryptography', function () {
|
||||||
curve.oid,
|
curve.oid,
|
||||||
cipher,
|
cipher,
|
||||||
hash,
|
hash,
|
||||||
bin2bi(ephemeral),
|
new Uint8Array(ephemeral),
|
||||||
data,
|
data,
|
||||||
bin2bi(priv),
|
new Uint8Array(priv),
|
||||||
fingerprint
|
fingerprint
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -204,7 +204,7 @@ describe("Packet", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Secret key packet (reading, unencrypted)', function(done) {
|
it('Secret key packet (reading, unencrypted)', function() {
|
||||||
const armored_key =
|
const armored_key =
|
||||||
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
|
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
|
||||||
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
|
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
|
||||||
|
@ -239,17 +239,14 @@ describe("Packet", function() {
|
||||||
enc.sessionKeyAlgorithm = 'aes256';
|
enc.sessionKeyAlgorithm = 'aes256';
|
||||||
enc.publicKeyId.bytes = '12345678';
|
enc.publicKeyId.bytes = '12345678';
|
||||||
|
|
||||||
enc.encrypt(key).then(() => {
|
return enc.encrypt(key).then(() => {
|
||||||
|
return enc.decrypt(key).then(() => {
|
||||||
enc.decrypt(key).then(() => {
|
|
||||||
|
|
||||||
expect(stringify(enc.sessionKey)).to.equal(stringify(secret));
|
expect(stringify(enc.sessionKey)).to.equal(stringify(secret));
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Public key encrypted packet (reading, GPG)', function(done) {
|
it('Public key encrypted packet (reading, GPG)', function() {
|
||||||
const armored_key =
|
const armored_key =
|
||||||
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
|
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
|
||||||
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
|
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
|
||||||
|
@ -304,17 +301,16 @@ describe("Packet", function() {
|
||||||
const msg = new openpgp.packet.List();
|
const msg = new openpgp.packet.List();
|
||||||
msg.read(openpgp.armor.decode(armored_msg).data);
|
msg.read(openpgp.armor.decode(armored_msg).data);
|
||||||
|
|
||||||
msg[0].decrypt(key).then(() => {
|
return msg[0].decrypt(key).then(() => {
|
||||||
msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
|
return msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
|
||||||
|
|
||||||
const text = stringify(msg[1].packets[0].packets[0].data);
|
const text = stringify(msg[1].packets[0].packets[0].data);
|
||||||
|
|
||||||
expect(text).to.equal('Hello world!');
|
expect(text).to.equal('Hello world!');
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sym encrypted session key reading/writing', function(done) {
|
it('Sym. encrypted session key reading/writing', function(done) {
|
||||||
const passphrase = 'hello';
|
const passphrase = 'hello';
|
||||||
const algo = 'aes256';
|
const algo = 'aes256';
|
||||||
|
|
||||||
|
@ -346,7 +342,7 @@ describe("Packet", function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Secret key encryption/decryption test', function(done) {
|
it('Secret key encryption/decryption test', function() {
|
||||||
const armored_msg =
|
const armored_msg =
|
||||||
'-----BEGIN PGP MESSAGE-----\n' +
|
'-----BEGIN PGP MESSAGE-----\n' +
|
||||||
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
|
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
|
||||||
|
@ -367,13 +363,12 @@ describe("Packet", function() {
|
||||||
const msg = new openpgp.packet.List();
|
const msg = new openpgp.packet.List();
|
||||||
msg.read(openpgp.armor.decode(armored_msg).data);
|
msg.read(openpgp.armor.decode(armored_msg).data);
|
||||||
|
|
||||||
msg[0].decrypt(key).then(() => {
|
return msg[0].decrypt(key).then(() => {
|
||||||
msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
|
return msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
|
||||||
|
|
||||||
const text = stringify(msg[1].packets[0].packets[0].data);
|
const text = stringify(msg[1].packets[0].packets[0].data);
|
||||||
|
|
||||||
expect(text).to.equal('Hello world!');
|
expect(text).to.equal('Hello world!');
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user