- Crypto library

2019-09-11 16:09

# Crypto library

In short:

```
async function testRSA() {
let packedKey = await (await io.openRead("../test/pregenerated_key.private.unikey")).allBytes();
let privateKey = new crypto.PrivateKey(packedKey);
let newPrivateKey = await crypto.PrivateKey.generate(4096);
// signing with assymmetric keys
let s1 = await privateKey.sign("data to sign");
let s2 = await privateKey.sign("data to sign!");
assert(!equalArrays(s1,s2));
assert(s1.length == 256);
let publicKey = privateKey.publicKey;
assert(await publicKey.verify("data to sign", s1));
assert(!await publicKey.verify("data to sign!", s1));
assert(await publicKey.verify("data to sign!", s2));
// encrypting with assymmetric keys
let plain = "go read THIS!";
let cipherText = await publicKey.encrypt(plain);
let plain1 = utf8Decode(await privateKey.decrypt(cipherText));
assert(plain == plain1);
// using symmetric key with ETA
let sk1 = new crypto.SymmetricKey();
let sk2 = new crypto.SymmetricKey();
assert(!equalArrays(sk1.packed, sk2.packed));
let sk11 = new crypto.SymmetricKey(sk1.packed);
assert(sk1.equals(sk11));
cipherText = sk1.etaEncrypt(plain);
assert(utf8Decode(sk11.etaDecrypt(cipherText)) == plain);
}
```

## Private keys

### Construct from the packed private key

```
let key = new crypto.PrivateKey(packed_uint8Array);
```

### Generate a new key

```
let key = await crypto.PrivateKey.generate(2048);
```

Genenerates synchronously new private key (in a separate thread) with a given bit sthrength that should be at least 2048 bits.

### Sign a string or the binary data

```
let signature = await key.sign(data[, hashType]);
```

`data`

could be either a string (then will be converted to utf8 bytes) or typed`Uint8Array`

.`hashType`

, defaults to sha3-256, could be any of:`crypto.SHA256, crypto.SHA512, crypto.SHA3_256, crypto.SHA3_384, crypto.SHA3_512`

.

**returns** the signature in form of `Uint8Array`

.

### Decrypting data

Decrypting data encrypted with corresponding public key:

```
let plainText = await key.decrypt(cipherText);
```

`cipherText`

:`Uint8Array`

with ecrnypted data.

**returns** the decrypted data as `Uint8Array`

.

**throws** (async) `crypto.Exception`

if `cipherText`

is corrupt so bad so can
not be decrypted. *Note that it is not guaranteed that the ciperText is properly
decrypted even if the promise resolves*. If the key does not match one used to
encrypt, the data could be arbitrary. The recommended way is to ecnrypt some
symmetric key with PublicKey, and use decrypted symmetric key to process the
data. Symmetric key provides safe authenticated encryption (AE) and allow to
effectively (e.g. fast) encypt also large data.

### Get packed private key

To obtain binary representation:

```
let packed = key.packed;
```

**returns** cached binary representation of a key as `Uint8Array`

.

### Get the address of the private key

```
let address1 = key.shortAddress;
let address2 = key.longAddress;
```

**returns** short or long `KeyAddress`

of the corresponding public key. Uses cache
for both key address and public key.

See also u8 KeyAddress.

## Public keys

### Construct from the packed public key

```
let key = new crypto.PublicKey(packed_uint8Array);
```

### Construct from the private key

```
let publicKey = privateKey.publicKey;
```

This propery is cached and can be effectively called multiple times.

### Verify a signature

```
let ok = await key.verify(data, signature[, hashType]);
```

`data`

: data to check the signature against. Could be either a string (then utf8 representatin will be used) or an`Uint8Array`

.`signature`

to check, should be obtained with`privateKey.sign()`

or like.`hashType`

: optional, should match one used when creating the signature, see`privateKey.sign()`

above.

