0.1.3 • Published 11 years ago

cryptopp v0.1.3

Weekly downloads
4
License
GPLv2
Repository
github
Last release
11 years ago

node-cryptopp

================

Node.js module that statically binds and simplifies the usage of the Crypto++ comprehensive cryptography library.

Bindings for:

All the crypto methods could be used in sync/async mode

Requirements

Installation

On installation, the node-cryptopp module compiles on your computer. Hence Crypto++ needs to be installed.

To install this module, simply

npm install cryptopp

CAUTION : minor API changes starting from v.0.2.0

Use the KeyRing !

This feature was introduced in version 0.2.0. A friend of mine told me that "key management" in 0.1.x versions of node-cryptopp was totally unsafe because of javascript's memory management : you have cannot control when a keypair is ereased from memory, even though you removed all references to it. Because Node.js is a relatively new technology and it is highly probable that there are unknown exploits in it (like in any piece of software), it would be then unsafe to have private keys loaded in js code.

Hence, I created the KeyRing class, that manages keypair generation, saving, loading and clearing in addition to the cryptographic operations where the private key is needed. Also, there is no method in this class that will allow you to extract the private key.

As of now, I kept the unsafe methods from the previous versions of the module, but I highly recommend using the key ring.

Note that I wanted to allow key encryption (ie, when saving then on disk). But it doesn't work as of now. Hence, don't use the passphrase parameter (or skip it with undefined like you'd skip any other parameter in cryptopp, as explained below).

General notes

  • By default, each method described could be given a callback. If no callback is given, the method's result is returned.
  • If you want to skip an optional parameter but want to define the parameter that follows it, then the skipped parameter MUST be set to undefined. Sorry if this seems to totally inconvenient
  • This library isn't well written in terms of error management (except the KeyRing class). If the app crashes or throws some strange exception, it is probably because you did something wrong (Thanks Captain Obvious) but in general it won't tell you what it is. Note that if you use a method with a callback, the errors will be thrown exactly like when you use the method without a callback
  • The different ECC algorithms for which are (or will be) implemented here use standard elliptic curves, defined here. The related methods will have a "curveName" parameter, taken from the previously linked document, like "secp256r1" or "sect233k1". Beware, it is case-sensible. Each communicating side must use the same curve.
  • ECIES keypairs can be used in ECDSA and vice-versa! (as long as you use the same curve in both algorithms) paper that proves it; look for section 4
  • You can choose what hash function want to use in ECDSA and RSA signatures. You can choose either SHA1 (default) or SHA256. Just set the hashName parameter to 'sha1' or 'sha256' in the corresponding methods. Note that the default hash function for these algorthims in version prior to v0.2.0 was SHA256.
  • Keys, ciphertexts and signatures are all hex encoded. These data types should be kept "as-is" when passed to other methods.

Usage

The test.js script gives example usages for most implemented algorithms. So you can learn from there, in addition to learning from this page.

KeyRing

Before using the KeyRing, you must construct it. This is how it's done :

var cryptopp = require('cryptopp');
var keyRing = new cryptopp.KeyRing();

Here are the list of methods exposed by the KeyRing

  • createKeyPair(algoType, algoOptions, [filename], [passphrase], [callback]):
    Generates a keypair the given algorithm. Returns the public key information object (as in the publicKeyInfo() method) algoType : the name of the algorithm for which you want to create a keyPair. Possible values are "rsa", "dsa", "ecies", "ecdsa", "ecdh" algoOptions : the keysize when algoType is "rsa" or "dsa", the curve name otherwise filename : the path to the file where you want the keypair to saved. Optional parameter passphrase : a passphrase used to encrypt the keypair (when you choose to save it). Optional parameter * callback : a callback function, that will recieve the public key information object as argument. Optional parameter
  • decrypt(cipherText, [encoding], [callback])
    Decrypts the cipherText (optionally encoded) cipherText : the ciphertext to decrypt encoding : optional, the encoding of the ciphertext. Possible values are : 'hex', 'base64'. Defaults to 'hex' * callback : optional, receives the plaintext as a parameter
  • sign(message, [signatureEncoding], [hashName], [callback])
    Signs the message with the loaded key ring. message : the message to be signed signatureEncoding : optional, determines the encoding that should be used for the signature. Possible values : 'hex', 'base64'. Defaults to 'hex'. hashName : optional, name of the hash function to be used in the signing process. Possible values are 'sha1', 'sha256'. Defaults to 'sha1'. callback : optional. Recieves the signature as a parameter if used
  • agree(pubKey, [callback])
    Agrees on a shared secret and returns it (hex encoded) pubKey : object containing the keyType, curveName and publicKey attributes for an ECDH key agreement callback : receives the shared secret
  • publicKeyInfo([callback]) Returns an object containing public key information from the currently loaded key pair. You can give a callback. The returned object has the following attributes : keyType : a string that contains the algo type. Possible values : "rsa", "dsa", "ecdsa", "ecies", "ecdh" if (keyType == "rsa") : modulus : the RSA modulus publicExponent : the RSA public exponent if (keyType == "dsa") : primeField : the DSA prime field divider : the DSA divider base : the DSA base publicElement : the DSA public key if (keyType == "ecdsa" || keyType == "ecies") curveName : the standard name of the cruve used publicKey.x : x coordinate of the public point publicKey.y : y coordinate of the public point if (keyType == "ecdh") curveName : the standard name of the curve used publicKey : the ECDH public key
  • save(filename, [passphrase], [callback])
    Save the keypair to the given filename. DON'T USE THE PASSPHRASE! No paramter passed to the callback
  • load(filename, [passphrase], [callback])
    Load the keypair from the given path. DON'T USE THE PASSPHRASE! The callback receives the public key information object
  • clear()
    Deletes the keypair from memory. You MUST call this method once you're done working the keyring.

RSA

RSA encryption and signature schemes are supported by this module. For signatures : the default hashing function used here is SHA1, but you can specify the hashName parameter either to "sha1" or "sha256" (other values will throw an exception)

There are 5 methods for RSA :

  • rsa.generateKeyPair(keySize, callback(keyPair)) : Generates a RSA keypair with the given key size (in bits). The keysize must be 1024 <= Math.power(2, k) <= 16384 (where k is an integer). The result of the method is an object with 3 attributes : modulus, publicExponent and privateExponent
  • rsa.encrypt(plainText, modulus, publicExponent, callback(cipherText)) : Returns the ciphertext
  • rsa.decrypt(cipherText, modulus, privateExponent, publicExponent, callback(plainText)) : Returns the plain text message
  • rsa.sign(message, modulus, privateExponent, publicExponent, hashName, callback(signature)) : Signs the message with the given private key
  • rsa.verify(message, signature, modulus, publicExponent, hashName, callback(isValid)) : Tells whether the signature for the given message and public key is valid or not

Example usage

var cryptopp = require('cryptopp');
var rsaKeyPair = cryptopp.rsa.generateKeyPair(2048);
var cipher = cryptopp.rsa.encrypt('Testing RSA', rsaKeyPair.modulus, rsaKeyPair.publicExponent);
var plaintext = cryptopp.rsa.decrypt(cipher, rsaKeyPair.modulus, rsaKeyPair.privateExponent);

DSA

There are 3 methods for DSA. Note that the hashing function used here is SHA1.

  • dsa.generateKeyPair(keySize, callback(keyPair)) : Generates a DSA keypair with the given key size (in bits). The result is an object with 5 attributes : primeField, divider, base, privateExponent, publicElement
  • dsa.sign(message, primeField, divider, base, privateExponent, callback(signature)) : Signs the given message using DSA with SHA1
  • dsa.verify(message, signature, primeField, divider, base, publicElement, callback(isValid)) : Verifies the signature

Example usage

var cryptopp = require('cryptopp');
var dsaKeyPair = cryptopp.dsa.generateKeyPair(2048);
var message = 'Testing DSA';
var signature = cryptopp.dsa.sign(message, dsaKeyPair.primeField, dsaKeyPair.divider, dsaKeyPair.base, dsaKeyPair.privateExponent);
var isValid = cryptopp.dsa.verify(message, signature, dsaKeyPair.primeField, dsaKeyPair.divider, dsaKeyPair.base, dsaKeyPair.publicElement);

ECIES

Bindings have been written for ECIES on prime and binary fields.

The methods are reachable as following cryptopp.ecies.fieldType.methodname

For each of these fields, there are 3 methods available :

  • ecies.fieldType.generateKeyPair(curveName, callback(keyPair)) : Returns an object containing the private key, the public key, and curve name. The private and public keys are hex encoded and should be passed in that format to other methods.
  • ecies.fieldType.encrypt(plainText, publicKey, curveName, callback(cipherText)) : encrypts the plainText with the given publicKey on the given curve.
  • ecies.fieldType.decrypt(cipherText, privateKey, curveName, callback(plainText)) : decrypts the cipherText with the given privateKey on the given curve.

Example usage

var cryptopp = require('cryptopp');
var keyPair = cryptopp.ecies.prime.generateKeyPair("secp256r1");
var cipher = cryptopp.ecies.prime.encrypt("Testing ECIES", keyPair.publicKey, keyPair.curveName);
var plainText = cryptopp.ecies.prime.decrypt(cipher, keyPair.privateKey, keyPair.curveName);

To use ECIES on binary fields, just replace in the code above "prime" by "binary" and the curve name by a "binary curve" one.

ECDSA

Bindings have been written for ECDSA for prime and prime fields. However, there is a bug somewhere in the binary field version in the signing method (probably in hexStr<->PolynomialMod2 conversions, a bug I don't want to fix for now...). You can choose which hashing function you want to use by setting the hashName parameter either to "sha1" or "sha256" (other values will throw an exception). The ECDSA methods are reachable in a manner similar to ECIES. Here are ECDSA's methods :

Example usage

var cryptopp = require('cryptopp');
var keyPair = cryptopp.ecdsa.prime.generateKeyPair("secp256r1");
var message = "Testing ECDSA";
var signature = cryptopp.ecdsa.prime.sign(message, keyPair.privateKey, keyPair.curveName);
var isValid = cryptopp.ecdsa.prime.verify(message, signature, keyPair.publicKey, keyPair.curveName);

ECDH

Binding have been written for ECDH for both type of fields. However, the ECDH version don't always give the same secret in the "agree" method. So don't use it... There is probably a bug somewhere in hexStr<->PolynomialMod2 conversion methods, but I don't want to fix it for now.

There are only 2 methods per field :

  • ecdh.fieldType.generateKeyPair(curveName, callback(keyPair)) : The result is an object with 3 attributes : curveName, privateKey, publicKey
  • ecdh.fieldType.agree(yourPrivateKey, yourCounterpartsPublicKey, curveName, callback(secret)) : Returns the common secret.

Example usage

var cryptopp = require('cryptopp');
var ecdhKeyPair1 = cryptopp.ecdh.prime.generateKeyPair('secp256r1');
var ecdhKeyPair2 = cryptopp.ecdh.prime.generateKeyPair('secp256r1');
var secret1 = cryptopp.ecdh.prime.agree(ecdhKeyPair1.privateKey, ecdhKeyPair2.publicKey, ecdhKeyPair1.curveName);
var secret2 = cryptopp.ecdh.prime.agree(ecdhKeyPair2.privateKey, ecdhKeyPair1.publicKey, ecdhKeyPair2.curveName);

Random bytes generation

I found it useful to have a method that gives you random bytes, using the a generator from Crypto++ rather than Math.random() or whatever

cryptopp.randomBytes(length, encoding) :

  • length : number of bytes to be generated
  • encoding : optional, possible values are 'hex' for hexadecimal and 'base64' for Base64 encoding. Defaults to 'hex'.

Hex and Base64 encodings

Although there are already ways to encode/decode to hex/base64 in Node.js, I wrote bindings to the implementations in Crypto++

  • hex.encode(text) : Encode the text to hexadecimal
  • hex.decode(encoded) : Decode the hex encoded text

  • base64.encode(text) : Encode the text to Base64

  • base64.decode(encoded) : Decode the Base64 encoded text

Keypair file format

Here is how a keypair file is built. Note that every number is in written in big endian

  • algoType : a byte; 0x00 for ECDSA, 0x01 for RSA, 0x02 for DSA, 0x03 for ECDH, 0x04 for ECIES
  • if keyType is ECDSA or ECIES curveID : a byte, corresponding to the curve used publicKeyX.length : length of the x coordinate of the public point (2 bytes, signed integer) publicKeyX : x coordinate of the public point publicKeyY.length : length of the y coordinate of the public point (2 bytes, signed integer) publicKeyY : y coordinate of the public point privateKey.length : length of the private key (2 bytes) * privateKey
  • if keyType is RSA modulus.length : length of the RSA modulus (2 bytes, signed integer) modulus : RSA modulus publicExponent.length : length of the public exponent (2 bytes, signed integer) publicExponent : RSA public exponent (or public key) privateExponent.length : length of the private exponent (2 bytes, signed integer) privateExponent : RSA private exponent (or private key)
  • if keyType is DSA primeField.length : length of the prime field used by the DSA key pair (2 bytes, signed integer) primeField divider.length : length of the divider (2 bytes, signed integer) divider base.length : length of the base (2 bytes, signed integer) base : DSA base publicElement.length : length of the DSA public key (2 bytes, signed integer) publicElement : DSA public key privateExponent.length : length of the DSA private exponent (2 bytes, signed integer) privateExponent : DSA private exponent (or private key)
  • if keyType is ECDH curveID : a byte, corresponding to the curve used publicKey.length : length of the ECDH public key (2 bytes, signed integer) publicKey : ECDH public key privateKey.length : length of the ECDH private key (2 bytes, signed integer) * privateKey : ECDH private key

CruveName <-> CurveID

CurveIDCurve name
0x01secp112r1
0x02secp112r2
0x03secp128r1
0x04secp128r2
0x05secp160r1
0x06secp160r2
0x07secp160k1
0x08secp192r1
0x09secp192k1
0x0Asecp224r1
0x0Bsecp224k1
0x0Csecp256r1
0x0Dsecp256k1
0x0Esecp384r1
0x0Fsecp521r1
0x80sect113r1
0x81sect113r2
0x82sect131r1
0x83sect131r2
0x84sect163r1
0x85sect163r2
0x86sect163k1
0x87sect193r1
0x88sect193r2
0x89sect233r1
0x8Asect233k1
0x8Bsect239r1
0x8Csect283r1
0x8Dsect283k1
0x8Esect409r1
0x8Fsect409k1
0x90sect571r1
0x91sect571k1

License

This module is licensed under GPLv2.

0.2.1

10 years ago

0.2.0

10 years ago

0.1.3

11 years ago

0.1.2

11 years ago

0.1.1

11 years ago

0.1.0

11 years ago