Skip to content
This repository was archived by the owner on Jul 3, 2020. It is now read-only.

Commit 547f7d9

Browse files
author
Face Kapow
committed
crypto_aead_chacha20poly1305_encrypt, crypto_aead_chacha20poly1305_decrypt
1 parent 639bf2d commit 547f7d9

3 files changed

Lines changed: 188 additions & 3 deletions

File tree

js/core/libsodium.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,32 @@ function hexToU8(hexStr) {
2626
return u8;
2727
}
2828

29+
function throwErr(funcName, argName, i, msg) {
30+
throw new Error(funcName + ': ' + argName + ' (argument ' + i + ') ' + msg + '.');
31+
}
32+
2933
function stringOrU8(arg, funcName, argName, i, msg) {
3034
var ret = arg;
3135
if (!(arg instanceof Uint8Array)) {
32-
if (typeof arg === 'string') {
36+
if (typeof arg === 'string' || (arg instanceof String)) {
3337
ret = new Uint8Array(arg.length);
3438
for (var i = 0; i < arg.length; i++) {
3539
ret[i] = arg.charCodeAt(i);
3640
}
3741
} else {
38-
throw new Error(funcName + ': ' + argName + '(argument ' + i + ') ' + (msg ? msg : 'must be a string or Uint8Array') + '.');
42+
throwErr(funcName, argName, i, (msg ? msg : 'must be a string or Uint8Array'));
3943
}
4044
}
4145
return ret;
4246
}
4347

48+
function isNumber(arg, funcName, argName, i, msg) {
49+
if (typeof arg !== 'number' && !(arg instanceof Number)) {
50+
throwErr(funcName, argName, i, (msg ? msg : 'must be a number'));
51+
}
52+
return arg;
53+
}
54+
4455
module.exports = {
4556
crypto_secretbox_easy: function(data, key) {
4657
var dataArr = stringOrU8(data, 'crypto_secretbox_easy', 'data', 0);
@@ -92,7 +103,37 @@ module.exports = {
92103
var dataArr = stringOrU8(data, 'crypto_auth_verify', 'data', 2);
93104

94105
return lib.crypto_auth_verify(macArr, keyArr, dataArr);
95-
}
106+
},
107+
crypto_aead_chacha20poly1305_encrypt: function(data, key, addData) {
108+
var dataArr = stringOrU8(data, 'crypto_secretbox_easy', 'data', 0);
109+
var keyArr = stringOrU8(key, 'crypto_secretbox_easy', 'key', 1);
110+
var addDataArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_encrypt', 'additional data', 2);
111+
112+
var nonceArr = runtime.random.getRandomValues(constants.crypto_aead_chacha20poly1305_NPUBBYTES);
113+
114+
var cipher = lib.crypto_aead_chacha20poly1305_encrypt(dataArr, keyArr, nonceArr, addDataArr);
115+
if (!cipher) {
116+
throw new Error('crypto_aead_chacha20poly1305_encrypt: error creating box.');
117+
}
118+
return {
119+
ciphertext: hexToU8(cipher.ciphertext),
120+
nonce: nonceArr,
121+
length: cipher.ciphertext_len
122+
};
123+
},
124+
crypto_aead_chacha20poly1305_decrypt: function(cipher, cipherLength, key, nonce, addData) {
125+
var cipherArr = stringOrU8(cipher, 'crypto_aead_chacha20poly1305_decrypt', 'cipher', 0);
126+
var cipherLen = isNumber(cipherLength, 'crypto_aead_chacha20poly1305_decrypt', 'cipher length', 1);
127+
var keyArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_decrypt', 'key', 2);
128+
var nonceArr = stringOrU8(nonce, 'crypto_aead_chacha20poly1305_decrypt', 'nonce', 3);
129+
var addDataArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_decrypt', 'additional data', 4);
130+
131+
var decipher = lib.crypto_aead_chacha20poly1305_decrypt(cipherArr, keyArr, nonceArr, addDataArr, cipherLen);
132+
if (!decipher) {
133+
throw new Error('crypto_aead_chacha20poly1305_decrypt: error decrypting box.');
134+
}
135+
return hexToU8(decipher.deciphertext);
136+
},
96137
};
97138

98139
var justConvertHex = [

src/kernel/native-object.cc

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,9 +1237,11 @@ NATIVE_FUNCTION(LibsodiumObject, Constants) {
12371237
LOCAL_V8STRING(s_crypto_secretbox_NONCEBYTES, "crypto_secretbox_NONCEBYTES");
12381238
LOCAL_V8STRING(s_crypto_auth_BYTES, "crypto_auth_BYTES");
12391239
LOCAL_V8STRING(s_crypto_auth_KEYBYTES, "crypto_auth_KEYBYTES");
1240+
LOCAL_V8STRING(s_crypto_aead_chacha20poly1305_NPUBBYTES, "crypto_aead_chacha20poly1305_NPUBBYTES");
12401241
ret->Set(context, s_crypto_secretbox_NONCEBYTES, v8::Number::New(iv8, crypto_secretbox_NONCEBYTES));
12411242
ret->Set(context, s_crypto_auth_BYTES, v8::Number::New(iv8, crypto_auth_BYTES));
12421243
ret->Set(context, s_crypto_auth_KEYBYTES, v8::Number::New(iv8, crypto_auth_KEYBYTES));
1244+
ret->Set(context, s_crypto_aead_chacha20poly1305_NPUBBYTES, v8::Number::New(iv8, crypto_aead_chacha20poly1305_NPUBBYTES));
12431245

12441246
args.GetReturnValue().Set(ret);
12451247
}
@@ -1429,4 +1431,142 @@ NATIVE_FUNCTION(LibsodiumObject, AuthVerify) {
14291431
args.GetReturnValue().Set(v8::Boolean::New(iv8, true));
14301432
}
14311433

1434+
NATIVE_FUNCTION(LibsodiumObject, AEADChaCha20Poly135Encrypt) {
1435+
PROLOGUE;
1436+
USEARG(0);
1437+
USEARG(1);
1438+
USEARG(2);
1439+
USEARG(3);
1440+
VALIDATEARG(0, OBJECT, "crypto_aead_chacha20poly1305_encrypt: argument 0 is not an array/object.");
1441+
VALIDATEARG(1, OBJECT, "crypto_aead_chacha20poly1305_encrypt: argument 1 is not an array/object.");
1442+
VALIDATEARG(2, OBJECT, "crypto_aead_chacha20poly1305_encrypt: argument 2 is not an array/object.");
1443+
VALIDATEARG(3, OBJECT, "crypto_aead_chacha20poly1305_encrypt: argument 3 is not an array/object.");
1444+
1445+
v8::Local<v8::Object> dataArray = arg0->ToObject(context).ToLocalChecked();
1446+
unsigned char dataBytes[(int)dataArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1447+
1448+
for (int i = 0; i < (int)dataArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1449+
dataBytes[i] = (unsigned char)dataArray->Get(i)->ToNumber()->Value();
1450+
}
1451+
1452+
v8::Local<v8::Object> keyArray = arg1->ToObject(context).ToLocalChecked();
1453+
unsigned char keyBytes[(int)keyArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1454+
1455+
for (int i = 0; i < (int)keyArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1456+
keyBytes[i] = (unsigned char)keyArray->Get(i)->ToNumber()->Value();
1457+
}
1458+
1459+
v8::Local<v8::Object> nonceArray = arg2->ToObject(context).ToLocalChecked();
1460+
unsigned char nonceBytes[crypto_secretbox_NONCEBYTES];
1461+
1462+
for (int i = 0; i < (int)nonceArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1463+
nonceBytes[i] = (unsigned char)nonceArray->Get(i)->ToNumber()->Value();
1464+
}
1465+
1466+
v8::Local<v8::Object> addArray = arg3->ToObject(context).ToLocalChecked();
1467+
unsigned char addBytes[(int)addArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1468+
1469+
for (int i = 0; i < (int)addArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1470+
addBytes[i] = (unsigned char)addArray->Get(i)->ToNumber()->Value();
1471+
}
1472+
1473+
unsigned char ciphertext[crypto_aead_chacha20poly1305_ABYTES + (int)dataArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1474+
unsigned long long ciphertext_len;
1475+
1476+
crypto_aead_chacha20poly1305_encrypt(ciphertext, &ciphertext_len, dataBytes, (int)dataArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(), addBytes, (int)addArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(), NULL, nonceBytes, keyBytes);
1477+
1478+
char returnString[(sizeof(ciphertext)/sizeof(unsigned char))*2 + 1];
1479+
1480+
for (int i = 0; i < (sizeof(ciphertext)/sizeof(unsigned char)); i++) {
1481+
sprintf(&returnString[i*2], "%02X", ciphertext[i]);
1482+
}
1483+
1484+
v8::MaybeLocal<v8::String> maybe_ret = v8::String::NewFromUtf8(iv8, returnString, v8::NewStringType::kNormal);
1485+
1486+
v8::Local<v8::String> ret;
1487+
if (!maybe_ret.ToLocal(&ret)) {
1488+
args.GetReturnValue().SetUndefined();
1489+
return;
1490+
}
1491+
1492+
v8::Local<v8::Object> retObj = v8::Object::New(iv8);
1493+
retObj->Set(context, v8::String::NewFromUtf8(iv8, "ciphertext", v8::NewStringType::kNormal).ToLocalChecked(), ret);
1494+
retObj->Set(context, v8::String::NewFromUtf8(iv8, "ciphertext_len", v8::NewStringType::kNormal).ToLocalChecked(), v8::Number::New(iv8, ciphertext_len));
1495+
1496+
args.GetReturnValue().Set(retObj);
1497+
}
1498+
1499+
NATIVE_FUNCTION(LibsodiumObject, AEADChaCha20Poly135Decrypt) {
1500+
PROLOGUE;
1501+
USEARG(0);
1502+
USEARG(1);
1503+
USEARG(2);
1504+
USEARG(3);
1505+
USEARG(4);
1506+
VALIDATEARG(0, OBJECT, "crypto_aead_chacha20poly1305_decrypt: argument 0 is not an array/object.");
1507+
VALIDATEARG(1, OBJECT, "crypto_aead_chacha20poly1305_decrypt: argument 1 is not an array/object.");
1508+
VALIDATEARG(2, OBJECT, "crypto_aead_chacha20poly1305_decrypt: argument 2 is not an array/object.");
1509+
VALIDATEARG(3, OBJECT, "crypto_aead_chacha20poly1305_decrypt: argument 3 is not an array/object.");
1510+
VALIDATEARG(4, NUMBER, "crypto_aead_chacha20poly1305_decrypt: argument 4 is not a number.");
1511+
1512+
v8::Local<v8::Object> cipherArray = arg0->ToObject(context).ToLocalChecked();
1513+
unsigned char cipherBytes[(int)cipherArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1514+
1515+
for (int i = 0; i < (int)cipherArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1516+
cipherBytes[i] = (unsigned char)cipherArray->Get(i)->ToNumber()->Value();
1517+
}
1518+
1519+
v8::Local<v8::Object> keyArray = arg1->ToObject(context).ToLocalChecked();
1520+
unsigned char keyBytes[(int)keyArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1521+
1522+
for (int i = 0; i < (int)keyArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1523+
keyBytes[i] = (unsigned char)keyArray->Get(i)->ToNumber()->Value();
1524+
}
1525+
1526+
v8::Local<v8::Object> nonceArray = arg2->ToObject(context).ToLocalChecked();
1527+
unsigned char nonceBytes[crypto_secretbox_NONCEBYTES];
1528+
1529+
for (int i = 0; i < (int)nonceArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1530+
nonceBytes[i] = (unsigned char)nonceArray->Get(i)->ToNumber()->Value();
1531+
}
1532+
1533+
v8::Local<v8::Object> addArray = arg3->ToObject(context).ToLocalChecked();
1534+
unsigned char addBytes[(int)addArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value()];
1535+
1536+
for (int i = 0; i < (int)addArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(); i++) {
1537+
addBytes[i] = (unsigned char)addArray->Get(i)->ToNumber()->Value();
1538+
}
1539+
1540+
v8::Local<v8::Number> ciphertextNum = arg4->ToNumber(context).ToLocalChecked();
1541+
unsigned long long ciphertextLen = ciphertextNum->Value();
1542+
1543+
unsigned char deciphertext[ciphertextLen - crypto_aead_chacha20poly1305_ABYTES];
1544+
unsigned long long deciphertext_len;
1545+
1546+
if (crypto_aead_chacha20poly1305_decrypt(deciphertext, &deciphertext_len, NULL, cipherBytes, ciphertextLen, addBytes, (int)addArray->Get(v8::String::NewFromUtf8(iv8, "length", v8::NewStringType::kNormal).ToLocalChecked())->ToNumber()->Value(), nonceBytes, keyBytes) != 0) {
1547+
args.GetReturnValue().SetUndefined();
1548+
return;
1549+
}
1550+
1551+
char returnString[(sizeof(deciphertext)/sizeof(unsigned char))*2 + 1];
1552+
1553+
for (int i = 0; i < (sizeof(deciphertext)/sizeof(unsigned char)); i++) {
1554+
sprintf(&returnString[i*2], "%02X", deciphertext[i]);
1555+
}
1556+
1557+
v8::MaybeLocal<v8::String> maybe_ret = v8::String::NewFromUtf8(iv8, returnString, v8::NewStringType::kNormal);
1558+
1559+
v8::Local<v8::String> ret;
1560+
if (!maybe_ret.ToLocal(&ret)) {
1561+
args.GetReturnValue().SetUndefined();
1562+
return;
1563+
}
1564+
1565+
v8::Local<v8::Object> retObj = v8::Object::New(iv8);
1566+
retObj->Set(context, v8::String::NewFromUtf8(iv8, "deciphertext", v8::NewStringType::kNormal).ToLocalChecked(), ret);
1567+
retObj->Set(context, v8::String::NewFromUtf8(iv8, "deciphertext_len", v8::NewStringType::kNormal).ToLocalChecked(), v8::Number::New(iv8, deciphertext_len));
1568+
1569+
args.GetReturnValue().Set(retObj);
1570+
}
1571+
14321572
} // namespace rt

src/kernel/native-object.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ class LibsodiumObject : public JsObjectWrapper<LibsodiumObject, NativeTypeId::TY
294294
DECLARE_NATIVE(SecretboxEasyOpen);
295295
DECLARE_NATIVE(Auth);
296296
DECLARE_NATIVE(AuthVerify);
297+
DECLARE_NATIVE(AEADChaCha20Poly135Encrypt);
298+
DECLARE_NATIVE(AEADChaCha20Poly135Decrypt);
297299

298300
void ObjectInit(ExportBuilder obj) {
299301
obj.SetCallback("crypto_generichash", BlakeHash);
@@ -304,6 +306,8 @@ class LibsodiumObject : public JsObjectWrapper<LibsodiumObject, NativeTypeId::TY
304306
obj.SetCallback("crypto_secretbox_open_easy", SecretboxEasyOpen);
305307
obj.SetCallback("crypto_auth", Auth);
306308
obj.SetCallback("crypto_auth_verify", AuthVerify);
309+
obj.SetCallback("crypto_aead_chacha20poly1305_encrypt", AEADChaCha20Poly135Encrypt);
310+
obj.SetCallback("crypto_aead_chacha20poly1305_decrypt", AEADChaCha20Poly135Decrypt);
307311
}
308312

309313
JsObjectWrapperBase* Clone() const {

0 commit comments

Comments
 (0)