Browse Source

crypto: allow setting add'l authenticated data

v0.11.12-release
Brian White 11 years ago
committed by Fedor Indutny
parent
commit
31ce34887f
  1. 12
      doc/api/crypto.markdown
  2. 4
      lib/crypto.js
  3. 30
      src/node_crypto.cc
  4. 2
      src/node_crypto.h
  5. 18
      test/simple/test-crypto-authenticated.js

12
doc/api/crypto.markdown

@ -250,6 +250,12 @@ method returns a `Buffer` that represents the _authentication tag_ that
has been computed from the given data. Should be called after has been computed from the given data. Should be called after
encryption has been completed using the `final` method! encryption has been completed using the `final` method!
### cipher.setAAD(buffer)
For authenticated encryption modes (currently supported: GCM), this
method sets the value used for the additional authenticated data (AAD) input
parameter.
## crypto.createDecipher(algorithm, password) ## crypto.createDecipher(algorithm, password)
@ -308,6 +314,12 @@ If no tag is provided or if the ciphertext has been tampered with,
`final` will throw, thus indicating that the ciphertext should `final` will throw, thus indicating that the ciphertext should
be discarded due to failed authentication. be discarded due to failed authentication.
### decipher.setAAD(buffer)
For authenticated encryption modes (currently supported: GCM), this
method sets the value used for the additional authenticated data (AAD) input
parameter.
## crypto.createSign(algorithm) ## crypto.createSign(algorithm)

4
lib/crypto.js

@ -334,6 +334,9 @@ Cipheriv.prototype.setAuthTag = function(tagbuf) {
this._binding.setAuthTag(tagbuf); this._binding.setAuthTag(tagbuf);
}; };
Cipheriv.prototype.setAAD = function(aadbuf) {
this._binding.setAAD(aadbuf);
};
exports.createDecipher = exports.Decipher = Decipher; exports.createDecipher = exports.Decipher = Decipher;
@ -381,6 +384,7 @@ Decipheriv.prototype.finaltol = Cipher.prototype.final;
Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
Decipheriv.prototype.getAuthTag = Cipheriv.prototype.getAuthTag; Decipheriv.prototype.getAuthTag = Cipheriv.prototype.getAuthTag;
Decipheriv.prototype.setAuthTag = Cipheriv.prototype.setAuthTag; Decipheriv.prototype.setAuthTag = Cipheriv.prototype.setAuthTag;
Decipheriv.prototype.setAAD = Cipheriv.prototype.setAAD;

30
src/node_crypto.cc

