diff --git a/Cargo.toml b/Cargo.toml index 0d6e6db..ddb508c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ sha3 = "0.10.8" x25519-dalek = {version = "2.0.0", features = ["static_secrets"]} rand_07 = { package = "rand", version = "0.7.0" } ascon-aead = "0.4.2" +rayon = "1.10.0" [profile.dev.package.num-bigint-dig] opt-level = 3 diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index a545d5c..3203cc4 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -11,6 +11,105 @@ const ciphertext = aesWrapper.aes128Encrypt(aesKey, aesNonce, tohashBytes); const plaintxt = aesWrapper.aes128Decrypt(aesKey, aesNonce, ciphertext); ``` +### Asymmetric +-RSA +```typescript +const rsaWrapper: RSAWrapper = new RSAWrapper(); +const keys: RsaKeyPairResult = rsaWrapper.generateKeys(4096); +const tohashed: string = "This is my array to encrypt"; +const encoder = new TextEncoder(); +const tohashBytes: Array = Array.from(encoder.encode(tohashed)); +const ciphertext = rsaWrapper.encrypt(keys.publicKey, tohashBytes); +const plaintext = rsaWrapper.decrypt(keys.privateKey, ciphertext); +``` + + +### Digital Signature +-ED25519 SHA +```typescript +const shaDsWrapper = DigitalSignatureFactory.get(DigitalSignatureType.SHA256) +const toHash: string = "This is my array to encrypt"; +const encoder = new TextEncoder(); +const toHashBytes: Array = Array.from(encoder.encode(toHash)); +const dsResult = shaDsWrapper.createED25519(toHashBytes); +const verify = shaDsWrapper.verifyED25519(dsResult.publicKey, toHashBytes, dsResult.signature); +``` + +-RSA SHA +```typescript +const shaDsWrapper = DigitalSignatureFactory.get(DigitalSignatureType.SHA512) +const tohashed: string = "This is my array to encrypt"; +const notOriginal: string = "This is not a fun time"; +const encoder = new TextEncoder(); +const tohashBytes: Array = Array.from(encoder.encode(tohashed)); +const badBytes: Array = Array.from(encoder.encode(notOriginal)); +const dsResult: RSADigitalSignatureResult = shaDsWrapper.createRsa(4096, tohashBytes); +const verify = shaDsWrapper.verifyRSa(dsResult.publicKey, badBytes, dsResult.signature); +``` + + +### Hashers +-SHA3 512 +```typescript +const wrapper = new SHAWrapper(); +const tohashed: string = "This is my array to hash"; +const encoder = new TextEncoder(); +const tohashBytes: Array = Array.from(encoder.encode(tohashed)); +const hashed = wrapper.hash512(tohashBytes); +``` + +-SHA3 256 +```typescript +const wrapper = new SHAWrapper(); +const tohashed: string = "This is my array to hash"; +const encoder = new TextEncoder(); +const tohashBytes: Array = Array.from(encoder.encode(tohashed)); +const hashed = wrapper.hash256(tohashBytes); +``` + +### Hybrid Encryption +-AES/RSA Encryption +```typescript +const hybridWrapper = new HybridEncryptionWrapper(); +let initalizer = new AESRSAHybridInitializer(128, 4096); +const tohashed: string = "This is my encrypt text for rsa hybrid"; +const encoder = new TextEncoder(); +const toEncrypt: Array = Array.from(encoder.encode(tohashed)); +let result: AesRsaHybridEncryptResult = hybridWrapper.encrypt(toEncrypt, initalizer); +let plaintext: Array = hybridWrapper.decrypt(initalizer.rsaKeyPair.privateKey, result); +``` + +### Key Exchange +-X25519 +```typescript +const wrapper = new X25519Wrapper(); +const alice = wrapper.generateSecretAndPublicKey(); +const bob = wrapper.generateSecretAndPublicKey(); + +const alice_shared_secret = wrapper.generateSharedSecret( + alice.secretKey, + bob.publicKey, + ); +const bob_shared_secret = wrapper.generateSharedSecret( + bob.secretKey, + alice.publicKey, + ); + +var result = areEqual(alice_shared_secret, bob_shared_secret); +``` + +### Sponges +-Ascon 128 +```typescript +const wrapper: AsconWrapper = new AsconWrapper(); +const key: Array = wrapper.ascon128Key(); +const nonce: Array = wrapper.ascon128Nonce(); +const tohashed: string = "This is my array to encrypt"; +const encoder = new TextEncoder(); +const tohashBytes: Array = Array.from(encoder.encode(tohashed)); +const ciphertext = wrapper.ascon128Encrypt(key, nonce, tohashBytes); +const plaintext = wrapper.ascon128Decrypt(key, nonce, ciphertext); +``` ### Passwords - BCrypt diff --git a/index.d.ts b/index.d.ts index 2f7f119..5e867e8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -4,11 +4,17 @@ /* auto-generated by NAPI-RS */ export function argon2Hash(password: string): string +export function argon2HashThreadPool(password: string): string export function argon2Verify(hashedPassword: string, passwordToVerify: string): boolean +export function argon2VerifyThreadpool(hashedPassword: string, passwordToVerify: string): boolean export function bcryptHash(passwordToHash: string): string +export function bcryptHashThreadpool(passwordToHash: string): string export function bcryptVerify(hashedPassword: string, passwordToVerify: string): boolean +export function bcryptVerifyThreadpool(passwordToHash: string, passwordToVerify: string): boolean export function scryptHash(passwordToHash: string): string export function scryptVerify(hashedPassword: string, passwordToVerify: string): boolean +export function scryptHashThreadpool(passwordToHash: string): string +export function scryptVerifyThreadpool(hashedPassword: string, passwordToVerify: string): boolean export function sha512(dataToHash: Array): Array export function sha512Verify(dataToHash: Array, dataToVerify: Array): boolean export function sha256(dataToHash: Array): Array diff --git a/index.node b/index.node index fb9abb1..903a440 100644 Binary files a/index.node and b/index.node differ diff --git a/package.json b/package.json index 55849e0..60b8af3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cas-typescript-sdk", - "version": "1.0.19", + "version": "1.0.22", "description": "", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src-ts/password-hashers/argon2-wrapper.ts b/src-ts/password-hashers/argon2-wrapper.ts index 61a1c37..2795955 100644 --- a/src-ts/password-hashers/argon2-wrapper.ts +++ b/src-ts/password-hashers/argon2-wrapper.ts @@ -1,9 +1,27 @@ -import {argon2Hash, argon2Verify} from "./../../index"; -import { IPasswordHasherBase} from "./password-hasher-base"; +import { argon2Hash, argon2HashThreadPool, argon2Verify, argon2VerifyThreadpool } from "./../../index"; +import { IPasswordHasherBase } from "./password-hasher-base"; export class Argon2Wrapper implements IPasswordHasherBase { + + verifyThreadPool(hashedPassword: string, passwordToCheck: string): boolean { + if (!hashedPassword) { + throw new Error("You must provide a password to verify with Argon2"); + } + if (!passwordToCheck) { + throw new Error("You must provide a password to check to verify with Argon2"); + } + return argon2VerifyThreadpool(hashedPassword, passwordToCheck); + } + + public hashPasswordThreadPool(password: string): string { + if (!password) { + throw new Error("You must provide a password to hash with Argon2"); + } + return argon2HashThreadPool(password); + } + public hashPassword(password: string): string { - if (!password){ + if (!password) { throw new Error("You must provide a password to hash with Argon2"); } return argon2Hash(password); @@ -11,7 +29,9 @@ export class Argon2Wrapper implements IPasswordHasherBase { public verify(hashedPassword: string, passwordToVerify: string): boolean { if (!hashedPassword || !passwordToVerify) { - throw new Error("You must provide a hashed password and a plaintext password to verify with Argon2"); + throw new Error( + "You must provide a hashed password and a plaintext password to verify with Argon2", + ); } return argon2Verify(hashedPassword, passwordToVerify); } diff --git a/src-ts/password-hashers/bcrypt-wrapper.ts b/src-ts/password-hashers/bcrypt-wrapper.ts index 3b94483..2f44195 100644 --- a/src-ts/password-hashers/bcrypt-wrapper.ts +++ b/src-ts/password-hashers/bcrypt-wrapper.ts @@ -1,7 +1,24 @@ import { IPasswordHasherBase } from "./password-hasher-base"; -import { bcryptHash, bcryptVerify } from "./../../index"; +import { bcryptHash, bcryptHashThreadpool, bcryptVerify, bcryptVerifyThreadpool } from "./../../index"; export class BCryptWrapper implements IPasswordHasherBase { + + verifyThreadPool(hashedPassword: string, passwordToCheck: string): boolean { + if (!hashedPassword || !passwordToCheck) { + throw new Error( + "You must provide a hashed password and a plaintext password to verify with Argon2", + ); + } + return bcryptVerifyThreadpool(hashedPassword, passwordToCheck); + } + + public hashPasswordThreadPool(password: string): string { + if (!password) { + throw new Error("You must provide a password to hash with Argon2"); + } + return bcryptHashThreadpool(password); + } + public hashPassword(password: string): string { if (!password) { throw new Error("You must provide a password to hash with Argon2"); diff --git a/src-ts/password-hashers/password-hasher-base.ts b/src-ts/password-hashers/password-hasher-base.ts index 839d56d..1621e1f 100644 --- a/src-ts/password-hashers/password-hasher-base.ts +++ b/src-ts/password-hashers/password-hasher-base.ts @@ -1,4 +1,6 @@ export interface IPasswordHasherBase { hashPassword(password: string): string; verify(hashedPassword: string, passwordToVerify: string): boolean; + hashPasswordThreadPool(password: string): string; + verifyThreadPool(hashedPassword: string, passwordToCheck: string): boolean; } \ No newline at end of file diff --git a/src-ts/password-hashers/scrypt-wrapper.ts b/src-ts/password-hashers/scrypt-wrapper.ts index 17499fb..47bbe84 100644 --- a/src-ts/password-hashers/scrypt-wrapper.ts +++ b/src-ts/password-hashers/scrypt-wrapper.ts @@ -1,20 +1,37 @@ -import { scryptHash, scryptVerify } from "../../index"; +import { scryptHash, scryptHashThreadpool, scryptVerify, scryptVerifyThreadpool } from "../../index"; import { IPasswordHasherBase } from "./password-hasher-base"; export class ScryptWrapper implements IPasswordHasherBase { - public hashPassword(password: string): string { - if (!password){ - throw new Error("You must provide a password to hash with Scrypt"); - } - return scryptHash(password); - } - - public verify(hashedPassword: string, passwordToVerify: string): boolean { - if (!hashedPassword || !passwordToVerify) { - throw new Error("You must provide a hashed password and a plaintext password to verify with Scrypt"); - } - return scryptVerify(hashedPassword, passwordToVerify); - } + verifyThreadPool(hashedPassword: string, passwordToCheck: string): boolean { + if (!hashedPassword || !passwordToCheck) { + throw new Error( + "You must provide a hashed password and a plaintext password to verify with Scrypt", + ); + } + return scryptVerifyThreadpool(hashedPassword, passwordToCheck); + } -} \ No newline at end of file + hashPasswordThreadPool(password: string): string { + if (!password) { + throw new Error("You must provide a password to hash with Scrypt"); + } + return scryptHashThreadpool(password); + } + + public hashPassword(password: string): string { + if (!password) { + throw new Error("You must provide a password to hash with Scrypt"); + } + return scryptHash(password); + } + + public verify(hashedPassword: string, passwordToVerify: string): boolean { + if (!hashedPassword || !passwordToVerify) { + throw new Error( + "You must provide a hashed password and a plaintext password to verify with Scrypt", + ); + } + return scryptVerify(hashedPassword, passwordToVerify); + } +} diff --git a/src-ts/symmetric/aes-wrapper.ts b/src-ts/symmetric/aes-wrapper.ts index eeda5f6..2449cff 100644 --- a/src-ts/symmetric/aes-wrapper.ts +++ b/src-ts/symmetric/aes-wrapper.ts @@ -11,11 +11,32 @@ import { aesNonce, } from "../../index"; +/** + * @description A wrapper class that contains methods to construct keys, nonces, and methods to encrypt and decrypt with AES-128-GCM and AES-256-GCM + * + * @example + * ```ts + * const nonce = aesWrapper.generateAESNonce(); +const key = aesWrapper.aes128Key(); +const textEncoder = new TextEncoder(); +const array = Array.from(textEncoder.encode("Hello World")); +const encrypted = aesWrapper.aes128Encrypt(key, nonce, array); + * ``` + */ export class AESWrapper { + + /** + * @description Generates a 128 bit AES key + * @returns returns a 128 bit AES key + */ public aes128Key(): Array { return aes128Key(); } + /** + * @description Generates a 256 bit AES key + * @returns returns a 256 bit AES key + */ public aes256Key(): Array { return aes256Key(); } diff --git a/src/password_hashers/argon2.rs b/src/password_hashers/argon2.rs index bff7430..670a12f 100644 --- a/src/password_hashers/argon2.rs +++ b/src/password_hashers/argon2.rs @@ -1,4 +1,3 @@ -use std::net::ToSocketAddrs; use napi_derive::napi; @@ -7,6 +6,8 @@ use argon2::{ Argon2, PasswordHash, PasswordHasher, PasswordVerifier, }; +use crate::symmetric::aes::CASAES128; + use super::cas_password_hasher::CASPasswordHasher; pub struct CASArgon; @@ -35,11 +36,49 @@ pub fn argon2_hash(password: String) -> String { return ::hash_password(password); } +#[napi] +pub fn argon2_hash_thread_pool(password: String) -> String { + let (sender, receiver) = std::sync::mpsc::channel(); + rayon::spawn(move || { + let hash_result = ::hash_password(password); + sender.send(hash_result); + }); + let result = receiver.recv().unwrap(); + result +} + #[napi] pub fn argon2_verify(hashed_password: String, password_to_verify: String) -> bool { return ::verify_password(hashed_password, password_to_verify); } +#[napi] +pub fn argon2_verify_threadpool(hashed_password: String, password_to_verify: String) -> bool { + let (sender, receiver) = std::sync::mpsc::channel(); + rayon::spawn(move || { + let verify_result = ::verify_password(hashed_password, password_to_verify); + sender.send(verify_result); + }); + let result = receiver.recv().unwrap(); + result +} + +#[test] +pub fn argon2_hash_threadpool_test() { + let password = "ThisIsNotMyPasswolrd".to_string(); + let hashed = argon2_hash_thread_pool(password.clone()); + assert_ne!(password, hashed); +} + +#[test] +pub fn argon2_verify_threadpool_test() { + let password = "ThisIsNotMyPasswolrd".to_string(); + let passwordToCheck = "ThisIsNotMyPasswolrd".to_string(); + let hashed = argon2_hash_thread_pool(password); + let result = argon2_verify_threadpool(hashed, passwordToCheck); + assert_eq!(result, true); +} + #[test] pub fn argon2_hash_test() { let password = "ThisIsNotMyPasswolrd".to_string(); diff --git a/src/password_hashers/bcrypt.rs b/src/password_hashers/bcrypt.rs index 8e67fd8..c51e6d9 100644 --- a/src/password_hashers/bcrypt.rs +++ b/src/password_hashers/bcrypt.rs @@ -1,3 +1,5 @@ +use std::sync::mpsc; + use bcrypt::{hash, verify, DEFAULT_COST}; use napi_derive::napi; @@ -20,11 +22,33 @@ pub fn bcrypt_hash(password_to_hash: String) -> String { return ::hash_password(password_to_hash); } +#[napi] +pub fn bcrypt_hash_threadpool(password_to_hash: String) -> String { + let (sender, receiver) = mpsc::channel(); + rayon::spawn(move || { + let thread_result = ::hash_password(password_to_hash); + sender.send(thread_result); + }); + let result = receiver.recv().unwrap(); + result +} + #[napi] pub fn bcrypt_verify(hashed_password: String, password_to_verify: String) -> bool { return ::verify_password(hashed_password, password_to_verify); } +#[napi] +pub fn bcrypt_verify_threadpool(password_to_hash: String, password_to_verify: String) -> bool { + let (sender, receiver) = mpsc::channel(); + rayon::spawn(move || { + let thread_result = ::verify_password(password_to_hash, password_to_verify); + sender.send(thread_result); + }); + let result = receiver.recv().unwrap(); + result +} + #[test] pub fn bcrypt_hash_test() { let password = "ThisIsNotMyPasswolrd".to_string(); @@ -32,6 +56,13 @@ pub fn bcrypt_hash_test() { assert_ne!(password, hashed); } +#[test] +pub fn bcrypt_hash_threadpool_test() { + let password = "ThisIsNotMyPasswolrd".to_string(); + let hashed = bcrypt_hash_threadpool(password.clone()); + assert_ne!(password, hashed); +} + #[test] pub fn bcrypt_verify_test() { let password = "ThisIsNotMyPasswolrd".to_string(); @@ -40,6 +71,14 @@ pub fn bcrypt_verify_test() { assert_eq!(true, verified); } +#[test] +pub fn bcrypt_verify_threadpool_test() { + let password = "ThisIsNotMyPasswolrd".to_string(); + let hashed = bcrypt_hash_threadpool(password.clone()); + let verified = bcrypt_verify_threadpool(hashed, password); + assert_eq!(true, verified); +} + #[test] pub fn bcrypt_verify_fail_test() { let password = "ThisIsNotMyPasswolrd".to_string(); diff --git a/src/password_hashers/scrypt.rs b/src/password_hashers/scrypt.rs index 2a33407..72c3314 100644 --- a/src/password_hashers/scrypt.rs +++ b/src/password_hashers/scrypt.rs @@ -1,3 +1,5 @@ +use std::sync::mpsc; + use napi_derive::napi; use scrypt::{ @@ -36,6 +38,43 @@ pub fn scrypt_verify(hashed_password: String, password_to_verify: String) -> boo return ::verify_password(hashed_password, password_to_verify); } +#[napi] +pub fn scrypt_hash_threadpool(password_to_hash: String) -> String { + let (sender, receiver) = mpsc::channel(); + rayon::spawn(move || { + let thread_result = ::hash_password(password_to_hash); + sender.send(thread_result); + }); + let result = receiver.recv().unwrap(); + result +} + +#[napi] +pub fn scrypt_verify_threadpool(hashed_password: String, password_to_verify: String) -> bool { + let (sender, receiver) = mpsc::channel(); + rayon::spawn(move || { + let thread_result = ::verify_password(hashed_password, password_to_verify); + sender.send(thread_result); + }); + let result = receiver.recv().unwrap(); + result +} + +#[test] +pub fn scrypt_hash_threadpool_test() { + let password = "BadPassword".to_string(); + let hashed_password = scrypt_hash_threadpool(password.clone()); + assert_ne!(password, hashed_password); +} + +#[test] +pub fn scrypt_verify_threadpool_test() { + let password = "BadPassword".to_string(); + let hashed_password = scrypt_hash_threadpool(password.clone()); + let verified = scrypt_verify_threadpool(hashed_password, password); + assert_eq!(true, verified); +} + #[test] pub fn scrypt_hash_test() { let password = "BadPassword".to_string(); diff --git a/test-ts/password-hasher.test.spec.ts b/test-ts/password-hasher.test.spec.ts index 843fa20..3949e6f 100644 --- a/test-ts/password-hasher.test.spec.ts +++ b/test-ts/password-hasher.test.spec.ts @@ -1,5 +1,5 @@ import { assert, expect } from "chai"; -import { BCryptWrapper } from "../src-ts/password-hashers/index"; +import { Argon2Wrapper, BCryptWrapper } from "../src-ts/password-hashers/index"; import { ScryptWrapper } from "../src-ts/password-hashers/index"; import { PasswordHasherFactory, @@ -7,6 +7,22 @@ import { } from "../src-ts/password-hashers"; describe("Bcrypt Tests", () => { + + it("hash threadpool", () => { + const hasher: BCryptWrapper = new BCryptWrapper(); + const password: string = "ThisOneBadPassword!@"; + const hashedPassword: string = hasher.hashPasswordThreadPool(password); + assert.notEqual(hashedPassword, password); + }); + + it("verify threadpool", () => { + const hasher: BCryptWrapper = new BCryptWrapper(); + const password: string = "NotThisPassword!@"; + const hashedPassword: string = hasher.hashPassword(password); + const isValid: boolean = hasher.verifyThreadPool(hashedPassword, password); + expect(isValid).to.equal(true); + }); + it("hash", () => { const hasher: BCryptWrapper = new BCryptWrapper(); const password: string = "ThisOneBadPassword!@"; @@ -35,6 +51,25 @@ describe("Bcrypt Tests", () => { }); describe("Scrypt Tests", () => { + it("hash with threadpool", () => { + const hasher: ScryptWrapper = PasswordHasherFactory.getHasher( + PasswordHasherType.Scrypt, + ); + const password: string = "ScryptRocks"; + const hashed: string = hasher.hashPasswordThreadPool(password); + assert.notEqual(password, hashed); + }); + + it("verify pass with threadpool", () => { + const hasher: ScryptWrapper = PasswordHasherFactory.getHasher( + PasswordHasherType.Scrypt, + ); + const password: string = "ScryptRocks1231231"; + const hashed: string = hasher.hashPasswordThreadPool(password); + const verified: boolean = hasher.verifyThreadPool(hashed, password); + assert.isTrue(verified); + }); + it("hash with factory", () => { const hasher: ScryptWrapper = PasswordHasherFactory.getHasher( PasswordHasherType.Scrypt, @@ -69,8 +104,23 @@ describe("Scrypt Tests", () => { }); describe("Argon2 Tests", () => { + it("hash with threadpool", () => { + const argon2: Argon2Wrapper = PasswordHasherFactory.getHasher(PasswordHasherType.Argon2); + const password = "Argon2OverBCrypt"; + const hashed = argon2.hashPasswordThreadPool(password); + assert.notEqual(password, hashed); + }) + + it("verify with threadpool", () => { + const argon2: Argon2Wrapper = PasswordHasherFactory.getHasher(PasswordHasherType.Argon2); + const password = "Argon2OverBCrypt"; + const hashed = argon2.hashPasswordThreadPool(password); + const result = argon2.verifyThreadPool(hashed, password); + assert.equal(result, true); + }); + it("hash with factory", () => { - const hasher: ScryptWrapper = PasswordHasherFactory.getHasher( + const hasher: Argon2Wrapper = PasswordHasherFactory.getHasher( PasswordHasherType.Argon2, ); const password: string = "ScryptRocks"; @@ -79,7 +129,7 @@ describe("Argon2 Tests", () => { }); it("verify pass with factory", () => { - const hasher: ScryptWrapper = PasswordHasherFactory.getHasher( + const hasher: Argon2Wrapper = PasswordHasherFactory.getHasher( PasswordHasherType.Argon2, ); const password: string = "ScryptRocks1231231";