diff --git a/hacl-star-snapshot/primitives-js/Primitives.ml b/hacl-star-snapshot/primitives-js/Primitives.ml index 26229bd..fa91c50 100644 --- a/hacl-star-snapshot/primitives-js/Primitives.ml +++ b/hacl-star-snapshot/primitives-js/Primitives.ml @@ -82,11 +82,32 @@ let chacha20_poly1305_decrypt ~key ~iv ~ad ~ct ~tag = | Some pt -> Some (H.bytes_of_uint8array pt) | None -> None +external whacl_aes128gcm_encrypt: + js_u8array -> js_u8array -> js_u8array -> js_u8array -> js_u8array Js.js_array Js.t += "whacl_aes128gcm_encrypt" let aes128gcm_encrypt ~key ~iv ~ad ~pt = - ignore (key, iv, ad, pt); - failwith "Not implemented in JS: aes128gcm_encrypt" + let key = H.uint8array_of_bytes key in + let iv = H.uint8array_of_bytes iv in + let ad = H.uint8array_of_bytes ad in + let pt = H.uint8array_of_bytes pt in + let ret = whacl_aes128gcm_encrypt key iv ad pt in + let ret = Js.to_array ret in + let ct = H.bytes_of_uint8array ret.(0) in + let tag = H.bytes_of_uint8array ret.(1) in + FStar_Seq_Base.append ct tag + +external whacl_aes128gcm_decrypt: + js_u8array -> js_u8array -> js_u8array -> js_u8array -> js_u8array -> js_u8array Js.Opt.t += "whacl_aes128gcm_decrypt" let aes128gcm_decrypt ~key ~iv ~ad ~ct ~tag = - ignore (key, iv, ad, ct, tag); - failwith "Not implemented in JS: aes128gcm_decrypt" + let key = H.uint8array_of_bytes key in + let iv = H.uint8array_of_bytes iv in + let ad = H.uint8array_of_bytes ad in + let ct = H.uint8array_of_bytes ct in + let tag = H.uint8array_of_bytes tag in + match Js.Opt.to_option (whacl_aes128gcm_decrypt key iv ad ct tag) with + | Some pt -> Some (H.bytes_of_uint8array pt) + | None -> None + diff --git a/hacl-star-snapshot/primitives-js/dummy.c b/hacl-star-snapshot/primitives-js/dummy.c index 4327b01..a96bf58 100644 --- a/hacl-star-snapshot/primitives-js/dummy.c +++ b/hacl-star-snapshot/primitives-js/dummy.c @@ -37,3 +37,11 @@ CAMLprim value whacl_chacha20_poly1305_encrypt() { CAMLprim value whacl_chacha20_poly1305_decrypt() { caml_failwith(error_msg); } + +CAMLprim value whacl_aes128gcm_encrypt() { + caml_failwith(error_msg); +} + +CAMLprim value whacl_aes128gcm_decrypt() { + caml_failwith(error_msg); +} diff --git a/js/MLS_JS.ml b/js/MLS_JS.ml index 5ba8d1c..25c0f76 100644 --- a/js/MLS_JS.ml +++ b/js/MLS_JS.ml @@ -125,12 +125,18 @@ let _ = (* Expects a JS string that contains the expected ciphersuite *) method setCiphersuite (cs: _ Js.t) = - match Js.to_string cs with - | _ -> - (* TODO: actually offer more ciphersuites *) - if !crypto_bytes_ <> None then - print_and_fail "Cannot dynamically change ciphersuites"; - crypto_bytes_ := Some MLS_Crypto_Builtins.(mk_concrete_crypto_bytes AC_mls_128_dhkemx25519_chacha20poly1305_sha256_ed25519) + let cs = Js.to_string cs in + if !crypto_bytes_ <> None then + print_and_fail "Cannot dynamically change ciphersuites"; + let ac = match cs with + | "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519" -> + MLS_Crypto_Builtins.AC_mls_128_dhkemx25519_aes128gcm_sha256_ed25519 + | "MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519" -> + AC_mls_128_dhkemx25519_chacha20poly1305_sha256_ed25519 + | _ -> + print_and_fail ("Unsupported ciphersuite: " ^ cs) + in + crypto_bytes_ := Some MLS_Crypto_Builtins.(mk_concrete_crypto_bytes ac) (* NEW API: binders for MLS.API.fst (via MLS_API.ml) *) diff --git a/js/index.js b/js/index.js index 21df5d0..45e78c7 100644 --- a/js/index.js +++ b/js/index.js @@ -158,8 +158,31 @@ function HaclCrypto(Hacl) { return plain; else return null; + }, + + // AES128-GCM implementation relying on OpenSSL via node-crypto to get the + // benefits of hardware acceleration with AESNI + aes128gcm_encrypt: (key, iv, ad, pt) => { + let cipher = node_crypto.createCipheriv("id-aes128-GCM", key, iv, { authTagLength: 16 }); + cipher.setAAD(ad); + let ct = cipher.update(pt); + cipher.final(); + return [ new Uint8Array(ct.buffer), new Uint8Array(cipher.getAuthTag().buffer) ]; + }, + + aes128gcm_decrypt: (key, iv, ad, ct, tag) => { + let decipher = node_crypto.createDecipheriv("id-aes128-GCM", key, iv, { authTagLength: 16 }); + decipher.setAAD(ad); + let pt = decipher.update(ct); + decipher.setAuthTag(tag); + try { + decipher.final(); + return pt; + } catch (e) { + return null; + } } - }; + } } if (typeof module !== undefined) diff --git a/js/overrides.js b/js/overrides.js index 103be3e..6822ede 100644 --- a/js/overrides.js +++ b/js/overrides.js @@ -47,6 +47,16 @@ function whacl_chacha20_poly1305_decrypt(key, iv, ad, ct, tag) { return joo_global_object.MyCrypto.chacha20_poly1305_decrypt(key, iv, ad, ct, tag); } +//Provides:whacl_aes128gcm_encrypt +function whacl_aes128gcm_encrypt(key, iv, ad, pt) { + return joo_global_object.MyCrypto.aes128gcm_encrypt(key, iv, ad, pt); +} + +//Provides:whacl_aes128gcm_decrypt +function whacl_aes128gcm_decrypt(key, iv, ad, ct, tag) { + return joo_global_object.MyCrypto.aes128gcm_decrypt(key, iv, ad, ct, tag); +} + // OCaml system stuff //Provides: caml_thread_initialize const diff --git a/js/test.js b/js/test.js index ac52bb6..3d8a4d6 100644 --- a/js/test.js +++ b/js/test.js @@ -87,8 +87,10 @@ var test_main = () => { var test_new = () => { // A test for the new, more general API. We start with some warm-up. - // This is the only supported one for now, we plan to expose AES-GCM soo. - MLS.setCiphersuite("mls_128_dhkemx25519_chacha20poly1305_sha256_ed25519"); + // Pick either one. + // MLS.setCiphersuite("MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519"); + MLS.setCiphersuite("MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519"); + // The source of entropy is customizable. MLS.setEntropy((n) => crypto.getRandomValues(new Uint8Array(n)));