cas-typescript-sdk 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/Cargo.toml +5 -0
  2. package/README.md +2 -0
  3. package/index.d.ts +26 -0
  4. package/index.node +0 -0
  5. package/lib/asymmetric/RSAWrapper.d.ts +8 -0
  6. package/lib/asymmetric/RSAWrapper.js +52 -0
  7. package/lib/asymmetric/index.d.ts +3 -0
  8. package/lib/asymmetric/index.js +7 -0
  9. package/lib/index.d.ts +4 -1
  10. package/lib/index.js +8 -1
  11. package/lib/key_exchange/index.d.ts +2 -0
  12. package/lib/key_exchange/index.js +5 -0
  13. package/lib/key_exchange/x25519.d.ts +5 -0
  14. package/lib/key_exchange/x25519.js +13 -0
  15. package/lib/symmetric/aes-wrapper.d.ts +9 -0
  16. package/lib/symmetric/aes-wrapper.js +28 -0
  17. package/lib/symmetric/index.d.ts +2 -0
  18. package/lib/symmetric/index.js +5 -0
  19. package/package.json +1 -1
  20. package/src/asymmetric/cas_asymmetric_encryption.rs +15 -0
  21. package/src/asymmetric/cas_rsa.rs +80 -0
  22. package/src/hashers/blake2.rs +39 -0
  23. package/src/key_exchange/cas_key_exchange.rs +6 -0
  24. package/src/key_exchange/x25519.rs +57 -0
  25. package/src/lib.rs +16 -0
  26. package/src/symmetric/aes.rs +116 -0
  27. package/src/symmetric/cas_symmetric_encryption.rs +5 -0
  28. package/src-ts/asymmetric/RSAWrapper.ts +53 -0
  29. package/src-ts/asymmetric/index.ts +4 -0
  30. package/src-ts/index.ts +10 -3
  31. package/src-ts/key_exchange/index.ts +3 -0
  32. package/src-ts/key_exchange/x25519.ts +11 -0
  33. package/src-ts/symmetric/aes-wrapper.ts +39 -0
  34. package/src-ts/symmetric/index.ts +3 -0
  35. package/test-ts/asymmetric.test.spec.ts +28 -0
  36. package/test-ts/helpers/array.ts +10 -0
  37. package/test-ts/key-exchange-test.spec.ts +23 -0
  38. package/test-ts/symmetric.test.spec.ts +31 -0
package/Cargo.toml CHANGED
@@ -8,13 +8,18 @@ path = "src/lib.rs"
8
8
  crate-type = ["cdylib"]
9
9
 
10
10
  [dependencies]
11
+ aes-gcm = "0.10.3"
11
12
  argon2 = "0.5.2"
12
13
  bcrypt = "0.15.0"
14
+ blake2 = "0.10.6"
13
15
  napi = "2"
14
16
  napi-derive = "2"
15
17
  rand = "0.8.5"
18
+ rand_chacha = "0.3.1"
19
+ rsa = "0.9.6"
16
20
  scrypt = "0.11.0"
17
21
  sha3 = "0.10.8"
22
+ x25519-dalek = {version = "2.0.0", features = ["static_secrets"] }
18
23
 
19
24
  [build-dependencies]
20
25
  napi-build = "1"
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # eas-typescript-sdk
2
2
 
