# globalid-crypto-library #

This library groups together all the crypto-related functionality in the
globaliD platform, and makes it available so that it works for Node.js on the server.

Note that this is not a standalone `npm` package in its own right.

## Breaking Changes

#### Support for Node 12 and up

globaliD crypto library version 5 only supports Node 12 and up. We are going to support
version based on the maintenance plan found here - https://nodejs.org/en/about/releases

#### Migrating from v3/v4 to v5

- Because all most every method in this package can be done without a promise, we decided to refactor the package so it
  can be used without a promise. 
- Fixed how the Typescript interfaces are defined and because of that names of the sub-packages changed. The list of renames: 
  - cryptosdk.aes -> cryptosdk.AES
  - cryptosdk.gid -> cryptosdk.GID
  - cryptosdk.jwe -> cryptosdk.JWE
  - cryptosdk.jwk -> cryptosdk.JWK
  - cryptosdk.hmac -> cryptosdk.HMAC
  - cryptosdk.pbkdf -> cryptosdk.PBKDF
  - cryptosdk.rsa -> cryptosdk.RSA
  - cryptosdk.util -> cryptosdk.Util
- Package no longer has a sub-package `bcrypt`, dependence `bcrypt` was removed from the project.
- Package no longer has a default export
- Method `cryptosdk.util.hmacSHA512` was remove, now it can be done with `cryptosdk.HMAC.sha512` or `cryptosdk.HMAC.nodeHmac('sha512',...)`

Example or how to migrate:
```typescript
// version 3 or 4
import cryptosdk from 'globalid-crypto-library'
const result: string = await cryptosdk.aes.encrypt(data, password)
// version 5
import * as cryptosdk from 'globalid-crypto-library'
const result: string = cryptosdk.AES.encrypt(data, password)
// or 
import { AES } from 'globalid-crypto-library'
const result: string = AES.encrypt(data, password)
```

# Dependencies

Currently the project has the following dependencies (two additional dependencies were introduced by PRE cryptography):

