working PBKDF2, and AES doing something, but not tested

This commit is contained in:
Gordon Williams 2015-10-01 18:49:30 +01:00
parent 2805ce4f84
commit 26f965510a
6 changed files with 153 additions and 36 deletions

View File

@ -975,10 +975,15 @@ ifdef USE_CRYPTO
INCLUDE += -I$(ROOT)/libs/crypto/mbedtls/include
WRAPPERSOURCES += libs/crypto/jswrap_crypto.c
SOURCES += \
libs/crypto/mbedtls/library/aes.c \
libs/crypto/mbedtls/library/asn1parse.c \
libs/crypto/mbedtls/library/cipher.c \
libs/crypto/mbedtls/library/cipher_wrap.c \
libs/crypto/mbedtls/library/md.c \
libs/crypto/mbedtls/library/md_wrap.c \
libs/crypto/mbedtls/library/oid.c \
libs/crypto/mbedtls/library/pkcs5.c
libs/crypto/mbedtls/library/pkcs5.c \
libs/crypto/mbedtls/library/sha1.c
endif

View File

@ -17,6 +17,7 @@
#include "jsvariterator.h"
#include "jswrap_crypto.h"
#include "mbedtls/include/mbedtls/aes.h"
#include "mbedtls/include/mbedtls/pkcs5.h"
@ -30,19 +31,16 @@ Cryptographic functions
For other boards you will have to make build your own firmware.
*/
mbedtls_md_context_t tls_md_ctx;
bool tls_md_ctx_init = false;
mbedtls_md_context_t *jswrap_crypto_getContext() {
if (!tls_md_ctx_init) {
// FIXME
tls_md_ctx_init = true;
mbedtls_md_init( &tls_md_ctx );
void jswrap_crypto_error(int err) {
const char *e = 0;
switch(err) {
case MBEDTLS_ERR_MD_BAD_INPUT_DATA: e="Bad Input Data"; break;
case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH: e="Invalid input length"; break;
}
return &tls_md_ctx;
if (e) jsError(e);
else jsError("Unknown error: -0x%x", -err);
}
/*JSON{
"type" : "class",
"library" : "crypto",
@ -55,16 +53,16 @@ A structure containing an array of 32 bit words
/*JSON{
"type" : "staticmethod",
"library" : "crypto",
"class" : "crypto",
"name" : "PBKDF2",
"generate" : "jswrap_crypto_PBKDF2",
"params" : [
["passphrase","JsVar",""],
["passphrase","JsVar","Passphrase"],
["salt","JsVar","Salt for turning passphrase into a key"],
["options","JsVar","Object of Options, `{ keySize: 8, iterations: 10 }`"]
],
"return" : ["JsVar","Returns a WordArray structure"],
"return_object" : "WordArray"
"return" : ["JsVar","Returns an ArrayBuffer"],
"return_object" : "ArrayBuffer"
}
Password-Based Key Derivation Function 2 algorithm.
@ -74,35 +72,125 @@ JsVar *jswrap_crypto_PBKDF2(JsVar *passphrase, JsVar *salt, JsVar *options) {
int keySize = 128/32;
if (jsvIsObject(options)) {
keySize = jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "keySize", 0));
if (keySize<1) keySize=1;
if (keySize<128/32) keySize=128/32;
iterations = jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "iterations", 0));
if (iterations<1) iterations = 1;
} else if (!jsvIsUndefined(options))
jsError("Options should be an object or undefined, got %t", options);
JSV_GET_AS_CHAR_ARRAY(passPtr, passLen, passphrase);
if (!passPtr) return 0;
JSV_GET_AS_CHAR_ARRAY(saltPtr, saltLen, salt);
if (!saltPtr) return 0;
mbedtls_md_context_t *ctx = jswrap_crypto_getContext();
int err;
mbedtls_md_context_t ctx;
JsVar *keyStr = jsvNewFlatStringOfLength(keySize*4);
if (!jsvIsFlatString(keyStr)) {
jsError("Not enough memory");
jsvUnLock(keyStr);
mbedtls_md_init( &ctx );
err = mbedtls_md_setup( &ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ), 1 );
assert(err==0)
char *keyPtr = 0;
JsVar *keyArr = jsvNewArrayBufferWithPtr((unsigned)keySize*4, &keyPtr);
if (!keyPtr) {
jsError("Not enough memory for result");
return 0;
}
int err = mbedtls_pkcs5_pbkdf2_hmac( ctx, passPtr, passLen,
saltPtr, saltLen,
iterations,
keySize*4, jsvGetFlatStringPointer(keyStr) );
err = mbedtls_pkcs5_pbkdf2_hmac( &ctx,
(unsigned char*)passPtr, passLen,
(unsigned char*)saltPtr, saltLen,
(unsigned)iterations,
(unsigned)keySize*4, (unsigned char*)keyPtr );
if (!err) {
// TODO: not WordArray
return keyStr;
return keyArr;
} else {
jsError("Cryto: err %d", err);
jsvUnLock(keyStr);
jswrap_crypto_error(err);
jsvUnLock(keyArr);
return 0;
}
}
static NO_INLINE JsVar *jswrap_crypto_AES_crypt(JsVar *message, JsVar *key, bool encrypt) {
int err;
mbedtls_aes_context aes;
mbedtls_aes_init( &aes );
JSV_GET_AS_CHAR_ARRAY(messagePtr, messageLen, message);
if (!messagePtr) return 0;
JSV_GET_AS_CHAR_ARRAY(keyPtr, keyLen, key);
if (!keyPtr) return 0;
if (encrypt)
err = mbedtls_aes_setkey_enc( &aes, (unsigned char*)keyPtr, keyLen*8 );
else
err = mbedtls_aes_setkey_dec( &aes, (unsigned char*)keyPtr, keyLen*8 );
if (err) {
jswrap_crypto_error(err);
return 0;
}
char *outPtr = 0;
JsVar *outVar = jsvNewArrayBufferWithPtr(messageLen, &outPtr);
if (!outPtr) {
jsError("Not enough memory for result");
return 0;
}
unsigned char iv[16]; // initialisation vector
memset(iv, 0, 16);
err = mbedtls_aes_crypt_cbc( &aes,
encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT,
messageLen,
iv,
messagePtr,
outPtr );
mbedtls_aes_free( &aes );
if (!err) {
return outVar;
} else {
jswrap_crypto_error(err);
jsvUnLock(outVar);
return 0;
}
}
/*JSON{
"type" : "staticmethod",
"class" : "crypto",
"name" : "AES_encrypt",
"generate" : "jswrap_crypto_AES_encrypt",
"params" : [
["passphrase","JsVar","Message to encrypt"],
["key","JsVar","Key to encrypt message - must be an ArrayBuffer of 128, 192, or 256 BITS"]
],
"return" : ["JsVar","Returns an ArrayBuffer"],
"return_object" : "ArrayBuffer"
}
*/
JsVar *jswrap_crypto_AES_encrypt(JsVar *message, JsVar *key) {
return jswrap_crypto_AES_crypt(message, key, true);
}
/*JSON{
"type" : "staticmethod",
"class" : "crypto",
"name" : "AES_decrypt",
"generate" : "jswrap_crypto_AES_decrypt",
"params" : [
["passphrase","JsVar","Message to decrypt"],
["key","JsVar","Key to encrypt message - must be an ArrayBuffer of 128, 192, or 256 BITS"]
],
"return" : ["JsVar","Returns an ArrayBuffer"],
"return_object" : "ArrayBuffer"
}
*/
JsVar *jswrap_crypto_AES_decrypt(JsVar *message, JsVar *key) {
return jswrap_crypto_AES_crypt(message, key, false);
}

View File

@ -16,3 +16,6 @@
#include "jsvar.h"
JsVar *jswrap_crypto_PBKDF2(JsVar *passphrase, JsVar *salt, JsVar *options);
JsVar *jswrap_crypto_AES_encrypt(JsVar *message, JsVar *key);
JsVar *jswrap_crypto_AES_decrypt(JsVar *message, JsVar *key);

View File

@ -37,22 +37,23 @@
*/
/* mbed TLS feature support */
/*
#define MBEDTLS_CIPHER_MODE_CBC
/*
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_SSL_PROTO_TLS1_1
*/
/* mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_SHA1_C
/*
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
@ -66,7 +67,7 @@
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C

View File

@ -3068,3 +3068,18 @@ JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length) {
jsvUnLock(lenVar);
return array;
}
JsVar *jsvNewArrayBufferWithPtr(unsigned int length, char **ptr) {
assert(ptr);
*ptr=0;
JsVar *backingString = jsvNewFlatStringOfLength(length);
if (!backingString) return 0;
JsVar *arr = jsvNewArrayBufferFromString(backingString, length);
if (!arr) {
jsvUnLock(backingString);
return 0;
}
*ptr = jsvGetFlatStringPointer(backingString);
jsvUnLock(backingString);
return arr;
}

View File

@ -669,6 +669,11 @@ bool jsvReadConfigObject(JsVar *object, jsvConfigObject *configs, int nConfigs);
/// Create a new typed array of the given type and length
JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length);
/** Create a new arraybuffer of the given type and length, also return a pointer
* to the contiguous memory area containing it. Returns 0 if it was unable to
* allocate it. */
JsVar *jsvNewArrayBufferWithPtr(unsigned int length, char **ptr);
/** Get the given JsVar as a character array. If it's a flat string, return a
* pointer to it, or if it isn't allocate data on the stack and copy the data.
*
@ -676,7 +681,7 @@ JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length);
* the data will be lost when we return. */
#define JSV_GET_AS_CHAR_ARRAY(TARGET_PTR, TARGET_LENGTH, DATA) \
size_t TARGET_LENGTH = 0; \
unsigned char *TARGET_PTR = 0; \
char *TARGET_PTR = 0; \
if (jsvIsFlatString(DATA)) { \
TARGET_LENGTH = jsvGetStringLength(DATA); \
TARGET_PTR = jsvGetFlatStringPointer(DATA); \
@ -685,8 +690,8 @@ JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length);
if (TARGET_LENGTH+256 > jsuGetFreeStack()) { \
jsExceptionHere(JSET_ERROR, "Not enough stack memory to decode data"); \
} else { \
unsigned char *TARGET_PTR = (unsigned char *)alloca(TARGET_LENGTH); \
jsvIterateCallbackToBytes(DATA, TARGET_PTR, (unsigned int)TARGET_LENGTH); \
TARGET_PTR = (char *)alloca(TARGET_LENGTH); \
jsvIterateCallbackToBytes(DATA, (unsigned char *)TARGET_PTR, (unsigned int)TARGET_LENGTH); \
} \
}