-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from rambler-digital-solutions/crypto
feat(crypto): add crypto utils
- Loading branch information
Showing
18 changed files
with
2,268 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Crypto | ||
|
||
Browser crypto utils | ||
|
||
## Install | ||
|
||
``` | ||
npm install -D @rambler-tech/crypto | ||
``` | ||
|
||
or | ||
|
||
``` | ||
yarn add -D @rambler-tech/crypto | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import {getRandomValues, subtle} from './crypto' | ||
import { | ||
bufferFromString, | ||
bufferFromUnicode, | ||
stringFromBuffer, | ||
base64urlFromString | ||
} from './buffers' | ||
|
||
function generateAESKey() { | ||
return subtle.generateKey( | ||
{ | ||
name: 'AES-GCM', | ||
length: 256 | ||
}, | ||
true, | ||
['encrypt', 'decrypt'] | ||
) | ||
} | ||
|
||
async function encryptAES( | ||
key: CryptoKey, | ||
initVector: Uint8Array, | ||
body: string | ||
) { | ||
const encryptedBody = await subtle.encrypt( | ||
{name: 'AES-GCM', iv: initVector}, | ||
key, | ||
bufferFromUnicode(body) | ||
) | ||
|
||
return base64urlFromString(stringFromBuffer(encryptedBody)) | ||
} | ||
|
||
function importRSAKey(keyString: string) { | ||
return subtle.importKey( | ||
'spki', | ||
bufferFromString(window.atob(keyString)), | ||
{ | ||
name: 'RSA-OAEP', | ||
hash: {name: 'SHA-256'} | ||
}, | ||
false, | ||
['wrapKey'] | ||
) | ||
} | ||
|
||
async function encryptRSA(key: CryptoKey, body: CryptoKey) { | ||
const encryptedBody = await subtle.wrapKey('raw', body, key, { | ||
name: 'RSA-OAEP' | ||
} as RsaOaepParams) | ||
|
||
return base64urlFromString(stringFromBuffer(encryptedBody)) | ||
} | ||
|
||
/** Encrypt with AES and RSA keys */ | ||
export async function encryptAESRSA(keyString: string, body: string) { | ||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers | ||
const initVector = getRandomValues(new Uint8Array(12)) | ||
const initVectorString = base64urlFromString(stringFromBuffer(initVector)) | ||
|
||
const [aesKey, rsaKey] = await Promise.all([ | ||
generateAESKey(), | ||
importRSAKey(keyString) | ||
]) | ||
|
||
const [encryptedBody, encryptedKey] = await Promise.all([ | ||
encryptAES(aesKey, initVector, body), | ||
encryptRSA(rsaKey, aesKey) | ||
]) | ||
|
||
return `${encryptedBody}.${encryptedKey}.${initVectorString}` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import sha from 'sha.js' | ||
import {hash} from './bcryptjs' | ||
|
||
/** bcrypt derivation params */ | ||
export interface DeriveBcryptKeyParams { | ||
salt: string | ||
token: string | ||
} | ||
|
||
/** Derive key with bcrypt */ | ||
export async function deriveBcryptKey( | ||
input: string, | ||
{salt, token}: DeriveBcryptKeyParams | ||
) { | ||
const hashString: string = await new Promise((resolve, reject) => { | ||
hash(input, salt, (error, hash) => { | ||
if (error) { | ||
reject(error) | ||
} else { | ||
resolve(hash) | ||
} | ||
}) | ||
}) | ||
|
||
if (!token) { | ||
return hashString | ||
} | ||
|
||
return sha('sha512') | ||
.update(hashString + token) | ||
.digest('hex') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Type definitions for bcryptjs v2.4.0 | ||
// Project: https://github.com/dcodeIO/bcrypt.js | ||
// Definitions by: Joshua Filby <https://github.com/Joshua-F/> | ||
// Rafael Kraut <https://github.com/RafaelKr> | ||
// Branislav Holý <https://github.com/branoholy> | ||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped | ||
// TypeScript Version: 2.1 | ||
|
||
/** | ||
* Sets the pseudo random number generator to use as a fallback if neither node's crypto module nor the Web Crypto API is available. | ||
* Please note: It is highly important that the PRNG used is cryptographically secure and that it is seeded properly! | ||
* @param random Function taking the number of bytes to generate as its sole argument, returning the corresponding array of cryptographically secure random byte values. | ||
*/ | ||
export declare function setRandomFallback( | ||
random: (random: number) => Buffer | ||
): void | ||
|
||
/** | ||
* Synchronously generates a salt. | ||
* @param rounds Number of rounds to use, defaults to 10 if omitted | ||
* @return Resulting salt | ||
* @throws If a random fallback is required but not set | ||
*/ | ||
export declare function genSaltSync(rounds?: number): string | ||
|
||
/** | ||
* Asynchronously generates a salt. | ||
* @param rounds Number of rounds to use, defaults to 10 if omitted | ||
* @return Promise with resulting salt, if callback has been omitted | ||
*/ | ||
export declare function genSalt(rounds?: number): Promise<string> | ||
|
||
/** | ||
* Asynchronously generates a salt. | ||
* @param callback Callback receiving the error, if any, and the resulting salt | ||
*/ | ||
export declare function genSalt( | ||
callback: (err: Error, salt: string) => void | ||
): void | ||
|
||
/** | ||
* Asynchronously generates a salt. | ||
* @param rounds Number of rounds to use, defaults to 10 if omitted | ||
* @param callback Callback receiving the error, if any, and the resulting salt | ||
*/ | ||
export declare function genSalt( | ||
rounds: number, | ||
callback: (err: Error, salt: string) => void | ||
): void | ||
|
||
/** | ||
* Synchronously generates a hash for the given string. | ||
* @param s String to hash | ||
* @param salt Salt length to generate or salt to use, default to 10 | ||
* @return Resulting hash | ||
*/ | ||
export declare function hashSync(s: string, salt?: number | string): string | ||
|
||
/** | ||
* Asynchronously generates a hash for the given string. | ||
* @param s String to hash | ||
* @param salt Salt length to generate or salt to use | ||
* @return Promise with resulting hash, if callback has been omitted | ||
*/ | ||
export declare function hash(s: string, salt: number | string): Promise<string> | ||
|
||
/** | ||
* Asynchronously generates a hash for the given string. | ||
* @param s String to hash | ||
* @param salt Salt length to generate or salt to use | ||
* @param callback Callback receiving the error, if any, and the resulting hash | ||
* @param progressCallback Callback successively called with the percentage of rounds completed (0.0 - 1.0), maximally once per MAX_EXECUTION_TIME = 100 ms. | ||
*/ | ||
export declare function hash( | ||
s: string, | ||
salt: number | string, | ||
callback?: (err: Error, hash: string) => void, | ||
progressCallback?: (percent: number) => void | ||
): void | ||
|
||
/** | ||
* Synchronously tests a string against a hash. | ||
* @param s String to compare | ||
* @param hash Hash to test against | ||
* @return true if matching, otherwise false | ||
*/ | ||
export declare function compareSync(s: string, hash: string): boolean | ||
|
||
/** | ||
* Asynchronously compares the given data against the given hash. | ||
* @param s Data to compare | ||
* @param hash Data to be compared to | ||
* @return Promise, if callback has been omitted | ||
*/ | ||
export declare function compare(s: string, hash: string): Promise<boolean> | ||
|
||
/** | ||
* Asynchronously compares the given data against the given hash. | ||
* @param s Data to compare | ||
* @param hash Data to be compared to | ||
* @param callback Callback receiving the error, if any, otherwise the result | ||
* @param progressCallback Callback successively called with the percentage of rounds completed (0.0 - 1.0), maximally once per MAX_EXECUTION_TIME = 100 ms. | ||
*/ | ||
export declare function compare( | ||
s: string, | ||
hash: string, | ||
callback?: (err: Error, success: boolean) => void, | ||
progressCallback?: (percent: number) => void | ||
): void | ||
|
||
/** | ||
* Gets the number of rounds used to encrypt the specified hash. | ||
* @param hash Hash to extract the used number of rounds from | ||
* @return Number of rounds used | ||
*/ | ||
export declare function getRounds(hash: string): number | ||
|
||
/** | ||
* Gets the salt portion from a hash. Does not validate the hash. | ||
* @param hash Hash to extract the salt from | ||
* @return Extracted salt part | ||
*/ | ||
export declare function getSalt(hash: string): string | ||
|
||
/** | ||
* Encodes a byte array to base64 with up to len bytes of input, using the custom bcrypt alphabet. | ||
* @function | ||
* @param b Byte array | ||
* @param len Maximum input length | ||
*/ | ||
export declare function encodeBase64( | ||
b: Readonly<ArrayLike<number>>, | ||
len: number | ||
): string | ||
|
||
/** | ||
* Decodes a base64 encoded string to up to len bytes of output, using the custom bcrypt alphabet. | ||
* @function | ||
* @param s String to decode | ||
* @param len Maximum output length | ||
*/ | ||
export declare function decodeBase64(s: string, len: number): number[] |
Oops, something went wrong.