Skip to content

Commit

Permalink
crypto: allow setting add'l authenticated data
Browse files Browse the repository at this point in the history
  • Loading branch information
mscdex authored and indutny committed Mar 4, 2014
1 parent caca4f3 commit 31ce348
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 4 deletions.
12 changes: 12 additions & 0 deletions doc/api/crypto.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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
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)

Expand Down Expand Up @@ -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
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)

Expand Down
4 changes: 4 additions & 0 deletions lib/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ Cipheriv.prototype.setAuthTag = function(tagbuf) {
this._binding.setAuthTag(tagbuf);
};

Cipheriv.prototype.setAAD = function(aadbuf) {
this._binding.setAAD(aadbuf);
};


exports.createDecipher = exports.Decipher = Decipher;
Expand Down Expand Up @@ -381,6 +384,7 @@ Decipheriv.prototype.finaltol = Cipher.prototype.final;
Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
Decipheriv.prototype.getAuthTag = Cipheriv.prototype.getAuthTag;
Decipheriv.prototype.setAuthTag = Cipheriv.prototype.setAuthTag;
Decipheriv.prototype.setAAD = Cipheriv.prototype.setAAD;



Expand Down
30 changes: 30 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2194,6 +2194,7 @@ void CipherBase::Initialize(Environment* env, Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
NODE_SET_PROTOTYPE_METHOD(t, "getAuthTag", GetAuthTag);
NODE_SET_PROTOTYPE_METHOD(t, "setAuthTag", SetAuthTag);
NODE_SET_PROTOTYPE_METHOD(t, "setAAD", SetAAD);

target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "CipherBase"),
t->GetFunction());
Expand Down Expand Up @@ -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,
int len,
unsigned char** out,
Expand Down
2 changes: 2 additions & 0 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ class CipherBase : public BaseObject {
bool IsAuthenticatedMode() const;
bool GetAuthTag(char** out, unsigned int* out_len) const;
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 Init(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand All @@ -366,6 +367,7 @@ class CipherBase : public BaseObject {

static void GetAuthTag(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,
v8::Local<v8::Object> wrap,
Expand Down
18 changes: 14 additions & 4 deletions test/simple/test-crypto-authenticated.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,17 @@ crypto.DEFAULT_ENCODING = 'buffer';
//

var TEST_CASES = [
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4', iv: 'X6sIq117H0vR',
plain: 'Hello World!', ct: '4BE13896F64DFA2C2D0F2C76',
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4',
iv: 'X6sIq117H0vR', plain: 'Hello World!',
ct: '4BE13896F64DFA2C2D0F2C76',
tag: '272B422F62EB545EAA15B5FF84092447', tampered: false },
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4', iv: 'X6sIq117H0vR',
plain: 'Hello World!', ct: '4BE13596F64DFA2C2D0FAC76',
{ algo: 'aes-128-gcm', key: 'ipxp9a6i1Mb4USb4',
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 },
{ algo: 'aes-256-gcm', key: '3zTvzr3p67VC61jmV54rIYu1545x4TlY',
iv: '60iP0h6vJoEa', plain: 'Hello node.js world!',
Expand All @@ -69,6 +75,8 @@ for (var i in TEST_CASES) {

(function() {
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');
hex += encrypt.final('hex');
var auth_tag = encrypt.getAuthTag();
Expand All @@ -82,6 +90,8 @@ for (var i in TEST_CASES) {
(function() {
var decrypt = crypto.createDecipheriv(test.algo, test.key, test.iv);
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');
if (!test.tampered) {
msg += decrypt.final('ascii');
Expand Down

0 comments on commit 31ce348

Please sign in to comment.