- [node-jose v2.0.0 or higher](https://www.npmjs.com/package/node-jose)
- [elliptic v6.5.4](https://www.npmjs.com/package/elliptic)
- [smart-buffer v4.2.0 or higher](https://www.npmjs.com/package/smart-buffer)

# Installation

To install, simply add the crypto library as a dependency within your project.
For example:

```bash
$ npm install globalid-crypto-library --save
```

## Usage ##

To use the globalid-crypto-library, simply `require` the library, like this in the commonJS format:

```javascript
const crypto = require('globalid-crypto-library')
```

or if you are using a transpiler (i.e. when using TypeScript):

```typescript
import * as crypto from 'globalid-crypto-library'
```

Once it has been required, you can use a consistent interface across all the
various platforms, following the API described below.  For example:

```typescript
let keyPair = crypto.RSA.generateKeyPair()
```

# Available Methods

The crypto library is broken into several sections, grouping functions
according to the type of cryptographic functionality they provide:

- [crypto.AES](#cryptoaes): symmetric encryption and decryption
- [crypto.GID](#cryptogid): utility functions for globaliD identities
- [crypto.JOSE](#cryptojose): exporting npm package [node-jose](https://www.npmjs.com/package/node-jose)
- [crypto.JWE](#cryptojwe): utility functions to create encryption and decryption
- [crypto.JWS](#cryptojws): utility functions to verify and create signature
- [crypto.JWK](#cryptojwk): utility functions to import JWK keys public or private to PEM format
- [crypto.HMAC](#cryptohmac): HMAC hashing algorithms
- [crypto.PBKDF](#cryptopbkdf): key-generation using passwords
- [crypto.RSA](#cryptorsa): key generation, signing, signing validation, encryption and decryption with RSA keys
- [crypto.ED25519](#cryptoed25519): key generation, signing, signing validation, encryption and decryption with ED25519 keys
- [crypto.PRE](#cryptoPRE): key generation, re-encryption key generation, encryption, decryption and re-encryption
- [crypto.Util](#cryptoutil): utility functions

## crypto.AES

#### encrypt

```typescript
crypto.AES.encrypt(data: string, password: string): string
```
Encrypt string data using `AES-256-CBC`. Returns a string containing
the IV in hex (first 32 characters) and encrypted data in base64-encoded encrypted data.

#### decrypt

```typescript
crypto.AES.decrypt(data: string, password: string): string
```

Decrypt some data previously encrypted using the ```typescript
crypto.AES.decrypt(data: string, password: string)`
function.

Note: Taking the first 32 characters from the `data` string is the IV value in hex needed for `AES-256-CBC`.

#### encryptBuffer

```typescript
crypto.AES.encryptBuffer(data: Buffer, password: string): Buffer
```

Encrypt Buffer data using `AES-256-CBC`. First 16 bytes are IV value everything else it is encrypted value Buffer type.

#### decryptBuffer

```typescript
crypto.AES.decryptBuffer(data, password): Buffer
```

Decrypt Buffer data previously encrypted using the ```typescript
crypto.AES.encryptBuffer(data, password)`
function.

#### encryptStream

```typescript
crypto.AES.encryptStream(password): stream.Transform
```

Get the encrypt stream which can then be piped to destination.

#### decryptStream

```typescript
crypto.AES.decryptStream(password): stream.Transform
```

Get the decrypt stream which can then be piped to destination.

## crypto.GID

#### aesCbcEncryptSecurity

```typescript
crypto.GID.aesCbcEncryptSecurity(data: string, password: string): string
```

Helper function to encrypt data. Password is hashed with PBKDF.get method and then use to encrypt the data.
Iteration parameter on PBKDF.get here is hardcoded to value 100001. 

#### aesCbcEncryptIdentity

```typescript
crypto.GID.aesCbcEncryptIdentity(data: string, password: string, iterations: number = 100000): string
```

Helper function to encrypt data. Password is hashed with PBKDF.get method and then use to encrypt the data.

#### aesCbcDecryptSecurity

```typescript
crypto.GID.aesCbcDecryptSecurity(encryptedData: string, password: string): string
```

Helper function to decrypt data. Password is hashed with PBKDF.get method and then use to decrypt the data.
Iteration parameter on PBKDF.get here is hardcoded to value 100001. 

#### aesCbcDecryptIdentity

```typescript
crypto.GID.aesCbcDecryptIdentity(encryptedData: string, password: string, iterations: number = 100000): string
```

Helper function to decrypt data. Password is hashed with PBKDF.get method and then use to decrypt the data.


## crypto.JOSE

Exporting package [node-jose](https://www.npmjs.com/package/node-jose). You can read more about the package
on their NPM page.

## crypto.JWE

#### encrypt

```typescript
type JwkKey = string | {[key: string]: string | string[] } | JWK.RawKey

async crypto.JWE.encrypt(public_key: JwkKey, data: string): Promise<string>
```

Encrypt data with JWK public key, with format `compact` and content algorithm `A256CBC-HS512`

#### decrypt

```typescript
type JwkKey = string | {[key: string]: string | string[] } | JWK.RawKey

async crypto.JWE.decrypt(private_key: JwkKey, encrypted_data: string): Promise<string>
```

Decrypting data with JWK private key.


## crypto.JWK

#### publicKeyToPem

```typescript
type JwkKey = string | {[key: string]: string | string[] } | JWK.RawKey

async crypto.JWK.publicKeyToPem(key: JwkKey): Promise<string>
```

Converting JWK public key format into PEM format

#### privateKeyToPem

```typescript
type JwkKey = string | {[key: string]: string | string[] } | JWK.RawKey

async crypto.JWK.privateKeyToPem(key: JwkKey): Promise<string>
```

Converting JWK private key format into PEM format

## crypto.JWS

#### sign

```typescript
type JwkKey = string | {[key: string]: string | string[] } | JWK.RawKey
type KeyForm = 'json' | 'private' | 'pkcs8' | 'public' | 'spki' | 'pkix' | 'x509' | 'pem'

async crypto.JWS.sign(private_key: JwkKey, payload: string, key_form?: KeyForm): Promise<string>
```
Sign payload using JWK private key. Note that if the private key is not in standard JWK format, key_form parameter should also be specified. Signature algorithm used is RSA-SHA256

#### verify

```typescript
type JwkKey = string | {[key: string]: string | string[] } | JWK.RawKey
type KeyForm = 'json' | 'private' | 'pkcs8' | 'public' | 'spki' | 'pkix' | 'x509' | 'pem'

async crypto.JWS.verify(public_key: JwkKey, jwk: string, key_form?: KeyForm): Promise<string>
```

Verify JWK signature using JWK public key. Note that if the private key is not in standard JWK format, key_form parameter should also be specified.

## crypto.HMAC

#### md5

```typescript
crypto.HMAC.md5(data: string, key: string): string
```

Calculate the `MD5` hash of the given data, using the given salt.  `data` should
be the data to hash, as a string, and `key` should be a string to
use as the key.

Returns the hash as a hex-encoded string.

#### sha1

```typescript
crypto.HMAC.sha1(data: string, key: string): string
```

Calculate the `SHA-1` hash of the given data, using the given salt.  `data`
should be the data to hash, as a string, and `key` should be a hex-encoded
string to use as the key.

Returns the hash as a hex-encoded string.

#### sha256

```typescript
crypto.HMAC.sha256(data: string, key: string): string
```

Calculate the `SHA-256` hash of the given data, using the given salt.  `data`
should be the data to hash, as a string, and `key` should be a hex-encoded
string to use as the key.

Returns the hash as a hex-encoded string.

#### sha384

```typescript
crypto.HMAC.sha384(data: string, key: string): string
```

Calculate the `SHA-384` hash of the given data, using the given salt.  `data`
should be the data to hash, as a string, and `key` should be a hex-encoded
string to use as the key.

Returns the hash as a hex-encoded string.

#### sha512

```typescript
crypto.HMAC.sha512(data: string, key: string): string
```

Calculate the `SHA-512` hash of the given data, using the given salt.  `data`
should be the data to hash, as a string, and `key` should be a hex-encoded
trying to use as the key.

Returns the hash as a hex-encoded string.

#### nodeHmac

```typescript
crypto.HMAC.nodeHmac(algorithm: string, data: string, key: string): string
```

Calculate hmac hash of the given algorithm and data, using the given salt.  `data`
should be the data to hash, as a string, and `key` should be a hex-encoded
trying to use as the key.

Returns the hash as a hex-encoded string.


## crypto.PBKDF

#### generate

```typescript
crypto.PBKDF.generate(data: string, num_iterations?: number =20000, salt_length?: number = 16, key_length?: number = 16): Generate
```

Generate a new password-based key derivation function (PBKDF) using
HMAC-SHA256.  Returns an object with the following fields:

- `iterations`: The number of iterations used to generate the PBKDF.
- `_salt`: A copy of the salt, as a Uint8Array.
- `_pbkdf`: A copy of the generated hash, as a Uint8Array.
- `salt`: A copy of the salt, as a base64-encoded string.
- `hash` The generated hash, as a hex-encoded string.
- `keySize`: The specified key length.

#### get

```typescript
crypto.PBKDF.get(data: string, salt: string | Buffer, iterations: number, keySize: number): string
```

Uses a previously-generated PBDKF function to hash a password. Returns values encoded in hex.

## crypto.PRE

A custom EC cryptosystem for proxy re-encryption (transform encryption) which is uni-directional and single-hop.
Currently limited to using `secp256k1` curve and `AES-256 CBC`/`SHA-256`.

#### encrypt

```typescript
const keyPair = cryptosdk.PRE.generateKeyPair();
const capsule = cryptosdk.PRE.encrypt(keyPair.public_key, message);
```

Encrypts with EC public key, produces a capsule - key and cipher (Lockbox type is used).

`publicKey` - public key used to encrypt given data
`data` - data to encrypt


#### decrypt

```typescript
const result = cryptosdk.PRE.decrypt(keyPair.private_key, capsule);
```

Decrypts capsule with EC private key, can decrypt both original and re-encrypted capsules.

`privateKey` - private key used to decrypt given data
`capsule` - capsule to decrypt (Lockbox type is used)

#### generateReEncryptionKey
Re-encryption key is used to grant access from producer (Alice) to a reader (Bob).
Key is not secret and re-encryption can be performed by a possibly untrusted third-party (Carol or Chuck), Bob can then use his private key to decrypt the re-encrypted capsule.

```typescript
const capsuleWithSymmetricKey = encapsulate(sharedKeyA);
const capsule = capsuleWithSymmetricKey.capsule;

const reEncryptionKeyAB = cryptosdk.PRE.generateReEncryptionKey(privateKeyA.toHex(), sharedKeyB.toHex());
```

Getting re-encryption key out of Private key (Alice) and public key (Bob) using random private key generation

`fromPrivateKey` - alice private key
`toPublicKey` - bob public key


#### reEncrypt

```typescript
const chunk: Lockbox = cryptosdk.PRE.encrypt(
        keyPairA.public_key,
        data
);

const reEncryptionKey: string = cryptosdk.PRE.generateReEncryptionKey(
        keyPairA.private_key,
        keyPairB.public_key
);

const reencryptedLockbox: Lockbox = cryptosdk.PRE.reEncrypt(
        reEncryptionKey,
        chunk
);
```

Performs re-encryption (a.k.a transform encryption).

`reEncryptionKey` - re-encryption key
`data` - capsule data

### Lockbox scheme with PRE
Lockbox encryption scheme is designed to use any arbitrary cipher for encryption of large volumes of data and use PRE capsule to store the encryption key.
Currently, it's not used and **not completely implemented**.

#### lockboxEncrypt

```typescript
const data = Buffer.from('{"example":"JSON"}', 'utf8');
const chunk: cryptosdk.PRE.LockboxWithContent = cryptosdk.PRE.lockboxEncrypt(
  keyPairA.public_key,
  data
);
```

Performs encryption in lockbox mode.

`publicKey` - public key
`data` - data to encrypt


#### lockboxDecrypt

```typescript
const reEncryptionKey: string = cryptosdk.PRE.generateReEncryptionKey(
  keyPairB.private_key,
  keyPairA.public_key
);
const reencryptedLockbox: Lockbox = cryptosdk.PRE.reEncrypt(
  reEncryptionKey,
  chunk.lockbox
);
const decrypted = cryptosdk.PRE.lockboxDecrypt(
  keyPairB.private_key,
  reencryptedLockbox,
  chunk.content
);
```

Performs decryption in lockbox mode.

`privateKey` - private key used for decryption
`lockbox` - lockbox
`data` - data to decrypt

### PRE internal functions
#### symmetricKeyFromPoint

```typescript
const keyPair = KeyPair.generateKeyPair();
const publicKeyPoint = keyPair.getPublicKey().valueOf();
const symKey = symmetricKeyFromPoint('sha256', publicKeyPoint);
```

Transforms GroupElement (point on a curve) to symmetric key for given algorithm. Ingests the elliptic curve material into a hash, which is then used as symmetric key for AES encryption producing capsule's cipher.

`hashAlgo` - digest algorithm used for size align
`obj` - curve group element to transform


#### hashToScalar

```typescript

const publicKey1Hex = '05044700040120009409092b3a87bd95b7b7dec82ae342d53ab11908c104fcf412c7d6aa3f85cb3f01200063bf48d4d4272e9263ff43a12cfa9282d282738f60e3f3f956518656f893a200';
const publicKey2Hex = '05044700040120009bba8b0894e213936b1001ea9442a88becabb5f5270f3950426fef8641056fe6012000f37ed2e5209b6ec6dd6ecf277de9099e6949e44d77cbd5e811cbf6ccc8aaccd2';
        
const publicKey1 = PublicKey.fromHex(publicKey1Hex).valueOf();
const publicKey2 = PublicKey.fromHex(publicKey2Hex).valueOf();
const tmpHash = [publicKey1, publicKey2];
const hash = cryptosdk.PRE.hashToScalar(tmpHash);
```

Calculates hash from given array of Scalar/GroupElement inputs and transforms to Scalar.


#### encapsulate

```typescript
const keyPair = KeyPair.generateKeyPair();
const pubKey = PublicKey.fromHex(keyPair.public_key);
const capsuleWithSymmetricKey = cryptosdk.PRE.encapsulate(pubKey);
```

Making capsule out of given PublicKey and two temporary EC keys (generated internally), returning
symmetric key wrapped as a string object.

`publicKey` - public key to encapsulate


#### decapsulate

```typescript
const keyPair = KeyPair.generateKeyPair();
const privateKey = keyPair.getPrivateKey();
const originalSymmetricKey = capsuleWithSymmetricKey.symmetricKey;
const capsule = capsuleWithSymmetricKey.capsule;
const decapsulatedSymmetricKey = decapsulate(capsule, privateKey);
```

Decapsulate given capsule with provided private key, returns symmetric key.

`capsule` - capsule to decapsulate
`privateKey` - private key


#### decapsulateOriginal

```typescript
const capsule = Capsule.fromHex(capsuleHex);
const privateKey = PrivateKey.fromHex(privateKeyHex);
const key = cryptosdk.PRE.decapsulateOriginal(capsule, privateKey);
```

Decapsulate given capsule with producer's private key.

NOTE: Provided private key, should be the original key from keypair where Public Key was used to create capsule. If top-level decrypt() function is used it's auto-detected whether capsule was re-encrypted or not.

`capsule` - capsule to decapsulate
`privateKey` - private key


#### decapsulateReEncrypted

```typescript
const privateKey = PrivateKey.fromHex(privateKeyHex);
const capsule = ReEncryptedCapsule.fromHex(reCapsuleHex);
const key = cryptosdk.PRE.decapsulateReEncrypted(capsule, privateKey);
```

Decapsulate given re-encrypted capsule with reader's private key.

NOTE: Provided private key, should be the original key of recipient for whom re-encryption key was generated.  If top-level decrypt() function is used it's auto-detected whether capsule was re-encrypted or not.

`capsule` - re-encrypted capsule to decapsulate
`privateKey` - private key


#### reEncryptCapsule

```typescript
const capsuleWithSymmetricKey = encapsulate(sharedKeyA);
const capsule = capsuleWithSymmetricKey.capsule;

const reEncryptionKeyAB = cryptosdk.PRE.generateReEncryptionKey(privateKeyA.toHex(), sharedKeyB.toHex());
const reEncryptedCapsule = cryptosdk.PRE.reEncryptCapsule(
        capsule, ReEncryptionKey.fromHex(reEncryptionKeyAB)
);
```

Getting re-encryption capsule from given original capsule and re-encryption key

`capsule` - re-encrypted capsule to decapsulate
`rk` - re-ecnryption key


## crypto.RSA

#### generateKeyPair

```typescript
crypto.RSA.generateKeyPair(bytes?: number = 2048): KeyPair
```

Upon completion, return an object containing two strings, the public and private
key making up a new key pair.

Returns an object with `public_key` and `private_key` fields.

#### encrypt

```typescript
crypto.RSA.encrypt(public_key: string, data: string): string`
```

Encrypt the given data using the given public key, using RSA.  Both
`public_key` and `data` should be strings.

Upon completion, returns the encrypted data as a base64-encoded string.

Note that if can throw an Error with a "DATA_TOO_LARGE" exception if
the data is too large to be encrypted.

Note for Node: the encrypt method as first parameter, `public_key`, can accept pem encoded string of the key  or path to the pem file in the filesystem.

#### decrypt

```typescript
crypto.RSA.decrypt(private_key: nodeCrypto.RsaPrivateKey | string, encrypted_data: string): string
```

Decrypt the given encrypted data using the given private key, using RSA.  Both
`encrypted_data` should be string and `private_key` should be the following type `nodeCrypto.RsaPrivateKey | string`.

Upon completion, returns the encrypted data as a string.

Note for Node:  first parameter `private_key` of the decrypt method  can be `string` or `nodeCrypto.RsaPrivateKey`.

#### sign

```typescript
crypto.RSA.sign(private_key: PrivateKey | string, data: string): string
```

Sign a piece of data using the given private key.  This generates an SHA256
signature hash of the given data using the given private key. `data` should be `string` and `private_key` should be the following type `PrivateKey | string`.

Upon completion, returns the digital signature as a base64-encoded `string`.

#### verifySignature

```typescript
crypto.RSA.verifySignature(public_key: string, data: string, signature: string): boolean
```

Verify a previously-signed piece of data using the given public key.  The given
signature is verified as being generated using the private key associated with
the given public key and the given data.  All three parameters should be
strings.

Upon completion, returns a boolean indicating whether or not the verification
was successful.

Note for Node: the encrypt method as first parameter, `public_key`, can accept pem encoded string of the key  or path to the pem file in the filesystem.

## crypto.ED25519

We are using the following package here - https://sodium-friends.github.io/docs/

#### generateKeys

```typescript
interface Ed25519Keys {
  privateKey: string
  publicSigningKey: string
}

crypto.ED25519.generateKeys(privateKeyBase58?: string): Ed25519Keys
```

It will generate you a ED25519 keypair, if arguments privateKeyBase58 is send, it will create public key from it
and return the keypair.


#### signMessage

```typescript
crypto.ED25519.signMessage(message: string, privateKey: string): string
```

Signing a message with a secret/private key ED25519. Signed message is in Base58.

#### verifySignature

```typescript
crypto.ED25519.verifySignature(message: string, publicKey: string, signature: string): boolean
```

Verifies that the message was signed with the secret/private key.

#### getSharedSecretHex

```typescript
crypto.ED25519.getSharedSecretHex(privateKey: string, publicKey: string): string
```

Generates a shared secret, with secret/private key and public key. Secret and public key needs to either be the following: 
- Secret and public key needs to be converted to curve 25519.
- Secret key is ED25519 and public key is a scalar multiplication public key based on a secret ED25519 key.
Secret Key A and Public Key B will generate the same secret as Secret Key B and Public Key A.

#### sealedBox

```typescript
crypto.ED25519.sealedBox(message: string, publicKey: string): string
```

Encrypt the given message using the given public key. Public key here needs to be ED25519, function will
do the conversion to curve25519.

#### sealedBoxOpen

```typescript
crypto.ED25519.sealedBoxOpen(ciphertext: string, publicKey: string, privateKey: string): string
```

Decrypt the given ciphertext using the given public key and secret/private key. Keys here needs to be ED25519, function will
do the conversion to curve25519.

#### getPublicEncryptionKey

```typescript
crypto.ED25519.getPublicEncryptionKey(publicKey: string): string
```

Converts an ed25519 public key to curve 25519

#### getPrivateEncryptionKey

```typescript
crypto.ED25519.getPrivateEncryptionKey(privateKey: string): string
```

Converts an ed25519 secret/private key to curve 25519

#### getXPublicKey

```typescript
crypto.ED25519.getXPublicKey(secretKey: string): string
```

Creates a scalar multiplication public key based on a secret key.

#### deriveIntoED25519Key

```typescript
crypto.ED25519.deriveIntoED25519Key(secretKey: string, index: number, context: string): string
```

Creates a new ED25519 signing key, derived based on the secretKey, index and context. `secretKey` needs to be ED25519 private/secret key.

## crypto.Util

#### randomBytes

```typescript
crypto.Util.randomBytes(bytes: number): number[]
```

Generates an array of `num_bytes` cryptographically-random bytes.  Each array
entry will be an integer in the range 0..255.

#### bytesToUint8Array

```typescript
crypto.Util.bytesToUint8Array(bytes: number[]): Uint8Array
```

Convert an array of bytes into a Uint8Array.

#### uint8ArrayToBytes

```typescript
crypto.Util.uint8ArrayToBytes(uint8Array: Uint8Array): number[]
```

Convert a Uint8Array back into a regular array of number in the range 0..255.

#### bytesToString

```typescript
crypto.Util.bytesToString(bytes: number[]): string
```

Convert an array of bytes into a string.  Each byte in the array will
correspond to a single character with that ordinal value in the resulting
string.

#### stringToBytes

```typescript
crypto.Util.stringToBytes(rawString: string): number[]
```

Convert a string back into an array of bytes.  Each character in the string
corresponds to one byte in the returned array.

#### bytesToBase64

```typescript
crypto.Util.bytesToBase64(bytesArray: number[]): string
```

Convert an array of bytes into a base64-encoded string.

#### base64ToBytes

```typescript
crypto.Util.base64ToBytes(base64String: string): number[]
```

Convert a base64-encoded string back into an array of bytes.

#### bytesToHex

```typescript
crypto.Util.bytesToHex(bytesArray: number[]): string
```

Convert an array of bytes into a hex-encoded string.

#### hexToBytes

```typescript
crypto.Util.hexToBytes(hexString: string): number[]
```

Convert a hex-encoded string back into an array of bytes.

#### nodeHash

```typescript
crypto.Util.nodeHash(algorithm: string, data: string | NodeJS.ArrayBufferView): string;
```

Calculate the hash ( based on `algorithm` ) of the given data. `data` can be a string or a
Buffer like object, salt should be  string or NodeJS.ArrayBufferView.

Returns the hash as a hex-encoded string.

#### hashSHA512

```typescript
crypto.Util.hashSHA512(data: string | NodeJS.ArrayBufferView): string
```

Calculate the `SHA-512` hash of the given data.  `data` can be a string or a
Buffer like object.

Returns the hash as a hex-encoded string.

#### bytesToBase58

```typescript
crypto.Util.bytesToBase58(byteData: Uint8Array): string
```

Convert bytes into an base58 string

#### base58ToBytes

```typescript
crypto.Util.base58ToBytes(str: string): Uint8Array
```

Convert base58 string into bytes ( Uint8Array )

#### stringToUint8Array

```typescript
crypto.Util.stringToUint8Array(str: string): Uint8Array
```

Convert string into Uint8Array array

## Examples with encrypt / decrypt streams

```typescript
// encrypt the file
createReadStream('file path')
.pipe(encryptStream(password))
.on('error', handleError)
.pipe(createWriteStream('encrypted file path'))
.on('close', done)

// decrypt the file
createReadStream('encrypted file path')w
.pipe(decryptStream(password))
.on('error', handleError)
.pipe(createWriteStream('decrypted file path'))
.on('close', done)

// re-encrypt the file with different password
createReadStream('encrypted file path')
.pipe(decryptStream(password))
.on('error', handleError)
.pipe(encryptStream(newPassword))
.on('error', handleError)
.pipe(createWriteStream('reencrypted file path'))
.on('close', done)

```

#### using aws s3

```typescript
// encrypt the file and upload to s3 bucket

const encryptStream: stream.Transform =
  createReadStream('path to file') // some valid read stream
  .pipe(GIDCrypto.AES.encryptStream(password))

const params: aws.S3.Types.PutObjectRequest = {
  Body: encryptStream,
  Bucket: '<bucket>',
  Key: `<s3 file path>`,
}

await S3.upload(params).promise()

```

```typescript
// download decrypted file from s3

return new Promise((resolve, reject) => {

  const params: aws.S3.GetObjectRequest = {
    Bucket: '<bucket>',
    Key: `<path to entrypted file>`,
  }

  // some valid write stream
  const destinationStream = createWriteStream('/path/to/dec/file.ext')

  S3
    .getObject(params)
    .createReadStream()
    .pipe(GIDCrypto.AES.decryptStream(password))
    .on('error', reject)
    .pipe(destinationStream)
    .on('error', reject)
    .on('finish', resolve)
})

```

```typescript
// re-uploading encrypted file from one S3 bucket to another
// with on-the-fly re-encryption

const password: string = '<current password>'
const newPassword: string = '<new desired password>'

return new Promise((resolve, reject) => {

  // currently encrypted file on s3
  const downloadParams: aws.S3.GetObjectRequest = {
    Bucket: currentBucket,
    Key: `<path to encrypted file>`,
  }

  // decrypt and encrypt stream
  const reencStream: stream.Transform = S3
  .getObject(downloadParams)
  .createReadStream()
  .on('error', reject)
  .pipe(GIDCrypto.AES.decryptStream(password))
  .on('error', reject)
  .pipe(GIDCrypto.AES.encryptStream(newPassword))
  .on('error', reject)

  // upload params for re-encrypted file on different bucket
  const uploadParams: aws.S3.Types.PutObjectRequest = {
    Body: reencStream,
    Bucket: bucket2,
    Key: `<desired encrypted file path>`,
  }

  S3
  .upload(uploadParams)
  .promise()
  .then(resolve)
  .catch(reject)
})

```
