comments, docs
This commit is contained in:
parent
cbe61e6feb
commit
f8bfde7447
134
README-ECC.md
134
README-ECC.md
|
@ -1,134 +0,0 @@
|
||||||
# Elliptic Curve Cryptography support for OpenPGPjs
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
This work is to provide an implementation of [RFC 6637](http://www.ietf.org/rfc/rfc6637.txt)
|
|
||||||
for OpenPGP.js.
|
|
||||||
|
|
||||||
## Compatibility with GnuPG
|
|
||||||
|
|
||||||
In order to assure compatibility of the provided implementation with RFC 6637,
|
|
||||||
the keys and messages were tested against GnuPG version v2.1.8, compiled
|
|
||||||
with a beta version of libgcrypt v1.7.0-beta262.
|
|
||||||
|
|
||||||
It was tested that keys, messages, and signatures generated by GnuPG
|
|
||||||
were imported correctly. Also keys, messages and signatures generated by this
|
|
||||||
implementation are correctly imported by GnuPG.
|
|
||||||
|
|
||||||
```txt
|
|
||||||
> gpg2 --homedir ../home --version
|
|
||||||
gpg (GnuPG) 2.1.8
|
|
||||||
libgcrypt 1.7.0-beta262
|
|
||||||
Copyright (C) 2015 Free Software Foundation, Inc.
|
|
||||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
|
||||||
This is free software: you are free to change and redistribute it.
|
|
||||||
There is NO WARRANTY, to the extent permitted by law.
|
|
||||||
|
|
||||||
Home: ../home
|
|
||||||
Supported algorithms:
|
|
||||||
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
|
|
||||||
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
|
|
||||||
CAMELLIA128, CAMELLIA192, CAMELLIA256
|
|
||||||
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
|
|
||||||
Compression: Uncompressed, ZIP, ZLIB
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extra dependencies
|
|
||||||
|
|
||||||
There are two new dependencies:
|
|
||||||
|
|
||||||
* [Elliptic](https://github.com/indutny/elliptic/) for the elliptic curve
|
|
||||||
cryptography. MIT license.
|
|
||||||
|
|
||||||
* [Aes](https://github.com/cryptocoinjs/aes) required to implement RFC 3394
|
|
||||||
Key wrap and Key Unwrap functions. BSD License.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Generate new key
|
|
||||||
|
|
||||||
```js
|
|
||||||
var openpgp = require('openpgp');
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
curve: 'secp256k1',
|
|
||||||
userIds: {name: 'Hamlet', email: 'hamlet@example.net'},
|
|
||||||
passphrase: 'To be, or not to be: that is the question'
|
|
||||||
};
|
|
||||||
|
|
||||||
openpgp.generateKey(options).then(function(key) {
|
|
||||||
// success
|
|
||||||
var privkey = key.privateKeyArmored;
|
|
||||||
var pubkey = key.publicKeyArmored;
|
|
||||||
}).catch(function(error) {
|
|
||||||
// failure
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generate keypair from bitcoin key
|
|
||||||
|
|
||||||
```js
|
|
||||||
var openpgp = require('openpgp');
|
|
||||||
var bs58check = require('bs58check');
|
|
||||||
|
|
||||||
var wif = 'KyiAchQgMKuXQu89j6k6UVZQj7brK6cM79JfmDvkNXPVW24L1thi';
|
|
||||||
var buff = bs58check.decode(wif);
|
|
||||||
var privateKey = buff.slice(1, -1);
|
|
||||||
privateKey = openpgp.util.bin2str(privateKey);
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
curve: 'secp256k1',
|
|
||||||
userIds: {name: 'Hamlet', email: 'hamlet@example.net'},
|
|
||||||
passphrase: 'To be, or not to be: that is the question',
|
|
||||||
material: {
|
|
||||||
key: privateKey,
|
|
||||||
subkey: privateKey
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
openpgp.generateKey(options).then(function(key) {
|
|
||||||
// success
|
|
||||||
var privkey = key.privateKeyArmored;
|
|
||||||
var pubkey = key.publicKeyArmored;
|
|
||||||
}).catch(function(error) {
|
|
||||||
// failure
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Signature, encryption and decryption
|
|
||||||
|
|
||||||
The normal operations: signature, encryption and decryption require
|
|
||||||
no modifications.
|
|
||||||
|
|
||||||
```js
|
|
||||||
var openpgp = require('openpgp');
|
|
||||||
|
|
||||||
var keyData = '-----BEGIN PGP PUBLIC KEY BLOCK ... END PGP PUBLIC KEY BLOCK-----';
|
|
||||||
var key = openpgp.key.readArmored(keyData);
|
|
||||||
|
|
||||||
openpgp.encrypt({publicKeys: key.keys, data: 'Hello, World!'}).then(function(msg) {
|
|
||||||
// success
|
|
||||||
}).catch(function(error) {
|
|
||||||
// failure
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Possible improvements
|
|
||||||
|
|
||||||
* The dependency with AES library can be eliminated, a suitable AES decrypt
|
|
||||||
function is provided. It is only used by the wrap and unwrap functions
|
|
||||||
in the crypto/rfc3394.js file.
|
|
||||||
|
|
||||||
## Note
|
|
||||||
|
|
||||||
Although the example uses the same value to generate the main key, and
|
|
||||||
the subkey, it is a recommended practice to use different keys.
|
|
||||||
The main key is used for signature and the subkeys are used for encryption.
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
* Elliptic Curve Cryptography (ECC) in OpenPGP [RFC 6637](http://www.ietf.org/rfc/rfc6637.txt)
|
|
||||||
* OpenPGP Message Format [RFC 4880](http://www.ietf.org/rfc/rfc4880.txt)
|
|
||||||
* Advanced Encryption Standard (AES) Key Wrap Algorithm [RFC 3394](http://www.ietf.org/rfc/rfc3394.txt)
|
|
||||||
* A JavaScript component for the Advanced Encryption Standard (AES) [AES](https://github.com/cryptocoinjs/aes)
|
|
||||||
* Fast elliptic-curve cryptography in a plain javascript implementation [Elliptic](https://github.com/indutny/elliptic/)
|
|
|
@ -65,10 +65,9 @@ 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>} publicParams Algorithm dependent multiprecision integers
|
* @param {Array<module:type/mpi|module:type/oid|module:type/kdf|module:type/ecdh_symkey>} publicParams Algorithm dependent params
|
||||||
* @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|module:type/oid|module:type/kdf|module:type/ecdh_symkey>} encrypted session key parameters
|
||||||
* if elgamal encryption an array of two module:type/mpi is returned; otherwise null
|
|
||||||
*/
|
*/
|
||||||
publicKeyEncrypt: function(algo, publicParams, data, fingerprint) {
|
publicKeyEncrypt: function(algo, publicParams, data, fingerprint) {
|
||||||
var types = this.getEncSessionKeyParamTypes(algo);
|
var types = this.getEncSessionKeyParamTypes(algo);
|
||||||
|
@ -111,17 +110,13 @@ 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>} publicParams Algorithm dependent multiprecision integers
|
* @param {Array<module:type/mpi|module:type/oid|module:type/kdf|module:type/ecdh_symkey>} keyIntegers Algorithm dependent params
|
||||||
* of the public key part of the private key
|
* @param {String} fingerprint Recipient fingerprint
|
||||||
* @param {Array<module:type/mpi>} secretMPIs Algorithm dependent multiprecision integers
|
|
||||||
* of the private key used
|
|
||||||
* @param {module:type/mpi} data Data to be encrypted as MPI
|
|
||||||
* @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null
|
* @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null
|
||||||
*/
|
*/
|
||||||
|
|
||||||
publicKeyDecrypt: function(algo, keyIntegers, dataIntegers, fingerprint) {
|
publicKeyDecrypt: function(algo, keyIntegers, dataIntegers, fingerprint) {
|
||||||
var p;
|
var p;
|
||||||
|
|
||||||
var bn = (function() {
|
var bn = (function() {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case 'rsa_encrypt_sign':
|
case 'rsa_encrypt_sign':
|
||||||
|
@ -163,9 +158,9 @@ export default {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Returns the number of integers comprising the private key of an algorithm
|
/** Returns the types comprising the private key of an algorithm
|
||||||
* @param {String} algo The public key algorithm
|
* @param {String} algo The public key algorithm
|
||||||
* @return {Integer} The number of integers.
|
* @return {Array<String>} The array of types
|
||||||
*/
|
*/
|
||||||
getPrivKeyParamTypes: function(algo) {
|
getPrivKeyParamTypes: function(algo) {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
|
@ -196,10 +191,10 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getPrivKeyParamCount: function(algo) {
|
/** Returns the types comprising the public key of an algorithm
|
||||||
return this.getPrivKeyParamTypes(algo).length;
|
* @param {String} algo The public key algorithm
|
||||||
},
|
* @return {Array<String>} The array of types
|
||||||
|
*/
|
||||||
getPubKeyParamTypes: function(algo) {
|
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;
|
||||||
|
@ -230,7 +225,7 @@ export default {
|
||||||
// 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.
|
// - KDF: variable-length field containing KDF parameters.
|
||||||
case 'ecdh':
|
case 'ecdh':
|
||||||
return ['oid', 'mpi', 'kdf'];
|
return ['oid', 'mpi', 'kdf'];
|
||||||
default:
|
default:
|
||||||
|
@ -238,10 +233,10 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getPubKeyParamCount: function(algo) {
|
/** Returns the types comprising the encrypted session key of an algorithm
|
||||||
return this.getPubKeyParamTypes(algo).length;
|
* @param {String} algo The public key algorithm
|
||||||
},
|
* @return {Array<String>} The array of types
|
||||||
|
*/
|
||||||
getEncSessionKeyParamTypes: function(algo) {
|
getEncSessionKeyParamTypes: function(algo) {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
// Algorithm-Specific Fields for RSA encrypted session keys:
|
// Algorithm-Specific Fields for RSA encrypted session keys:
|
||||||
|
@ -258,7 +253,7 @@ export default {
|
||||||
|
|
||||||
// Algorithm-Specific Fields for ECDH encrypted session keys:
|
// Algorithm-Specific Fields for ECDH encrypted session keys:
|
||||||
// - MPI containing the ephemeral key used to establish the shared secret
|
// - MPI containing the ephemeral key used to establish the shared secret
|
||||||
// - ECDHSymmetricKey
|
// - ECDH Symmetric Key
|
||||||
case 'ecdh':
|
case 'ecdh':
|
||||||
return ['mpi', 'ecdh_symkey'];
|
return ['mpi', 'ecdh_symkey'];
|
||||||
|
|
||||||
|
@ -267,10 +262,10 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getEncSessionKeyParamCount: function(algo) {
|
/** Generate algorithm-specific key parameters
|
||||||
return this.getEncSessionKeyParamTypes(algo).length;
|
* @param {String} algo The public key algorithm
|
||||||
},
|
* @return {Array} The array of parameters
|
||||||
|
*/
|
||||||
generateParams: function(algo, bits, curve) {
|
generateParams: function(algo, bits, curve) {
|
||||||
var types = this.getPubKeyParamTypes(algo).concat(this.getPrivKeyParamTypes(algo));
|
var types = this.getPubKeyParamTypes(algo).concat(this.getPrivKeyParamTypes(algo));
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
|
|
|
@ -134,7 +134,7 @@ 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 paramCount = crypto.getPubKeyParamCount(this.algorithm);
|
var paramCount = crypto.getPubKeyParamTypes(this.algorithm).length;
|
||||||
|
|
||||||
for (var i = 0; i < paramCount; i++) {
|
for (var i = 0; i < paramCount; i++) {
|
||||||
arr.push(this.params[i].write());
|
arr.push(this.params[i].write());
|
||||||
|
@ -189,7 +189,7 @@ 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 paramCount = crypto.getPubKeyParamCount(this.algorithm);
|
var paramCount = crypto.getPubKeyParamTypes(this.algorithm).length;
|
||||||
for (var i = 0; i < paramCount; i++) {
|
for (var i = 0; i < paramCount; i++) {
|
||||||
toHash += this.params[i].toBytes();
|
toHash += this.params[i].toBytes();
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ function parse_cleartext_params(hash_algorithm, cleartext, algorithm) {
|
||||||
|
|
||||||
function write_cleartext_params(hash_algorithm, algorithm, params) {
|
function write_cleartext_params(hash_algorithm, algorithm, params) {
|
||||||
var arr = [];
|
var arr = [];
|
||||||
var numPublicParams = crypto.getPubKeyParamCount(algorithm);
|
var numPublicParams = crypto.getPubKeyParamTypes(algorithm).length;
|
||||||
|
|
||||||
for (var i = numPublicParams; i < params.length; i++) {
|
for (var i = numPublicParams; i < params.length; i++) {
|
||||||
arr.push(params[i].write());
|
arr.push(params[i].write());
|
||||||
|
@ -288,6 +288,6 @@ 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.params = this.params.slice(0, crypto.getPubKeyParamCount(this.algorithm));
|
this.params = this.params.slice(0, crypto.getPubKeyParamTypes(this.algorithm).length);
|
||||||
this.isDecrypted = false;
|
this.isDecrypted = false;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user