3
+ Ever wanted all of your most useful cryptograpihc operations in one module and not have to surf documentation for various packages?
4
+ CAS is here to provide a unified development experience as an abstract layer to the RustCrypto and Dalek-Cryptography suite of algorithms.
3
5
  The official NPM page can be found [here](https://www.npmjs.com/package/cas-typescript-sdk).
4
6
 
5
7
  ## Consuming Library Documentation
package/index.d.ts CHANGED
@@ -13,3 +13,29 @@ export function sha512(dataToHash: Array<number>): Array<number>
13
13
  export function sha512Verify(dataToHash: Array<number>, dataToVerify: Array<number>): boolean
14
14
  export function sha256(dataToHash: Array<number>): Array<number>
15
15
  export function sha256Verify(dataToHash: Array<number>, dataToVerify: Array<number>): boolean
16
+ export function x25519GenerateSecretAndPublicKey(): X25519SecretPublicKeyResult
17
+ export function x25519DiffieHellman(mySecretKey: Array<number>, usersPublicKey: Array<number>): Array<number>
18
+ export function aesNonce(): Array<number>
19
+ export function aes128Key(): Array<number>
20
+ export function aes256Key(): Array<number>
21
+ export function aes128Encrypt(aesKey: Array<number>, nonce: Array<number>, plaintext: Array<number>): Array<number>
22
+ export function aes128Decrypt(aesKey: Array<number>, nonce: Array<number>, ciphertext: Array<number>): Array<number>
23
+ export function aes256Encrypt(aesKey: Array<number>, nonce: Array<number>, plaintext: Array<number>): Array<number>
24
+ export function aes256Decrypt(aesKey: Array<number>, nonce: Array<number>, ciphertext: Array<number>): Array<number>
25
+ export function generateRsaKeys(keySize: number): RsaKeyPairResult
26
+ export function encryptPlaintextRsa(publicKey: string, plaintext: Array<number>): Array<number>
27
+ export function decryptCiphertextRsa(privateKey: string, ciphertext: Array<number>): Array<number>
28
+ export function signRsa(privateKey: string, hash: Array<number>): Array<number>
29
+ export function verifyRsa(publicKey: string, hash: Array<number>, signature: Array<number>): boolean
30
+ export type x25519SecretPublicKeyResult = X25519SecretPublicKeyResult
31
+ export class X25519SecretPublicKeyResult {
32
+ publicKey: Array<number>
33
+ secretKey: Array<number>
34
+ constructor(publicKey: Array<number>, secretKey: Array<number>)
35
+ }
36
+ export type RSAKeyPairResult = RsaKeyPairResult
37
+ export class RsaKeyPairResult {
38
+ privateKey: string
39
+ publicKey: string
40
+ constructor(privateKey: string, publicKey: string)
41
+ }
package/index.node CHANGED
Binary file
@@ -0,0 +1,8 @@
1
+ import { RsaKeyPairResult } from "../../index";
2
+ export declare class RSAWrapper {
3
+ generateKeys(keySize: number): RsaKeyPairResult;
4
+ encrypt(publicKey: string, plaintext: Array<number>): Array<number>;
5
+ decrypt(privateKey: string, ciphertext: Array<number>): Array<number>;
6
+ sign(privateKey: string, hash: Array<number>): Array<number>;
7
+ verify(publicKey: string, hash: Array<number>, signature: Array<number>): boolean;
8
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RSAWrapper = void 0;
4
+ const index_1 = require("../../index");
5
+ class RSAWrapper {
6
+ generateKeys(keySize) {
7
+ if (keySize !== 1024 && keySize !== 2048 && keySize !== 4096) {
8
+ throw new Error("You must provide an appropriate key size to generate RSA keys");
9
+ }
10
+ return (0, index_1.generateRsaKeys)(keySize);
11
+ }
12
+ encrypt(publicKey, plaintext) {
13
+ if (!publicKey) {
14
+ throw new Error("You must provide a public key to encrypt with RSA");
15
+ }
16
+ if (!plaintext || plaintext.length === 0) {
17
+ throw new Error("You must provide an array of plaintext bytes to encrypt with RSA");
18
+ }
19
+ return (0, index_1.encryptPlaintextRsa)(publicKey, plaintext);
20
+ }
21
+ decrypt(privateKey, ciphertext) {
22
+ if (!privateKey) {
23
+ throw new Error("You must provide a private key to encrypt with RSA");
24
+ }
25
+ if (!ciphertext || ciphertext.length === 0) {
26
+ throw new Error("You must provide an array of ciphertext bytes to encrypt with RSA");
27
+ }
28
+ return (0, index_1.decryptCiphertextRsa)(privateKey, ciphertext);
29
+ }
30
+ sign(privateKey, hash) {
31
+ if (!privateKey) {
32
+ throw new Error("You must provide a private key to sign with RSA");
33
+ }
34
+ if (!hash || hash.length === 0) {
35
+ throw new Error("You must provide an allocated hash to sign with RSA");
36
+ }
37
+ return (0, index_1.signRsa)(privateKey, hash);
38
+ }
39
+ verify(publicKey, hash, signature) {
40
+ if (!publicKey) {
41
+ throw new Error("You must provide a public key to verify with RSA");
42
+ }
43
+ if (!hash || hash.length === 0) {
44
+ throw new Error("You must provide an allocated hash to verify with RSA");
45
+ }
46
+ if (!signature || signature.length === 0) {
47
+ throw new Error("You must provide and allocated signature to verify with RSA");
48
+ }
49
+ return (0, index_1.verifyRsa)(publicKey, hash, signature);
50
+ }
51
+ }
52
+ exports.RSAWrapper = RSAWrapper;
@@ -0,0 +1,3 @@
1
+ import { RSAWrapper } from "./RSAWrapper";
2
+ import { RsaKeyPairResult } from "../../index";
3
+ export { RSAWrapper, RsaKeyPairResult };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RsaKeyPairResult = exports.RSAWrapper = void 0;
4
+ const RSAWrapper_1 = require("./RSAWrapper");
5
+ Object.defineProperty(exports, "RSAWrapper", { enumerable: true, get: function () { return RSAWrapper_1.RSAWrapper; } });
6
+ const index_1 = require("../../index");
7
+ Object.defineProperty(exports, "RsaKeyPairResult", { enumerable: true, get: function () { return index_1.RsaKeyPairResult; } });
package/lib/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  import { Argon2Wrapper, BCryptWrapper, PasswordHasherFactory, PasswordHasherType, ScryptWrapper } from "./password-hashers/index";
2
2
  import { HasherFactory, HasherType, SHAWrapper } from "./hashers/index";
3
- export { Argon2Wrapper, BCryptWrapper, ScryptWrapper, PasswordHasherFactory, PasswordHasherType, HasherFactory, HasherType, SHAWrapper, };
3
+ import { X25519Wrapper } from "./key_exchange/index";
4
+ import { AESWrapper } from "./symmetric/index";
5
+ import { RSAWrapper, RsaKeyPairResult } from "./asymmetric";
6
+ export { Argon2Wrapper, BCryptWrapper, HasherFactory, HasherType, PasswordHasherFactory, PasswordHasherType, ScryptWrapper, SHAWrapper, X25519Wrapper, AESWrapper, RSAWrapper, RsaKeyPairResult };
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SHAWrapper = exports.HasherType = exports.HasherFactory = exports.PasswordHasherType = exports.PasswordHasherFactory = exports.ScryptWrapper = exports.BCryptWrapper = exports.Argon2Wrapper = void 0;
3
+ exports.RsaKeyPairResult = exports.RSAWrapper = exports.AESWrapper = exports.X25519Wrapper = exports.SHAWrapper = exports.ScryptWrapper = exports.PasswordHasherType = exports.PasswordHasherFactory = exports.HasherType = exports.HasherFactory = exports.BCryptWrapper = exports.Argon2Wrapper = void 0;
4
4
  const index_1 = require("./password-hashers/index");
5
5
  Object.defineProperty(exports, "Argon2Wrapper", { enumerable: true, get: function () { return index_1.Argon2Wrapper; } });
6
6
  Object.defineProperty(exports, "BCryptWrapper", { enumerable: true, get: function () { return index_1.BCryptWrapper; } });
@@ -11,3 +11,10 @@ const index_2 = require("./hashers/index");
11
11
  Object.defineProperty(exports, "HasherFactory", { enumerable: true, get: function () { return index_2.HasherFactory; } });
12
12
  Object.defineProperty(exports, "HasherType", { enumerable: true, get: function () { return index_2.HasherType; } });
13
13
  Object.defineProperty(exports, "SHAWrapper", { enumerable: true, get: function () { return index_2.SHAWrapper; } });
14
+ const index_3 = require("./key_exchange/index");
15
+ Object.defineProperty(exports, "X25519Wrapper", { enumerable: true, get: function () { return index_3.X25519Wrapper; } });
16
+ const index_4 = require("./symmetric/index");
17
+ Object.defineProperty(exports, "AESWrapper", { enumerable: true, get: function () { return index_4.AESWrapper; } });
18
+ const asymmetric_1 = require("./asymmetric");
19
+ Object.defineProperty(exports, "RSAWrapper", { enumerable: true, get: function () { return asymmetric_1.RSAWrapper; } });
20
+ Object.defineProperty(exports, "RsaKeyPairResult", { enumerable: true, get: function () { return asymmetric_1.RsaKeyPairResult; } });
@@ -0,0 +1,2 @@
1
+ import { X25519Wrapper } from "./x25519";
2
+ export { X25519Wrapper };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.X25519Wrapper = void 0;
4
+ const x25519_1 = require("./x25519");
5
+ Object.defineProperty(exports, "X25519Wrapper", { enumerable: true, get: function () { return x25519_1.X25519Wrapper; } });
@@ -0,0 +1,5 @@
1
+ import { X25519SecretPublicKeyResult } from "../../index";
2
+ export declare class X25519Wrapper {
3
+ generateSecretAndPublicKey(): X25519SecretPublicKeyResult;
4
+ diffieHellman(secretKey: Array<number>, publicKey: Array<number>): number[];
5
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.X25519Wrapper = void 0;
4
+ const index_1 = require("../../index");
5
+ class X25519Wrapper {
6
+ generateSecretAndPublicKey() {
7
+ return (0, index_1.x25519GenerateSecretAndPublicKey)();
8
+ }
9
+ diffieHellman(secretKey, publicKey) {
10
+ return (0, index_1.x25519DiffieHellman)(secretKey, publicKey);
11
+ }
12
+ }
13
+ exports.X25519Wrapper = X25519Wrapper;
@@ -0,0 +1,9 @@
1
+ export declare class AESWrapper {
2
+ aes128Key(): Array<number>;
3
+ aes256Key(): Array<number>;
4
+ aesNonce(): Array<number>;
5
+ aes128Encrypt(aesKey: Array<number>, nonce: Array<number>, plaintext: Array<number>): Array<number>;
6
+ aes128Decrypt(aesKey: Array<number>, nonce: Array<number>, ciphertext: Array<number>): Array<number>;
7
+ aes256Encrypt(aesKey: Array<number>, nonce: Array<number>, plaintext: Array<number>): Array<number>;
8
+ aes256Decrypt(aesKey: Array<number>, nonce: Array<number>, ciphertext: Array<number>): Array<number>;
9
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AESWrapper = void 0;
4
+ const index_1 = require("../../index");
5
+ class AESWrapper {
6
+ aes128Key() {
7
+ return (0, index_1.aes128Key)();
8
+ }
9
+ aes256Key() {
10
+ return (0, index_1.aes256Key)();
11
+ }
12
+ aesNonce() {
13
+ return (0, index_1.aesNonce)();
14
+ }
15
+ aes128Encrypt(aesKey, nonce, plaintext) {
16
+ return (0, index_1.aes128Encrypt)(aesKey, nonce, plaintext);
17
+ }
18
+ aes128Decrypt(aesKey, nonce, ciphertext) {
19
+ return (0, index_1.aes128Decrypt)(aesKey, nonce, ciphertext);
20
+ }
21
+ aes256Encrypt(aesKey, nonce, plaintext) {
22
+ return (0, index_1.aes256Encrypt)(aesKey, nonce, plaintext);
23
+ }
24
+ aes256Decrypt(aesKey, nonce, ciphertext) {
25
+ return (0, index_1.aes256Decrypt)(aesKey, nonce, ciphertext);
26
+ }
27
+ }
28
+ exports.AESWrapper = AESWrapper;
@@ -0,0 +1,2 @@
1
+ import { AESWrapper } from "./aes-wrapper";
2
+ export { AESWrapper };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AESWrapper = void 0;
4
+ const aes_wrapper_1 = require("./aes-wrapper");
5
+ Object.defineProperty(exports, "AESWrapper", { enumerable: true, get: function () { return aes_wrapper_1.AESWrapper; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cas-typescript-sdk",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -0,0 +1,15 @@
1
+ use napi_derive::napi;
2
+
3
+ #[napi(constructor)]
4
+ pub struct RSAKeyPairResult {
5
+ pub private_key: String,
6
+ pub public_key: String
7
+ }
8
+
9
+ pub trait CASRSAEncryption {
10
+ fn generate_rsa_keys(key_size: u32) -> RSAKeyPairResult;
11
+ fn encrypt_plaintext(public_key: String, plaintext: Vec<u8>) -> Vec<u8>;
12
+ fn decrypt_ciphertext(private_key: String, ciphertext: Vec<u8>) -> Vec<u8>;
13
+ fn sign(private_key: String, hash: Vec<u8>) -> Vec<u8>;
14
+ fn verify(public_key: String, hash: Vec<u8>, signed_text: Vec<u8>) -> bool;
15
+ }
@@ -0,0 +1,80 @@
1
+ use napi_derive::napi;
2
+ use rand::rngs::OsRng;
3
+ use rsa::{
4
+ pkcs1::{DecodeRsaPublicKey, EncodeRsaPublicKey}, pkcs8::{DecodePrivateKey, EncodePrivateKey}, Pkcs1v15Encrypt, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey
5
+ };
6
+
7
+ use super::cas_asymmetric_encryption::{CASRSAEncryption, RSAKeyPairResult};
8
+ pub struct CASRSA;
9
+
10
+ impl CASRSAEncryption for CASRSA {
11
+ fn generate_rsa_keys(key_size: u32) -> RSAKeyPairResult {
12
+ let mut rng: OsRng = OsRng;
13
+ let private_key: RsaPrivateKey = RsaPrivateKey::new(&mut rng, key_size as usize).expect("failed to generate a key");
14
+ let public_key: RsaPublicKey = private_key.to_public_key();
15
+ let result = RSAKeyPairResult {
16
+ public_key: public_key.to_pkcs1_pem(rsa::pkcs1::LineEnding::LF).unwrap().to_string(),
17
+ private_key: private_key.to_pkcs8_pem(rsa::pkcs8::LineEnding::LF).unwrap().to_string()
18
+ };
19
+ result
20
+ }
21
+
22
+ fn encrypt_plaintext(public_key: String, plaintext: Vec<u8>) -> Vec<u8> {
23
+ let public_key = RsaPublicKey::from_pkcs1_pem(&public_key).unwrap();
24
+ let mut rng = rand::thread_rng();
25
+ let ciphertext = public_key.encrypt(&mut rng, Pkcs1v15Encrypt, &plaintext).unwrap();
26
+ ciphertext
27
+ }
28
+
29
+ fn decrypt_ciphertext(private_key: String, ciphertext: Vec<u8>) -> Vec<u8> {
30
+ let private_key = RsaPrivateKey::from_pkcs8_pem(&private_key).unwrap();
31
+ let plaintext = private_key.decrypt(Pkcs1v15Encrypt, &ciphertext).unwrap();
32
+ plaintext
33
+ }
34
+
35
+ fn sign(private_key: String, hash: Vec<u8>) -> Vec<u8> {
36
+ let private_key = RsaPrivateKey::from_pkcs8_pem(&private_key).unwrap();
37
+ let mut signed_data = private_key.sign(Pkcs1v15Sign::new_unprefixed(), &hash).unwrap();
38
+ signed_data
39
+ }
40
+
41
+ fn verify(public_key: String, hash: Vec<u8>, signature: Vec<u8>) -> bool {
42
+ let public_key = RsaPublicKey::from_pkcs1_pem(&public_key).unwrap();
43
+ let verified = public_key.verify(
44
+ Pkcs1v15Sign::new_unprefixed(),
45
+ &hash,
46
+ &signature,
47
+ );
48
+ if verified.is_err() == false {
49
+ return true;
50
+ } else {
51
+ return false;
52
+ }
53
+ }
54
+ }
55
+
56
+
57
+ #[napi]
58
+ pub fn generate_rsa_keys(key_size: u32) -> RSAKeyPairResult {
59
+ return CASRSA::generate_rsa_keys(key_size);
60
+ }
61
+
62
+ #[napi]
63
+ pub fn encrypt_plaintext_rsa(public_key: String, plaintext: Vec<u8>) -> Vec<u8> {
64
+ return CASRSA::encrypt_plaintext(public_key, plaintext);
65
+ }
66
+
67
+ #[napi]
68
+ pub fn decrypt_ciphertext_rsa(private_key: String, ciphertext: Vec<u8>) -> Vec<u8> {
69
+ return CASRSA::decrypt_ciphertext(private_key, ciphertext);
70
+ }
71
+
72
+ #[napi]
73
+ pub fn sign_rsa(private_key: String, hash: Vec<u8>) -> Vec<u8> {
74
+ return CASRSA::sign(private_key, hash);
75
+ }
76
+
77
+ #[napi]
78
+ pub fn verify_rsa(public_key: String, hash: Vec<u8>, signature: Vec<u8>) -> bool {
79
+ return CASRSA::verify(public_key, hash, signature);
80
+ }
@@ -0,0 +1,39 @@
1
+ use blake2::{Blake2b512, Blake2s256, Digest};
2
+ use super::cas_hasher::CASHasher;
3
+
4
+ pub struct CASBlake2;
5
+
6
+ impl CASHasher for CASBlake2 {
7
+ fn hash_512(data_to_hash: Vec<u8>) -> Vec<u8> {
8
+ let mut hasher = Blake2b512::new();
9
+ hasher.update(data_to_hash);
10
+ let result = hasher.finalize();
11
+ return result.to_vec();
12
+ }
13
+
14
+ fn verify_512(hash_to_verify: Vec<u8>, data_to_verify: Vec<u8>) -> bool {
15
+ let mut hasher = Blake2b512::new();
16
+ hasher.update(data_to_verify);
17
+ let result = hasher.finalize();
18
+ return hash_to_verify.eq(&result.to_vec());
19
+ }
20
+
21
+ fn hash_256(data_to_hash: Vec<u8>) -> Vec<u8> {
22
+ let mut hasher = Blake2s256::new();
23
+ hasher.update(data_to_hash);
24
+ let result = hasher.finalize();
25
+ return result.to_vec();
26
+ }
27
+
28
+ fn verify_256(hash_to_verify: Vec<u8>, data_to_verify: Vec<u8>) -> bool {
29
+ let mut hasher = Blake2s256::new();
30
+ hasher.update(data_to_verify);
31
+ let result = hasher.finalize();
32
+ return hash_to_verify.eq(&result.to_vec());
33
+ }
34
+ }
35
+
36
+ #[test]
37
+ fn hash_512_test() {
38
+
39
+ }
@@ -0,0 +1,6 @@
1
+ use super::x25519::x25519SecretPublicKeyResult;
2
+
3
+ pub trait CASKeyExchange {
4
+ fn generate_secret_and_public_key() -> x25519SecretPublicKeyResult;
5
+ fn diffie_hellman(my_secret_key: Vec<u8>, users_public_key: Vec<u8>) -> Vec<u8>;
6
+ }
@@ -0,0 +1,57 @@
1
+ use napi::bindgen_prelude::ClassInstance;
2
+ use napi_derive::napi;
3
+ use rand::rngs::OsRng;
4
+ use x25519_dalek::{PublicKey, StaticSecret};
5
+
6
+ use super::cas_key_exchange::CASKeyExchange;
7
+
8
+ #[napi(constructor)]
9
+ pub struct x25519SecretPublicKeyResult {
10
+ pub public_key: Vec<u8>,
11
+ pub secret_key: Vec<u8>
12
+ }
13
+
14
+ pub struct X25519;
15
+
16
+ impl CASKeyExchange for X25519 {
17
+ fn generate_secret_and_public_key() -> x25519SecretPublicKeyResult {
18
+ let secret_key = StaticSecret::random_from_rng(OsRng);
19
+ let public_key = PublicKey::from(&secret_key);
20
+ let result = x25519SecretPublicKeyResult {
21
+ secret_key: secret_key.as_bytes().to_vec(),
22
+ public_key: public_key.as_bytes().to_vec()
23
+ };
24
+ result
25
+ }
26
+
27
+ fn diffie_hellman(my_secret_key: Vec<u8>, users_public_key: Vec<u8>) -> Vec<u8> {
28
+ let mut secret_key_array: [u8; 32] = Default::default();
29
+ secret_key_array.copy_from_slice(&my_secret_key);
30
+ let mut users_public_key_array: [u8; 32] = Default::default();
31
+ users_public_key_array.copy_from_slice(&users_public_key);
32
+
33
+ let secret_key = StaticSecret::from(secret_key_array);
34
+ let public_key = PublicKey::from(users_public_key_array);
35
+ return secret_key.diffie_hellman(&public_key).as_bytes().to_vec();
36
+ }
37
+ }
38
+
39
+ #[napi]
40
+ pub fn x25519_generate_secret_and_public_key() -> x25519SecretPublicKeyResult {
41
+ return <X25519 as CASKeyExchange>::generate_secret_and_public_key();
42
+ }
43
+
44
+ #[napi]
45
+ pub fn x25519_diffie_hellman(my_secret_key: Vec<u8>, users_public_key: Vec<u8>) -> Vec<u8> {
46
+ return <X25519 as CASKeyExchange>::diffie_hellman(my_secret_key, users_public_key);
47
+ }
48
+
49
+ #[test]
50
+ pub fn x25519_diffie_hellman_test() {
51
+ let alice = x25519_generate_secret_and_public_key();
52
+ let bob = x25519_generate_secret_and_public_key();
53
+
54
+ let alice_shared_secret = x25519_diffie_hellman(alice.secret_key, bob.public_key);
55
+ let bob_shared_secret = x25519_diffie_hellman(bob.secret_key, alice.public_key);
56
+ assert_eq!(true, alice_shared_secret.eq(&bob_shared_secret));
57
+ }
package/src/lib.rs CHANGED
@@ -8,4 +8,20 @@ mod password_hashers {
8
8
  mod hashers {
9
9
  pub mod sha;
10
10
  pub mod cas_hasher;
11
+ pub mod blake2;
12
+ }
13
+
14
+ mod key_exchange {
15
+ pub mod x25519;
16
+ pub mod cas_key_exchange;
17
+ }
18
+
19
+ mod symmetric {
20
+ pub mod aes;
21
+ pub mod cas_symmetric_encryption;
22
+ }
23
+
24
+ mod asymmetric {
25
+ pub mod cas_asymmetric_encryption;
26
+ pub mod cas_rsa;
11
27
  }
@@ -0,0 +1,116 @@
1
+ use napi_derive::napi;
2
+ use rand::rngs::OsRng;
3
+ use rand::{RngCore, SeedableRng};
4
+ use rand_chacha::ChaCha20Rng;
5
+
6
+ use aes_gcm::{
7
+ aead::{generic_array::GenericArray, Aead},
8
+ Aes256Gcm, Aes128Gcm, KeyInit, Nonce
9
+ };
10
+
11
+ use super::cas_symmetric_encryption::CASAESEncryption;
12
+ pub struct CASAES128;
13
+ pub struct CASAES256;
14
+
15
+ impl CASAESEncryption for CASAES256 {
16
+ fn generate_key() -> Vec<u8> {
17
+ return Aes256Gcm::generate_key(&mut OsRng).to_vec();
18
+ }
19
+
20
+ fn encrypt_plaintext(aes_key: Vec<u8>, nonce: Vec<u8>, plaintext: Vec<u8>) -> Vec<u8> {
21
+ let key = GenericArray::from_slice(&aes_key);
22
+ let mut cipher = Aes256Gcm::new(&key);
23
+ let nonce = Nonce::from_slice(&nonce);
24
+ let ciphertext = cipher.encrypt(nonce, plaintext.as_ref()).unwrap();
25
+ ciphertext
26
+ }
27
+
28
+ fn decrypt_ciphertext(aes_key: Vec<u8>, nonce: Vec<u8>, ciphertext: Vec<u8>) -> Vec<u8> {
29
+ let key = GenericArray::from_slice(&aes_key);
30
+ let mut cipher = Aes256Gcm::new(&key);
31
+ let nonce = Nonce::from_slice(&nonce);
32
+ let plaintext = cipher.decrypt(nonce, ciphertext.as_ref()).unwrap();
33
+ plaintext
34
+ }
35
+ }
36
+
37
+ impl CASAESEncryption for CASAES128 {
38
+ fn generate_key() -> Vec<u8> {
39
+ return Aes128Gcm::generate_key(&mut OsRng).to_vec();
40
+ }
41
+
42
+ fn encrypt_plaintext(aes_key: Vec<u8>, nonce: Vec<u8>, plaintext: Vec<u8>) -> Vec<u8> {
43
+ let key = GenericArray::from_slice(&aes_key);
44
+ let mut cipher = Aes128Gcm::new(&key);
45
+ let nonce = Nonce::from_slice(&nonce);
46
+ let ciphertext = cipher.encrypt(nonce, plaintext.as_ref()).unwrap();
47
+ ciphertext
48
+ }
49
+
50
+ fn decrypt_ciphertext(aes_key: Vec<u8>, nonce: Vec<u8>, ciphertext: Vec<u8>) -> Vec<u8> {
51
+ let key = GenericArray::from_slice(&aes_key);
52
+ let mut cipher = Aes128Gcm::new(&key);
53
+ let nonce = Nonce::from_slice(&nonce);
54
+ let plaintext = cipher.decrypt(nonce, ciphertext.as_ref()).unwrap();
55
+ plaintext
56
+ }
57
+ }
58
+
59
+ #[napi]
60
+ pub fn aes_nonce() -> Vec<u8> {
61
+ let mut rng = ChaCha20Rng::from_entropy();
62
+ let mut random_bytes = Vec::with_capacity(12);
63
+ random_bytes.resize(12, 0);
64
+ rng.fill_bytes(&mut random_bytes);
65
+ random_bytes
66
+ }
67
+
68
+ #[napi]
69
+ pub fn aes128_key() -> Vec<u8> {
70
+ return CASAES128::generate_key();
71
+ }
72
+
73
+ #[napi]
74
+ pub fn aes256_key() -> Vec<u8> {
75
+ return CASAES256::generate_key();
76
+ }
77
+
78
+ #[napi]
79
+ pub fn aes128_encrypt(aes_key: Vec<u8>, nonce: Vec<u8>, plaintext: Vec<u8>) -> Vec<u8> {
80
+ return CASAES128::encrypt_plaintext(aes_key, nonce, plaintext);
81
+ }
82
+
83
+ #[napi]
84
+ pub fn aes128_decrypt(aes_key: Vec<u8>, nonce: Vec<u8>, ciphertext: Vec<u8>) -> Vec<u8> {
85
+ return CASAES128::decrypt_ciphertext(aes_key, nonce, ciphertext);
86
+ }
87
+
88
+ #[napi]
89
+ pub fn aes256_encrypt(aes_key: Vec<u8>, nonce: Vec<u8>, plaintext: Vec<u8>) -> Vec<u8> {
90
+ return CASAES256::encrypt_plaintext(aes_key, nonce, plaintext);
91
+ }
92
+
93
+ #[napi]
94
+ pub fn aes256_decrypt(aes_key: Vec<u8>, nonce: Vec<u8>, ciphertext: Vec<u8>) -> Vec<u8> {
95
+ return CASAES256::decrypt_ciphertext(aes_key, nonce, ciphertext);
96
+ }
97
+
98
+ #[test]
99
+ fn aes128_encrypt_decrypt_test() {
100
+ let aes_key = aes128_key();
101
+ let nonce = aes_nonce();
102
+ let plaintext = b"WelcomeHome".to_vec();
103
+ let ciphertext = aes128_encrypt(aes_key.clone(), nonce.clone(), plaintext.clone());
104
+ let decrypted_plaintext = aes128_decrypt(aes_key, nonce, ciphertext);
105
+ assert_eq!(decrypted_plaintext, plaintext)
106
+ }
107
+
108
+ #[test]
109
+ fn aes256_encrypt_decrypt_test() {
110
+ let aes_key = aes256_key();
111
+ let nonce = aes_nonce();
112
+ let plaintext = b"WelcomeHome".to_vec();
113
+ let ciphertext = aes256_encrypt(aes_key.clone(), nonce.clone(), plaintext.clone());
114
+ let decrypted_plaintext = aes256_decrypt(aes_key, nonce, ciphertext);
115
+ assert_eq!(decrypted_plaintext, plaintext)
116
+ }
@@ -0,0 +1,5 @@
1
+ pub trait CASAESEncryption {
2
+ fn generate_key() -> Vec<u8>;
3
+ fn encrypt_plaintext(aes_key: Vec<u8>, nonce: Vec<u8>, plaintext: Vec<u8>) -> Vec<u8>;
4
+ fn decrypt_ciphertext(aes_key: Vec<u8>, nonce: Vec<u8>, ciphertext: Vec<u8>) -> Vec<u8>;
5
+ }
@@ -0,0 +1,53 @@
1
+ import { decryptCiphertextRsa, encryptPlaintextRsa, generateRsaKeys, RsaKeyPairResult, signRsa, verifyRsa } from "../../index";
2
+
3
+ export class RSAWrapper {
4
+ public generateKeys(keySize: number): RsaKeyPairResult {
5
+ if (keySize !== 1024 && keySize !== 2048 && keySize !== 4096) {
6
+ throw new Error("You must provide an appropriate key size to generate RSA keys");
7
+ }
8
+ return generateRsaKeys(keySize);
9
+ }
10
+
11
+ public encrypt(publicKey: string, plaintext: Array<number>): Array<number> {
12
+ if (!publicKey) {
13
+ throw new Error("You must provide a public key to encrypt with RSA");
14
+ }
15
+ if (!plaintext || plaintext.length === 0) {
16
+ throw new Error("You must provide an array of plaintext bytes to encrypt with RSA");
17
+ }
18
+ return encryptPlaintextRsa(publicKey, plaintext);
19
+ }
20
+
21
+ public decrypt(privateKey: string, ciphertext: Array<number>): Array<number> {
22
+ if (!privateKey) {
23
+ throw new Error("You must provide a private key to encrypt with RSA");
24
+ }
25
+ if (!ciphertext || ciphertext.length === 0) {
26
+ throw new Error("You must provide an array of ciphertext bytes to encrypt with RSA");
27
+ }
28
+ return decryptCiphertextRsa(privateKey, ciphertext);
29
+ }
30
+
31
+ public sign(privateKey: string, hash: Array<number>): Array<number> {
32
+ if (!privateKey) {
33
+ throw new Error("You must provide a private key to sign with RSA");
34
+ }
35
+ if (!hash || hash.length === 0) {
36
+ throw new Error("You must provide an allocated hash to sign with RSA");
37
+ }
38
+ return signRsa(privateKey, hash);
39
+ }
40
+
41
+ public verify(publicKey: string, hash: Array<number>, signature: Array<number>): boolean {
42
+ if (!publicKey) {
43
+ throw new Error("You must provide a public key to verify with RSA");
44
+ }
45
+ if (!hash || hash.length === 0) {
46
+ throw new Error("You must provide an allocated hash to verify with RSA");
47
+ }
48
+ if (!signature || signature.length === 0) {
49
+ throw new Error("You must provide and allocated signature to verify with RSA");
50
+ }
51
+ return verifyRsa(publicKey, hash, signature);
52
+ }
53
+ }
@@ -0,0 +1,4 @@
1
+ import { RSAWrapper } from "./RSAWrapper";
2
+ import { RsaKeyPairResult } from "../../index";
3
+
4
+ export { RSAWrapper, RsaKeyPairResult };
package/src-ts/index.ts CHANGED
@@ -6,14 +6,21 @@ import {
6
6
  ScryptWrapper,
7
7
  } from "./password-hashers/index";
8
8
  import { HasherFactory, HasherType, SHAWrapper } from "./hashers/index";
9
+ import { X25519Wrapper } from "./key_exchange/index";
10
+ import { AESWrapper } from "./symmetric/index";
11
+ import { RSAWrapper, RsaKeyPairResult } from "./asymmetric";
9
12
 
10
13
  export {
11
14
  Argon2Wrapper,
12
15
  BCryptWrapper,
13
- ScryptWrapper,
14
- PasswordHasherFactory,
15
- PasswordHasherType,
16
16
  HasherFactory,
17
17
  HasherType,
18
+ PasswordHasherFactory,
19
+ PasswordHasherType,
20
+ ScryptWrapper,
18
21
  SHAWrapper,
22
+ X25519Wrapper,
23
+ AESWrapper,
24
+ RSAWrapper,
25
+ RsaKeyPairResult
19
26
  };
@@ -0,0 +1,3 @@
1
+ import { X25519Wrapper } from "./x25519";
2
+
3
+ export { X25519Wrapper };
@@ -0,0 +1,11 @@
1
+ import { x25519DiffieHellman, x25519GenerateSecretAndPublicKey, X25519SecretPublicKeyResult } from "../../index"
2
+
3
+ export class X25519Wrapper {
4
+ public generateSecretAndPublicKey(): X25519SecretPublicKeyResult {
5
+ return x25519GenerateSecretAndPublicKey();
6
+ }
7
+
8
+ public diffieHellman(secretKey: Array<number>, publicKey: Array<number>) {
9
+ return x25519DiffieHellman(secretKey, publicKey);
10
+ }
11
+ }
@@ -0,0 +1,39 @@
1
+ import {
2
+ aes128Decrypt,
3
+ aes128Encrypt,
4
+ aes128Key,
5
+ aes256Decrypt,
6
+ aes256Encrypt,
7
+ aes256Key,
8
+ aesNonce,
9
+ } from "../../index";
10
+
11
+ export class AESWrapper {
12
+ public aes128Key(): Array<number> {
13
+ return aes128Key();
14
+ }
15
+
16
+ public aes256Key(): Array<number> {
17
+ return aes256Key();
18
+ }
19
+
20
+ public aesNonce(): Array<number> {
21
+ return aesNonce();
22
+ }
23
+
24
+ public aes128Encrypt(aesKey: Array<number>, nonce: Array<number>, plaintext: Array<number>): Array<number> {
25
+ return aes128Encrypt(aesKey, nonce, plaintext);
26
+ }
27
+
28
+ public aes128Decrypt(aesKey: Array<number>, nonce: Array<number>, ciphertext: Array<number>): Array<number> {
29
+ return aes128Decrypt(aesKey, nonce, ciphertext);
30
+ }
31
+
32
+ public aes256Encrypt(aesKey: Array<number>, nonce: Array<number>, plaintext: Array<number>): Array<number> {
33
+ return aes256Encrypt(aesKey, nonce, plaintext);
34
+ }
35
+
36
+ public aes256Decrypt(aesKey: Array<number>, nonce: Array<number>, ciphertext: Array<number>): Array<number> {
37
+ return aes256Decrypt(aesKey, nonce, ciphertext);
38
+ }
39
+ }
@@ -0,0 +1,3 @@
1
+ import { AESWrapper } from "./aes-wrapper";
2
+
3
+ export { AESWrapper };
@@ -0,0 +1,28 @@
1
+ import { assert } from "chai";
2
+ import { RSAWrapper, RsaKeyPairResult } from "..";
3
+ import { areEqual } from "./helpers/array";
4
+
5
+ describe("Asymmetric Tests", () => {
6
+ it("RSA 4096 encrypt and decrypt equals", () => {
7
+ const rsaWrapper: RSAWrapper = new RSAWrapper();
8
+ const keys: RsaKeyPairResult = rsaWrapper.generateKeys(4096);
9
+ const tohashed: string = "This is my array to encrypt";
10
+ const encoder = new TextEncoder();
11
+ const tohashBytes: Array<number> = Array.from(encoder.encode(tohashed));
12
+ const ciphertext = rsaWrapper.encrypt(keys.publicKey, tohashBytes);
13
+ const plaintext = rsaWrapper.decrypt(keys.privateKey, ciphertext);
14
+ let result = areEqual(tohashBytes, plaintext);
15
+ assert.isTrue(result);
16
+ });
17
+
18
+ it("RSA 2048 Sign and Verify", () => {
19
+ const rsaWrapper = new RSAWrapper();
20
+ const keys: RsaKeyPairResult = rsaWrapper.generateKeys(2048);
21
+ const tohashed: string = "This is my encrypt";
22
+ const encoder = new TextEncoder();
23
+ const toSignBytes: Array<number> = Array.from(encoder.encode(tohashed));
24
+ const signature: Array<number> = rsaWrapper.sign(keys.privateKey, toSignBytes);
25
+ const verified = rsaWrapper.verify(keys.publicKey, toSignBytes, signature);
26
+ assert.isTrue(verified);
27
+ });
28
+ });
@@ -0,0 +1,10 @@
1
+ export const areEqual = (a: any, b: any) => {
2
+ if (a === b) return true;
3
+ if (a == null || b == null) return false;
4
+ if (a.length !== b.length) return false;
5
+
6
+ for (var i = 0; i < a.length; ++i) {
7
+ if (a[i] !== b[i]) return false;
8
+ }
9
+ return true;
10
+ };
@@ -0,0 +1,23 @@
1
+ import { assert } from "chai";
2
+ import { X25519Wrapper } from "../src-ts/index";
3
+ import { areEqual } from "./helpers/array";
4
+
5
+ describe("X25519 Key Exchange", () => {
6
+ it("Pass", () => {
7
+ const wrapper = new X25519Wrapper();
8
+ const alice = wrapper.generateSecretAndPublicKey();
9
+ const bob = wrapper.generateSecretAndPublicKey();
10
+
11
+ const alice_shared_secret = wrapper.diffieHellman(
12
+ alice.secretKey,
13
+ bob.publicKey,
14
+ );
15
+ const bob_shared_secret = wrapper.diffieHellman(
16
+ bob.secretKey,
17
+ alice.publicKey,
18
+ );
19
+
20
+ var result = areEqual(alice_shared_secret, bob_shared_secret);
21
+ assert.isTrue(result);
22
+ });
23
+ });
@@ -0,0 +1,31 @@
1
+ import { assert } from "chai";
2
+ import { AESWrapper } from "../src-ts/symmetric/aes-wrapper";
3
+ import { areEqual } from "./helpers/array";
4
+
5
+ describe("Symmetric Tests", () => {
6
+ it("aes 128 encrypt and decrypt equals", () => {
7
+ const aesWrapper: AESWrapper = new AESWrapper();
8
+ const aesKey = aesWrapper.aes128Key();
9
+ const aesNonce = aesWrapper.aesNonce();
10
+ const tohashed: string = "This is my array to encrypt";
11
+ const encoder = new TextEncoder();
12
+ const tohashBytes: Array<number> = Array.from(encoder.encode(tohashed));
13
+ const ciphertext = aesWrapper.aes128Encrypt(aesKey, aesNonce, tohashBytes);
14
+ const plaintxt = aesWrapper.aes128Decrypt(aesKey, aesNonce, ciphertext);
15
+ var result = areEqual(plaintxt, tohashBytes);
16
+ assert.isTrue(result);
17
+ });
18
+
19
+ it("aes 256 encrypt and decrypt equals", () => {
20
+ const aesWrapper: AESWrapper = new AESWrapper();
21
+ const aesKey = aesWrapper.aes256Key();
22
+ const aesNonce = aesWrapper.aesNonce();
23
+ const tohashed: string = "This is my array to encrypt";
24
+ const encoder = new TextEncoder();
25
+ const tohashBytes: Array<number> = Array.from(encoder.encode(tohashed));
26
+ const ciphertext = aesWrapper.aes256Encrypt(aesKey, aesNonce, tohashBytes);
27
+ const plaintxt = aesWrapper.aes256Decrypt(aesKey, aesNonce, ciphertext);
28
+ var result = areEqual(plaintxt, tohashBytes);
29
+ assert.isTrue(result);
30
+ });
31
+ });