@ -2194,6 +2194,7 @@ void CipherBase::Initialize(Environment* env, Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding); NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
NODE_SET_PROTOTYPE_METHOD(t, "getAuthTag", GetAuthTag); NODE_SET_PROTOTYPE_METHOD(t, "getAuthTag", GetAuthTag);
NODE_SET_PROTOTYPE_METHOD(t, "setAuthTag", SetAuthTag); NODE_SET_PROTOTYPE_METHOD(t, "setAuthTag", SetAuthTag);
NODE_SET_PROTOTYPE_METHOD(t, "setAAD", SetAAD);
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "CipherBase"), target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "CipherBase"),
t->GetFunction()); t->GetFunction());
@ -2386,6 +2387,35 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {
} }
bool CipherBase::SetAAD(const char* data, unsigned int len) {
if (!initialised_ || !IsAuthenticatedMode())
return false;
int outlen;
if (!EVP_CipherUpdate(&ctx_,
NULL,
&outlen,
reinterpret_cast<const unsigned char*>(data),
len)) {
ThrowCryptoTypeError(env(), ERR_get_error());
return false;
}
return true;
}
void CipherBase::SetAAD(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope handle_scope(env->isolate());
ASSERT_IS_BUFFER(args[0]);
CipherBase* cipher = Unwrap<CipherBase>(args.This());
if (!cipher->SetAAD(Buffer::Data(args[0]), Buffer::Length(args[0])))
env->ThrowError("Attempting to set AAD in unsupported state");
}
bool CipherBase::Update(const char* data, bool CipherBase::Update(const char* data,
int len, int len,
unsigned char** out, unsigned char** out,

2
src/node_crypto.h

@ -356,6 +356,7 @@ class CipherBase : public BaseObject {
bool IsAuthenticatedMode() const; bool IsAuthenticatedMode() const;
bool GetAuthTag(char** out, unsigned int* out_len) const; bool GetAuthTag(char** out, unsigned int* out_len) const;
bool SetAuthTag(const char* data, unsigned int len); bool SetAuthTag(const char* data, unsigned int len);
bool SetAAD(const char* data, unsigned int len);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args); static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -366,6 +367,7 @@ class CipherBase : public BaseObject {
static void GetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args); static void SetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetAAD(const v8::FunctionCallbackInfo<v8::Value>& args);
CipherBase(Environment* env, CipherBase(Environment* env,
v8::Local<v8::Object> wrap, v8::Local<v8::Object> wrap,

18
test/simple/test-crypto-authenticated.js

@ -41,11 +41,17 @@ crypto.DEFAULT_ENCODING = 'buffer';
// //
var TEST_CASES = [ var TEST_CASES = [
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4', iv: 'X6sIq117H0vR', { algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4',
plain: 'Hello World!', ct: '4BE13896F64DFA2C2D0F2C76', iv: 'X6sIq117H0vR', plain: 'Hello World!',
ct: '4BE13896F64DFA2C2D0F2C76',
tag: '272B422F62EB545EAA15B5FF84092447', tampered: false }, tag: '272B422F62EB545EAA15B5FF84092447', tampered: false },
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4', iv: 'X6sIq117H0vR', { algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4',
plain: 'Hello World!', ct: '4BE13596F64DFA2C2D0FAC76', iv: 'X6sIq117H0vR', plain: 'Hello World!',
ct: '4BE13896F64DFA2C2D0F2C76', aad: '000000FF',
tag: 'BA2479F66275665A88CB7B15F43EB005', tampered: false },
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4',
iv: 'X6sIq117H0vR', plain: 'Hello World!',
ct: '4BE13596F64DFA2C2D0FAC76',
tag: '272B422F62EB545EAA15B5FF84092447', tampered: true }, tag: '272B422F62EB545EAA15B5FF84092447', tampered: true },
{ algo: 'aes-256-gcm', key: '3zTvzr3p67VC61jmV54rIYu1545x4TlY', { algo: 'aes-256-gcm', key: '3zTvzr3p67VC61jmV54rIYu1545x4TlY',
iv: '60iP0h6vJoEa', plain: 'Hello node.js world!', iv: '60iP0h6vJoEa', plain: 'Hello node.js world!',
@ -69,6 +75,8 @@ for (var i in TEST_CASES) {
(function() { (function() {
var encrypt = crypto.createCipheriv(test.algo, test.key, test.iv); var encrypt = crypto.createCipheriv(test.algo, test.key, test.iv);
if (test.aad)
encrypt.setAAD(new Buffer(test.aad, 'hex'));
var hex = encrypt.update(test.plain, 'ascii', 'hex'); var hex = encrypt.update(test.plain, 'ascii', 'hex');
hex += encrypt.final('hex'); hex += encrypt.final('hex');
var auth_tag = encrypt.getAuthTag(); var auth_tag = encrypt.getAuthTag();
@ -82,6 +90,8 @@ for (var i in TEST_CASES) {
(function() { (function() {
var decrypt = crypto.createDecipheriv(test.algo, test.key, test.iv); var decrypt = crypto.createDecipheriv(test.algo, test.key, test.iv);
decrypt.setAuthTag(new Buffer(test.tag, 'hex')); decrypt.setAuthTag(new Buffer(test.tag, 'hex'));
if (test.aad)
decrypt.setAAD(new Buffer(test.aad, 'hex'));
var msg = decrypt.update(test.ct, 'hex', 'ascii'); var msg = decrypt.update(test.ct, 'hex', 'ascii');
if (!test.tampered) { if (!test.tampered) {
msg += decrypt.final('ascii'); msg += decrypt.final('ascii');

Loading…
Cancel
Save