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 typedUint8Array
.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 anUint8Array
.signature
to check, should be obtained withprivateKey.sign()
or like.hashType
: optional, should match one used when creating the signature, seeprivateKey.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 aUint8Array
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. UsetoString()
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.