**returns** true if the signature is valid, false in all other cases.

### Get the address of the public key

```
let address1 = key.shortAddress;
let address2 = key.longAddress;
```

**returns** short or long `KeyAddress`

. Uses cache
for both key address and public key.

See also U8 KeyAddress.

### Get the packed public key

To obtain binary representation:

```
let packed = key.packed;
```

**returns** cached binary representation of a key as `Uint8Array`

.

### Public key fingerprints

```
let fp = publicKey.fingerprints
```

## Symmetric keys

Universa symmetric keys provide robust authenticated encryption and decryption of arbitrary sized binary data. Note that these methods are synchronous (because they are fast). The actual processing is implemented in C++.

in short:

```
unit.test("symmetric keys", () => {
let plain = "go read THIS";
let sk1 = new crypto.SymmetricKey();
let sk2 = new crypto.SymmetricKey();
expect.notEqualArrays(sk1.packed, sk2.packed);
let sk11 = new crypto.SymmetricKey(sk1.packed);
expect.equal(sk1, sk11);
let cipherText = sk1.etaEncrypt(plain);
expect.equal(utf8Decode(sk11.etaDecrypt(cipherText)), plain);
expect.throws(crypto.Exception, () => sk2.etaDecrypt(cipherText));
});
```

If the data can't be encrypted (e.g. tampered or wrong key),
`key.etaDecrypt(cipherText)`

will raise `crypto.Exception`

.

## KeyAddress

See Java API for more on key addresses.

### Constructing KeyAddress

Usually, you get it from `publicKey.shortAddress`

, `publicKey.longAddress`

or corresponding properties of the provate key, which just get the public key
properties.

#### from packed binary

```
let keyAddress = new KeyAddress(packed);
```

`packed`

should be a`Uint8Array`

instance with binary packed data.

#### from string

String representation uses a special encoding, **safe58** to get non ambigous
representation of the binary packed form. The `packed`

property of the `KeyAddress`

returns a binary backed address.

```
let keyAddress = new KeyAddress(string);
```

`packed`

should be a valid string representation. Use`toString()`

to get it.

### String representation

```
let addressString = keyAddress.toString();
```

**returns** just as expected, Universa **safe58** represetnation of the `KeyAddress`

.

### Binary packed representation

```
let addressString = keyAddress.packed;
```

**returns** Universa binary represntation of the KeyAddress in the `Unit8Array`

form.

### Check the key is matching

```
let ska = publicKey.shortAddress;
let lka = publicKey.shortAddress;
assert(ska.match(publicKey));
assert(lka.match(publicKey));
```

## HashId

Pre-imported in `crypto`

package and as simple as:

```
// constructing from binary byte or a string, utf8 will be applied
let x = crypto.HashId.of("hello, world");
// from a binary digest
let y = crypto.HashId.withDigest(x.digest);
// from a base64 encoded digest
let z = crypto.HashId.withBase64Digest(x.base64);
// get the binary digest (Uint8Array)
console.log(x.digest);
// get the string digest (base64)
console.log(x.base64);
// Check digests are equal
assert(x.equals(y));
assert(z.equals(x));
```

## Hash functions

```
let binaryDigest = crypto.diegst(hashType, data);
```

Here is an example:

```
let dd = crypto.digest(crypto.SHA256, "hello, world");
assert(btoa(dd) == "Ccp+TqpuiunH0mEWcSkYSINkTQffuny/vEyKLgg2DVs=");
```

- data should be eqithe a binary
`Uint8Array`

instance or a string, in which case the UTF8 ecnoding will be applied.

**returns** binary digest, `Uint8Array`

.

Supported hash types as for now are:

`crypto.SHA256`

`crypto.SHA512`

`crypto.SHA3_256`

`crypto.SHA3_384`

`crypto.SHA3_512`

## Error reporting

In case of any errors the crypto module throws (or rejects) the `crypto.Exception`

class instances.