refactor mpi, generalize mpi to params to account for non-mpi algorithm-specific data
This commit is contained in:
parent
840c0229f8
commit
cdc7004b96
|
@ -38,14 +38,26 @@ import type_kdf_params from '../type/kdf_params.js';
|
||||||
import type_mpi from '../type/mpi.js';
|
import type_mpi from '../type/mpi.js';
|
||||||
import type_oid from '../type/oid.js';
|
import type_oid from '../type/oid.js';
|
||||||
|
|
||||||
function BigInteger2mpi(bn) {
|
function createType(data, type) {
|
||||||
var mpi = new type_mpi();
|
switch(type) {
|
||||||
mpi.fromBigInteger(bn);
|
case 'mpi':
|
||||||
return mpi;
|
return new type_mpi(data);
|
||||||
|
case 'oid':
|
||||||
|
return new type_oid(data);
|
||||||
|
case 'kdf':
|
||||||
|
return new type_kdf_params(data);
|
||||||
|
case 'ecdh_symkey':
|
||||||
|
return new type_ecdh_symkey(data);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapResult(result) {
|
function mapResult(result, types) {
|
||||||
return result.map(BigInteger2mpi);
|
for (var i=0; i < result.length; i++) {
|
||||||
|
result[i] = createType(result[i], types[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -53,38 +65,39 @@ export default {
|
||||||
* Encrypts data using the specified public key multiprecision integers
|
* Encrypts data using the specified public key multiprecision integers
|
||||||
* and the specified algorithm.
|
* and the specified algorithm.
|
||||||
* @param {module:enums.publicKey} algo Algorithm to be used (See {@link http://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1})
|
* @param {module:enums.publicKey} algo Algorithm to be used (See {@link http://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1})
|
||||||
* @param {Array<module:type/mpi>} publicMPIs Algorithm dependent multiprecision integers
|
* @param {Array<module:type/mpi>} publicParams Algorithm dependent multiprecision integers
|
||||||
* @param {module:type/mpi} data Data to be encrypted as MPI
|
* @param {module:type/mpi} data Data to be encrypted as MPI
|
||||||
* @return {Array<module:type/mpi>} if RSA an module:type/mpi;
|
* @return {Array<module:type/mpi>} if RSA an module:type/mpi;
|
||||||
* if elgamal encryption an array of two module:type/mpi is returned; otherwise null
|
* if elgamal encryption an array of two module:type/mpi is returned; otherwise null
|
||||||
*/
|
*/
|
||||||
publicKeyEncrypt: function(algo, publicMPIs, data, fingerprint) {
|
publicKeyEncrypt: function(algo, publicParams, data, fingerprint) {
|
||||||
|
var types = this.getEncSessionKeyParamTypes(algo);
|
||||||
var result = (function() {
|
var result = (function() {
|
||||||
var m;
|
var m;
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case 'rsa_encrypt':
|
case 'rsa_encrypt':
|
||||||
case 'rsa_encrypt_sign':
|
case 'rsa_encrypt_sign':
|
||||||
var rsa = new publicKey.rsa();
|
var rsa = new publicKey.rsa();
|
||||||
var n = publicMPIs[0].toBigInteger();
|
var n = publicParams[0].toBigInteger();
|
||||||
var e = publicMPIs[1].toBigInteger();
|
var e = publicParams[1].toBigInteger();
|
||||||
m = data.toBigInteger();
|
m = data.toBigInteger();
|
||||||
return mapResult([rsa.encrypt(m, e, n)]);
|
return mapResult([rsa.encrypt(m, e, n)], types);
|
||||||
|
|
||||||
case 'elgamal':
|
case 'elgamal':
|
||||||
var elgamal = new publicKey.elgamal();
|
var elgamal = new publicKey.elgamal();
|
||||||
var p = publicMPIs[0].toBigInteger();
|
var p = publicParams[0].toBigInteger();
|
||||||
var g = publicMPIs[1].toBigInteger();
|
var g = publicParams[1].toBigInteger();
|
||||||
var y = publicMPIs[2].toBigInteger();
|
var y = publicParams[2].toBigInteger();
|
||||||
m = data.toBigInteger();
|
m = data.toBigInteger();
|
||||||
return mapResult(elgamal.encrypt(m, g, p, y));
|
return mapResult(elgamal.encrypt(m, g, p, y), types);
|
||||||
|
|
||||||
case 'ecdh':
|
case 'ecdh':
|
||||||
var ecdh = publicKey.elliptic.ecdh;
|
var ecdh = publicKey.elliptic.ecdh;
|
||||||
var curve = publicMPIs[0];
|
var curve = publicParams[0];
|
||||||
var kdf_params = publicMPIs[2];
|
var kdf_params = publicParams[2];
|
||||||
var R = publicMPIs[1].toBigInteger();
|
var R = publicParams[1].toBigInteger();
|
||||||
var res = ecdh.encrypt(curve.oid, kdf_params.cipher, kdf_params.hash, data, R, fingerprint);
|
var res = ecdh.encrypt(curve.oid, kdf_params.cipher, kdf_params.hash, data, R, fingerprint);
|
||||||
return [BigInteger2mpi(res.V), new type_ecdh_symkey(res.C)];
|
return mapResult([res.V, res.C], types);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
|
@ -98,7 +111,7 @@ export default {
|
||||||
* Decrypts data using the specified public key multiprecision integers of the private key,
|
* Decrypts data using the specified public key multiprecision integers of the private key,
|
||||||
* the specified secretMPIs of the private key and the specified algorithm.
|
* the specified secretMPIs of the private key and the specified algorithm.
|
||||||
* @param {module:enums.publicKey} algo Algorithm to be used (See {@link http://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1})
|
* @param {module:enums.publicKey} algo Algorithm to be used (See {@link http://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1})
|
||||||
* @param {Array<module:type/mpi>} publicMPIs Algorithm dependent multiprecision integers
|
* @param {Array<module:type/mpi>} publicParams Algorithm dependent multiprecision integers
|
||||||
* of the public key part of the private key
|
* of the public key part of the private key
|
||||||
* @param {Array<module:type/mpi>} secretMPIs Algorithm dependent multiprecision integers
|
* @param {Array<module:type/mpi>} secretMPIs Algorithm dependent multiprecision integers
|
||||||
* of the private key used
|
* of the private key used
|
||||||
|
@ -146,8 +159,7 @@ export default {
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var result = new type_mpi();
|
var result = new type_mpi(bn);
|
||||||
result.fromBigInteger(bn);
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -155,7 +167,7 @@ export default {
|
||||||
* @param {String} algo The public key algorithm
|
* @param {String} algo The public key algorithm
|
||||||
* @return {Integer} The number of integers.
|
* @return {Integer} The number of integers.
|
||||||
*/
|
*/
|
||||||
getPrivateMpiCount: function(algo) {
|
getPrivKeyParamTypes: function(algo) {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case 'rsa_encrypt':
|
case 'rsa_encrypt':
|
||||||
case 'rsa_encrypt_sign':
|
case 'rsa_encrypt_sign':
|
||||||
|
@ -165,27 +177,30 @@ export default {
|
||||||
// - MPI of RSA secret prime value p.
|
// - MPI of RSA secret prime value p.
|
||||||
// - MPI of RSA secret prime value q (p < q).
|
// - MPI of RSA secret prime value q (p < q).
|
||||||
// - MPI of u, the multiplicative inverse of p, mod q.
|
// - MPI of u, the multiplicative inverse of p, mod q.
|
||||||
return 4;
|
return ['mpi', 'mpi', 'mpi', 'mpi'];
|
||||||
case 'elgamal':
|
case 'elgamal':
|
||||||
// Algorithm-Specific Fields for Elgamal secret keys:
|
// Algorithm-Specific Fields for Elgamal secret keys:
|
||||||
// - MPI of Elgamal secret exponent x.
|
// - MPI of Elgamal secret exponent x.
|
||||||
return 1;
|
return ['mpi'];
|
||||||
case 'dsa':
|
case 'dsa':
|
||||||
// Algorithm-Specific Fields for DSA secret keys:
|
// Algorithm-Specific Fields for DSA secret keys:
|
||||||
// - MPI of DSA secret exponent x.
|
// - MPI of DSA secret exponent x.
|
||||||
return 1;
|
return ['mpi'];
|
||||||
case 'ecdh':
|
case 'ecdh':
|
||||||
case 'ecdsa':
|
case 'ecdsa':
|
||||||
// Algorithm-Specific Fields for ECDSA or ECDH secret keys:
|
// Algorithm-Specific Fields for ECDSA or ECDH secret keys:
|
||||||
// - MPI of an integer representing the secret key.
|
// - MPI of an integer representing the secret key.
|
||||||
return 1;
|
return ['mpi'];
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown algorithm');
|
throw new Error('Unknown algorithm');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getPublicMpiCount: function(algo) {
|
getPrivKeyParamCount: function(algo) {
|
||||||
// - A series of multiprecision integers comprising the key material:
|
return this.getPrivKeyParamTypes(algo).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
getPubKeyParamTypes: function(algo) {
|
||||||
// Algorithm-Specific Fields for RSA public keys:
|
// Algorithm-Specific Fields for RSA public keys:
|
||||||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||||||
// - an MPI of RSA public encryption exponent e.
|
// - an MPI of RSA public encryption exponent e.
|
||||||
|
@ -193,42 +208,71 @@ export default {
|
||||||
case 'rsa_encrypt':
|
case 'rsa_encrypt':
|
||||||
case 'rsa_encrypt_sign':
|
case 'rsa_encrypt_sign':
|
||||||
case 'rsa_sign':
|
case 'rsa_sign':
|
||||||
return 2;
|
return ['mpi', 'mpi'];
|
||||||
|
|
||||||
// Algorithm-Specific Fields for Elgamal public keys:
|
// Algorithm-Specific Fields for Elgamal public keys:
|
||||||
// - MPI of Elgamal prime p;
|
// - MPI of Elgamal prime p;
|
||||||
// - MPI of Elgamal group generator g;
|
// - MPI of Elgamal group generator g;
|
||||||
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
||||||
case 'elgamal':
|
case 'elgamal':
|
||||||
return 3;
|
return ['mpi', 'mpi', 'mpi'];
|
||||||
|
|
||||||
// Algorithm-Specific Fields for DSA public keys:
|
// Algorithm-Specific Fields for DSA public keys:
|
||||||
// - MPI of DSA prime p;
|
// - MPI of DSA prime p;
|
||||||
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
||||||
// - MPI of DSA group generator g;
|
// - MPI of DSA group generator g;
|
||||||
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
||||||
case 'dsa':
|
case 'dsa':
|
||||||
return 4;
|
return ['mpi', 'mpi', 'mpi', 'mpi'];
|
||||||
|
|
||||||
// Algorithm-Specific Fields for ECDSA public keys:
|
// Algorithm-Specific Fields for ECDSA public keys:
|
||||||
// - OID of curve;
|
// - OID of curve;
|
||||||
// - MPI of EC point representing public key.
|
// - MPI of EC point representing public key.
|
||||||
case 'ecdsa':
|
case 'ecdsa':
|
||||||
return 2;
|
return ['oid', 'mpi'];
|
||||||
|
|
||||||
// Algorithm-Specific Fields for ECDH public keys:
|
// Algorithm-Specific Fields for ECDH public keys:
|
||||||
// - OID of curve;
|
// - OID of curve;
|
||||||
// - MPI of EC point representing public key.
|
// - MPI of EC point representing public key.
|
||||||
// - variable-length field containing KDF parameters.
|
// - variable-length field containing KDF parameters.
|
||||||
case 'ecdh':
|
case 'ecdh':
|
||||||
return 3;
|
return ['oid', 'mpi', 'kdf'];
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown algorithm.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getPubKeyParamCount: function(algo) {
|
||||||
|
return this.getPubKeyParamTypes(algo).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
getEncSessionKeyParamTypes: function(algo) {
|
||||||
|
switch (algo) {
|
||||||
|
// Algorithm-Specific Fields for RSA encrypted session keys:
|
||||||
|
// - MPI of RSA encrypted value m**e mod n.
|
||||||
|
case 'rsa_encrypt':
|
||||||
|
case 'rsa_encrypt_sign':
|
||||||
|
return ['mpi'];
|
||||||
|
|
||||||
|
// Algorithm-Specific Fields for Elgamal encrypted session keys:
|
||||||
|
// - MPI of Elgamal value g**k mod p
|
||||||
|
// - MPI of Elgamal value m * y**k mod p
|
||||||
|
case 'elgamal':
|
||||||
|
return ['mpi', 'mpi'];
|
||||||
|
|
||||||
|
// Algorithm-Specific Fields for ECDH encrypted session keys:
|
||||||
|
// - MPI containing the ephemeral key used to establish the shared secret
|
||||||
|
// - EcdhSymmetricKey
|
||||||
|
case 'ecdh':
|
||||||
|
return ['mpi', 'ecdh_symkey'];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown algorithm.');
|
throw new Error('Unknown algorithm.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
generateMpi: function(algo, bits, curve) {
|
getEncSessionKeyParamCount: function(algo) {
|
||||||
|
return this.getEncSessionKeyParamTypes(algo).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
generateParams: function(algo, bits, curve) {
|
||||||
|
var types = this.getPubKeyParamTypes(algo).concat(this.getPrivKeyParamTypes(algo));
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case 'rsa_encrypt':
|
case 'rsa_encrypt':
|
||||||
case 'rsa_encrypt_sign':
|
case 'rsa_encrypt_sign':
|
||||||
|
@ -236,33 +280,17 @@ export default {
|
||||||
//remember "publicKey" refers to the crypto/public_key dir
|
//remember "publicKey" refers to the crypto/public_key dir
|
||||||
var rsa = new publicKey.rsa();
|
var rsa = new publicKey.rsa();
|
||||||
return rsa.generate(bits, "10001").then(function(keyObject) {
|
return rsa.generate(bits, "10001").then(function(keyObject) {
|
||||||
var output = [];
|
return mapResult([keyObject.n, keyObject.ee, keyObject.d, keyObject.p, keyObject.q, keyObject.u], types);
|
||||||
output.push(keyObject.n);
|
|
||||||
output.push(keyObject.ee);
|
|
||||||
output.push(keyObject.d);
|
|
||||||
output.push(keyObject.p);
|
|
||||||
output.push(keyObject.q);
|
|
||||||
output.push(keyObject.u);
|
|
||||||
return mapResult(output);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
case 'ecdsa':
|
case 'ecdsa':
|
||||||
return publicKey.elliptic.generate(curve).then(function (keyObject) {
|
return publicKey.elliptic.generate(curve).then(function (keyObject) {
|
||||||
return [
|
return mapResult([keyObject.oid, keyObject.R, keyObject.r], types);
|
||||||
new type_oid(keyObject.oid),
|
|
||||||
BigInteger2mpi(keyObject.R),
|
|
||||||
BigInteger2mpi(keyObject.r)
|
|
||||||
];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
case 'ecdh':
|
case 'ecdh':
|
||||||
return publicKey.elliptic.generate(curve).then(function (keyObject) {
|
return publicKey.elliptic.generate(curve).then(function (keyObject) {
|
||||||
return [
|
return mapResult([keyObject.oid, keyObject.R, [keyObject.hash, keyObject.cipher], keyObject.r], types);
|
||||||
new type_oid(keyObject.oid),
|
|
||||||
BigInteger2mpi(keyObject.R),
|
|
||||||
new type_kdf_params(keyObject.hash, keyObject.cipher),
|
|
||||||
BigInteger2mpi(keyObject.r)
|
|
||||||
];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -113,8 +113,7 @@ export default {
|
||||||
randomBits.charCodeAt(0)) +
|
randomBits.charCodeAt(0)) +
|
||||||
randomBits.substring(1);
|
randomBits.substring(1);
|
||||||
}
|
}
|
||||||
var mpi = new type_mpi();
|
var mpi = new type_mpi(randomBits);
|
||||||
mpi.fromBytes(randomBits);
|
|
||||||
return mpi.toBigInteger();
|
return mpi.toBigInteger();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ Key.prototype.encrypt = function(passphrase) {
|
||||||
var keys = this.getAllKeyPackets();
|
var keys = this.getAllKeyPackets();
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
keys[i].encrypt(passphrase);
|
keys[i].encrypt(passphrase);
|
||||||
keys[i].clearPrivateMPIs();
|
keys[i].clearPrivateParams();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1279,8 +1279,8 @@ function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
|
||||||
packetlist.push(subkeySignaturePacket);
|
packetlist.push(subkeySignaturePacket);
|
||||||
|
|
||||||
if (!options.unlocked) {
|
if (!options.unlocked) {
|
||||||
secretKeyPacket.clearPrivateMPIs();
|
secretKeyPacket.clearPrivateParams();
|
||||||
secretSubkeyPacket.clearPrivateMPIs();
|
secretSubkeyPacket.clearPrivateParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Key(packetlist);
|
return new Key(packetlist);
|
||||||
|
|
|
@ -51,12 +51,8 @@ export default function PublicKey() {
|
||||||
/** Key creation date.
|
/** Key creation date.
|
||||||
* @type {Date} */
|
* @type {Date} */
|
||||||
this.created = new Date();
|
this.created = new Date();
|
||||||
/** A list of multiprecision integers
|
/* Algorithm specific params */
|
||||||
* @type {module:type/mpi} */
|
this.params = [];
|
||||||
this.mpi = [];
|
|
||||||
/** Public key algorithm
|
|
||||||
* @type {module:enums.publicKey} */
|
|
||||||
this.algorithm = 'rsa_sign';
|
|
||||||
// time in days (V3 only)
|
// time in days (V3 only)
|
||||||
this.expirationTimeV3 = 0;
|
this.expirationTimeV3 = 0;
|
||||||
/**
|
/**
|
||||||
|
@ -97,22 +93,22 @@ PublicKey.prototype.read = function (bytes) {
|
||||||
// - A one-octet number denoting the public-key algorithm of this key.
|
// - A one-octet number denoting the public-key algorithm of this key.
|
||||||
this.algorithm = enums.read(enums.publicKey, bytes[pos++]);
|
this.algorithm = enums.read(enums.publicKey, bytes[pos++]);
|
||||||
|
|
||||||
var mpicount = crypto.getPublicMpiCount(this.algorithm);
|
var param_count = crypto.getPubKeyParamCount(this.algorithm);
|
||||||
this.mpi = [];
|
this.params = [];
|
||||||
|
|
||||||
var bmpi = bytes.subarray(pos, bytes.length);
|
var bmpi = bytes.subarray(pos, bytes.length);
|
||||||
var p = 0;
|
var p = 0;
|
||||||
|
|
||||||
for (var i = 0; i < mpicount && p < bmpi.length; i++) {
|
for (var i = 0; i < param_count && p < bmpi.length; i++) {
|
||||||
if ((this.algorithm === 'ecdsa' || this.algorithm === 'ecdh') && i === 0) {
|
if ((this.algorithm === 'ecdsa' || this.algorithm === 'ecdh') && i === 0) {
|
||||||
this.mpi[i] = new type_oid();
|
this.params[i] = new type_oid();
|
||||||
} else if (this.algorithm === 'ecdh' && i === 2) {
|
} else if (this.algorithm === 'ecdh' && i === 2) {
|
||||||
this.mpi[i] = new type_kdf_params();
|
this.params[i] = new type_kdf_params();
|
||||||
} else {
|
} else {
|
||||||
this.mpi[i] = new type_mpi();
|
this.params[i] = new type_mpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
p += this.mpi[i].read(bmpi.subarray(p, bmpi.length));
|
p += this.params[i].read(bmpi.subarray(p, bmpi.length));
|
||||||
|
|
||||||
if (p > bmpi.length) {
|
if (p > bmpi.length) {
|
||||||
throw new Error('Error reading MPI @:' + p);
|
throw new Error('Error reading MPI @:' + p);
|
||||||
|
@ -147,10 +143,10 @@ PublicKey.prototype.write = function () {
|
||||||
}
|
}
|
||||||
arr.push(new Uint8Array([enums.write(enums.publicKey, this.algorithm)]));
|
arr.push(new Uint8Array([enums.write(enums.publicKey, this.algorithm)]));
|
||||||
|
|
||||||
var mpicount = crypto.getPublicMpiCount(this.algorithm);
|
var param_count = crypto.getPubKeyParamCount(this.algorithm);
|
||||||
|
|
||||||
for (var i = 0; i < mpicount; i++) {
|
for (var i = 0; i < param_count; i++) {
|
||||||
arr.push(this.mpi[i].write());
|
arr.push(this.params[i].write());
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.concatUint8Array(arr);
|
return util.concatUint8Array(arr);
|
||||||
|
@ -183,7 +179,7 @@ PublicKey.prototype.getKeyId = function () {
|
||||||
if (this.version === 4) {
|
if (this.version === 4) {
|
||||||
this.keyid.read(util.str2Uint8Array(util.hex2bin(this.getFingerprint()).substr(12, 8)));
|
this.keyid.read(util.str2Uint8Array(util.hex2bin(this.getFingerprint()).substr(12, 8)));
|
||||||
} else if (this.version === 3) {
|
} else if (this.version === 3) {
|
||||||
var arr = this.mpi[0].write();
|
var arr = this.params[0].write();
|
||||||
this.keyid.read(arr.subarray(arr.length - 8, arr.length));
|
this.keyid.read(arr.subarray(arr.length - 8, arr.length));
|
||||||
}
|
}
|
||||||
return this.keyid;
|
return this.keyid;
|
||||||
|
@ -202,9 +198,9 @@ PublicKey.prototype.getFingerprint = function () {
|
||||||
toHash = this.writeOld();
|
toHash = this.writeOld();
|
||||||
this.fingerprint = util.Uint8Array2str(crypto.hash.sha1(toHash));
|
this.fingerprint = util.Uint8Array2str(crypto.hash.sha1(toHash));
|
||||||
} else if (this.version === 3) {
|
} else if (this.version === 3) {
|
||||||
var mpicount = crypto.getPublicMpiCount(this.algorithm);
|
var param_count = crypto.getPubKeyParamCount(this.algorithm);
|
||||||
for (var i = 0; i < mpicount; i++) {
|
for (var i = 0; i < param_count; i++) {
|
||||||
toHash += this.mpi[i].toBytes();
|
toHash += this.params[i].toBytes();
|
||||||
}
|
}
|
||||||
this.fingerprint = util.Uint8Array2str(crypto.hash.md5(util.str2Uint8Array(toHash)));
|
this.fingerprint = util.Uint8Array2str(crypto.hash.md5(util.str2Uint8Array(toHash)));
|
||||||
}
|
}
|
||||||
|
@ -217,15 +213,15 @@ PublicKey.prototype.getFingerprint = function () {
|
||||||
* @return {int} Number of bits
|
* @return {int} Number of bits
|
||||||
*/
|
*/
|
||||||
PublicKey.prototype.getBitSize = function () {
|
PublicKey.prototype.getBitSize = function () {
|
||||||
return this.mpi[0].byteLength() * 8;
|
return this.params[0].byteLength() * 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix custom types after cloning
|
* Fix custom types after cloning
|
||||||
*/
|
*/
|
||||||
PublicKey.prototype.postCloneTypeFix = function() {
|
PublicKey.prototype.postCloneTypeFix = function() {
|
||||||
for (var i = 0; i < this.mpi.length; i++) {
|
for (var i = 0; i < this.params.length; i++) {
|
||||||
this.mpi[i] = type_mpi.fromClone(this.mpi[i]);
|
this.params[i] = type_mpi.fromClone(this.params[i]);
|
||||||
}
|
}
|
||||||
if (this.keyid) {
|
if (this.keyid) {
|
||||||
this.keyid = type_keyid.fromClone(this.keyid);
|
this.keyid = type_keyid.fromClone(this.keyid);
|
||||||
|
|
|
@ -55,10 +55,7 @@ export default function PublicKeyEncryptedSessionKey() {
|
||||||
this.version = 3;
|
this.version = 3;
|
||||||
|
|
||||||
this.publicKeyId = new type_keyid();
|
this.publicKeyId = new type_keyid();
|
||||||
this.publicKeyAlgorithm = 'rsa_encrypt';
|
|
||||||
|
|
||||||
this.sessionKey = null;
|
this.sessionKey = null;
|
||||||
this.sessionKeyAlgorithm = 'aes256';
|
|
||||||
|
|
||||||
/** @type {Array<module:type/mpi>} */
|
/** @type {Array<module:type/mpi>} */
|
||||||
this.encrypted = [];
|
this.encrypted = [];
|
||||||
|
@ -81,34 +78,20 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
|
||||||
|
|
||||||
var i = 10;
|
var i = 10;
|
||||||
|
|
||||||
var integerCount = (function(algo) {
|
var integerCount = crypto.getEncSessionKeyParamCount(this.publicKeyAlgorithm);
|
||||||
switch (algo) {
|
|
||||||
case 'rsa_encrypt':
|
|
||||||
case 'rsa_encrypt_sign':
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case 'elgamal':
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case 'ecdh':
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error("Invalid algorithm.");
|
|
||||||
}
|
|
||||||
})(this.publicKeyAlgorithm);
|
|
||||||
|
|
||||||
this.encrypted = [];
|
this.encrypted = [];
|
||||||
|
|
||||||
for (var j = 0; j < integerCount; j++) {
|
for (var j = 0; j < integerCount; j++) {
|
||||||
var mpi;
|
var param;
|
||||||
if (this.publicKeyAlgorithm === 'ecdh' && j === 1) {
|
if (this.publicKeyAlgorithm === 'ecdh' && j === 1) {
|
||||||
mpi = new type_ecdh_symkey();
|
param = new type_ecdh_symkey();
|
||||||
} else {
|
} else {
|
||||||
mpi = new type_mpi();
|
param = new type_mpi();
|
||||||
}
|
}
|
||||||
i += mpi.read(bytes.subarray(i, bytes.length));
|
i += param.read(bytes.subarray(i, bytes.length));
|
||||||
this.encrypted.push(mpi);
|
this.encrypted.push(param);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,20 +119,20 @@ PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) {
|
||||||
var checksum = util.calc_checksum(this.sessionKey);
|
var checksum = util.calc_checksum(this.sessionKey);
|
||||||
data += util.Uint8Array2str(util.writeNumber(checksum, 2));
|
data += util.Uint8Array2str(util.writeNumber(checksum, 2));
|
||||||
|
|
||||||
var mpi;
|
var param;
|
||||||
if (this.publicKeyAlgorithm === 'ecdh') {
|
if (this.publicKeyAlgorithm === 'ecdh') {
|
||||||
mpi = util.str2Uint8Array(crypto.pkcs5.addPadding(data));
|
param = util.str2Uint8Array(crypto.pkcs5.addPadding(data));
|
||||||
} else {
|
} else {
|
||||||
mpi = new type_mpi();
|
param = new type_mpi();
|
||||||
mpi.fromBytes(crypto.pkcs1.eme.encode(
|
param.fromBytes(crypto.pkcs1.eme.encode(
|
||||||
data,
|
data,
|
||||||
key.mpi[0].byteLength()));
|
key.params[0].byteLength()));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.encrypted = crypto.publicKeyEncrypt(
|
this.encrypted = crypto.publicKeyEncrypt(
|
||||||
this.publicKeyAlgorithm,
|
this.publicKeyAlgorithm,
|
||||||
key.mpi,
|
key.params,
|
||||||
mpi,
|
param,
|
||||||
key.fingerprint);
|
key.fingerprint);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,7 +147,7 @@ PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) {
|
||||||
PublicKeyEncryptedSessionKey.prototype.decrypt = function (key) {
|
PublicKeyEncryptedSessionKey.prototype.decrypt = function (key) {
|
||||||
var result = crypto.publicKeyDecrypt(
|
var result = crypto.publicKeyDecrypt(
|
||||||
this.publicKeyAlgorithm,
|
this.publicKeyAlgorithm,
|
||||||
key.mpi,
|
key.params,
|
||||||
this.encrypted,
|
this.encrypted,
|
||||||
key.fingerprint).toBytes();
|
key.fingerprint).toBytes();
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
|
||||||
return new Error("Hash mismatch.");
|
return new Error("Hash mismatch.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var mpis = crypto.getPrivateMpiCount(algorithm);
|
var mpis = crypto.getPrivKeyParamCount(algorithm);
|
||||||
|
|
||||||
var j = 0;
|
var j = 0;
|
||||||
var mpi = [];
|
var mpi = [];
|
||||||
|
@ -104,7 +104,7 @@ function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
|
||||||
|
|
||||||
function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
|
function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
|
||||||
var arr = [];
|
var arr = [];
|
||||||
var discard = crypto.getPublicMpiCount(algorithm);
|
var discard = crypto.getPubKeyParamCount(algorithm);
|
||||||
|
|
||||||
for (var i = discard; i < mpi.length; i++) {
|
for (var i = discard; i < mpi.length; i++) {
|
||||||
arr.push(mpi[i].write());
|
arr.push(mpi[i].write());
|
||||||
|
@ -147,7 +147,7 @@ SecretKey.prototype.read = function (bytes) {
|
||||||
if (parsedMPI instanceof Error) {
|
if (parsedMPI instanceof Error) {
|
||||||
throw parsedMPI;
|
throw parsedMPI;
|
||||||
}
|
}
|
||||||
this.mpi = this.mpi.concat(parsedMPI);
|
this.params = this.params.concat(parsedMPI);
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ SecretKey.prototype.write = function () {
|
||||||
|
|
||||||
if (!this.encrypted) {
|
if (!this.encrypted) {
|
||||||
arr.push(new Uint8Array([0]));
|
arr.push(new Uint8Array([0]));
|
||||||
arr.push(write_cleartext_mpi('mod', this.algorithm, this.mpi));
|
arr.push(write_cleartext_mpi('mod', this.algorithm, this.params));
|
||||||
} else {
|
} else {
|
||||||
arr.push(this.encrypted);
|
arr.push(this.encrypted);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ SecretKey.prototype.encrypt = function (passphrase) {
|
||||||
|
|
||||||
var s2k = new type_s2k(),
|
var s2k = new type_s2k(),
|
||||||
symmetric = 'aes256',
|
symmetric = 'aes256',
|
||||||
cleartext = write_cleartext_mpi('sha1', this.algorithm, this.mpi),
|
cleartext = write_cleartext_mpi('sha1', this.algorithm, this.params),
|
||||||
key = produceEncryptionKey(s2k, passphrase, symmetric),
|
key = produceEncryptionKey(s2k, passphrase, symmetric),
|
||||||
blockLen = crypto.cipher[symmetric].blockSize,
|
blockLen = crypto.cipher[symmetric].blockSize,
|
||||||
iv = crypto.random.getRandomBytes(blockLen);
|
iv = crypto.random.getRandomBytes(blockLen);
|
||||||
|
@ -267,7 +267,7 @@ SecretKey.prototype.decrypt = function (passphrase) {
|
||||||
if (parsedMPI instanceof Error) {
|
if (parsedMPI instanceof Error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.mpi = this.mpi.concat(parsedMPI);
|
this.params = this.params.concat(parsedMPI);
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
this.encrypted = null;
|
this.encrypted = null;
|
||||||
return true;
|
return true;
|
||||||
|
@ -276,8 +276,8 @@ SecretKey.prototype.decrypt = function (passphrase) {
|
||||||
SecretKey.prototype.generate = function (bits, curve) {
|
SecretKey.prototype.generate = function (bits, curve) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return crypto.generateMpi(self.algorithm, bits, curve).then(function(mpi) {
|
return crypto.generateParams(self.algorithm, bits, curve).then(function(params) {
|
||||||
self.mpi = mpi;
|
self.params = params;
|
||||||
self.isDecrypted = true;
|
self.isDecrypted = true;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -285,10 +285,10 @@ SecretKey.prototype.generate = function (bits, curve) {
|
||||||
/**
|
/**
|
||||||
* Clear private MPIs, return to initial state
|
* Clear private MPIs, return to initial state
|
||||||
*/
|
*/
|
||||||
SecretKey.prototype.clearPrivateMPIs = function () {
|
SecretKey.prototype.clearPrivateParams = function () {
|
||||||
if (!this.encrypted) {
|
if (!this.encrypted) {
|
||||||
throw new Error('If secret key is not encrypted, clearing private MPIs is irreversible.');
|
throw new Error('If secret key is not encrypted, clearing private MPIs is irreversible.');
|
||||||
}
|
}
|
||||||
this.mpi = this.mpi.slice(0, crypto.getPublicMpiCount(this.algorithm));
|
this.params = this.params.slice(0, crypto.getPubKeyParamCount(this.algorithm));
|
||||||
this.isDecrypted = false;
|
this.isDecrypted = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -243,7 +243,7 @@ Signature.prototype.sign = function (key, data) {
|
||||||
this.signedHashValue = hash.subarray(0, 2);
|
this.signedHashValue = hash.subarray(0, 2);
|
||||||
|
|
||||||
this.signature = crypto.signature.sign(hashAlgorithm,
|
this.signature = crypto.signature.sign(hashAlgorithm,
|
||||||
publicKeyAlgorithm, key.mpi, toHash);
|
publicKeyAlgorithm, key.params, toHash);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -644,7 +644,7 @@ Signature.prototype.verify = function (key, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.verified = crypto.signature.verify(publicKeyAlgorithm,
|
this.verified = crypto.signature.verify(publicKeyAlgorithm,
|
||||||
hashAlgorithm, mpi, key.mpi,
|
hashAlgorithm, mpi, key.params,
|
||||||
util.concatUint8Array([bytes, this.signatureData, trailer]));
|
util.concatUint8Array([bytes, this.signatureData, trailer]));
|
||||||
|
|
||||||
return this.verified;
|
return this.verified;
|
||||||
|
|
|
@ -42,9 +42,15 @@ import util from '../util.js';
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export default function MPI() {
|
export default function MPI(data) {
|
||||||
/** An implementation dependent integer */
|
/** An implementation dependent integer */
|
||||||
this.data = null;
|
if (data instanceof BigInteger) {
|
||||||
|
this.fromBigInteger(data);
|
||||||
|
} else if (typeof data === 'string') {
|
||||||
|
this.fromBytes(data);
|
||||||
|
} else {
|
||||||
|
this.data = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -191,13 +191,13 @@ describe("Packet", function() {
|
||||||
enc.publicKeyAlgorithm = 'rsa_encrypt';
|
enc.publicKeyAlgorithm = 'rsa_encrypt';
|
||||||
enc.sessionKeyAlgorithm = 'aes256';
|
enc.sessionKeyAlgorithm = 'aes256';
|
||||||
enc.publicKeyId.bytes = '12345678';
|
enc.publicKeyId.bytes = '12345678';
|
||||||
enc.encrypt({ mpi: mpi });
|
enc.encrypt({ params: mpi });
|
||||||
|
|
||||||
msg.push(enc);
|
msg.push(enc);
|
||||||
|
|
||||||
msg2.read(msg.write());
|
msg2.read(msg.write());
|
||||||
|
|
||||||
msg2[0].decrypt({ mpi: mpi });
|
msg2[0].decrypt({ params: mpi });
|
||||||
|
|
||||||
expect(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey));
|
expect(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey));
|
||||||
expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm);
|
expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm);
|
||||||
|
@ -445,8 +445,8 @@ describe("Packet", function() {
|
||||||
return mpi;
|
return mpi;
|
||||||
});
|
});
|
||||||
|
|
||||||
key[0].mpi = mpi;
|
key[0].params = mpi;
|
||||||
|
key[0].algorithm = "rsa_sign";
|
||||||
key[0].encrypt('hello');
|
key[0].encrypt('hello');
|
||||||
|
|
||||||
var raw = key.write();
|
var raw = key.write();
|
||||||
|
@ -455,7 +455,7 @@ describe("Packet", function() {
|
||||||
key2.read(raw);
|
key2.read(raw);
|
||||||
key2[0].decrypt('hello');
|
key2[0].decrypt('hello');
|
||||||
|
|
||||||
expect(key[0].mpi.toString()).to.equal(key2[0].mpi.toString());
|
expect(key[0].params.toString()).to.equal(key2[0].params.toString());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -473,7 +473,8 @@ describe("Packet", function() {
|
||||||
return mpi;
|
return mpi;
|
||||||
});
|
});
|
||||||
|
|
||||||
key.mpi = mpi;
|
key.params = mpi;
|
||||||
|
key.algorithm = "rsa_sign";
|
||||||
|
|
||||||
var signed = new openpgp.packet.List(),
|
var signed = new openpgp.packet.List(),
|
||||||
literal = new openpgp.packet.Literal(),
|
literal = new openpgp.packet.Literal(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user