Skip to content

UniversaBlockchain/minicrypto-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Important note

This project is no more supported, instead, we have created much improved version with similar interface: unicrypto npm package, see also unicrypto github page

We strongly encourage all users to migrate to it.

Sorry for inconveniente.

universa-js/universajs

Minimalistic Javascript library required to perform basic operations with Universa smart contracts and other objects.

Supports:

Installation

Node.js

For usage in an existing Node.js project, add it to your dependencies:

$ npm install universa-minicrypto

or with yarn:

$ yarn add universa-minicrypto

And use it with the following line wherever you need it:

const Universa = require('universa-minicrypto');

Web

In root folder of package run

npm install
npm run build

In folder dist there will be universa.min.js and boss.min.js. Also there will be *.LICENSE files.

Simply copy dist/universa.min.js to wherever you keep your vendor scripts and include it as a script:

<script src="path/to/universa.min.js"></script>

Usage

Universa Capsule tools

Sign capsule

const { Capsule } = Universa;

const newCapsuleBin = Capsule.sign(capsuleBin, privateKey); // Uint8Array

Extract signatures

const { Capsule } = Universa;

const signatures = Capsule.getSignatures(capsuleBin); // Array[Uint8Array]

Extract signature keys

const { Capsule } = Universa;

const publicKeys = Capsule.getSignatureKeys(capsuleBin); // Array[PublicKey]

Signed record

Pack data to signed record (Uint8Array) with key:

const { SignedRecord, decode64, PrivateKey } = Universa;

const payload = { ab: "cd" };
const nonce = decode64("abc");
const key = PrivateKey.unpack(privateKeyPacked);

const recordBinary = SignedRecord.packWithKey(key, payload, nonce); // Uint8Array

Unpack signed record:

const { SignedRecord, decode64, PrivateKey } = Universa;

const payload = { ab: "cd" };
const nonce = decode64("abc");
const key = PrivateKey.unpack(privateKeyPacked);

const recordBinary = SignedRecord.packWithKey(key, payload, nonce); // Uint8Array

const record = SignedRecord.unpack(recordBinary);

record.recordType === SignedRecord.RECORD_WITH_KEY; // true
record.nonce // nonce
record.payload // payload
record.key // PublicKey

Misc

Random byte array for given length

const { randomBytes } = Universa;
const bytes16 = randomBytes(16); // Uint8Array

HashId for binary data

const { hashId } = Universa;
const id = hashId(decode64("abc")); // Uint8Array

CRC32

const { crc32 } = Universa;
const digest = crc32(decode64("abc")); // Uint8Array

Converters

Convert byte array to hex string and back

    const { bytesToHex, hexToBytes } = Universa;
    const hexString = bytesToHex(uint8arr);  // String
    const bytesArray = hexToBytes(hexString); // Uint8Array

Convert plain text to bytes and back

  const { textToBytes, bytesToText } = Universa;
  const bytes = textToBytes("one two three"); // Uint8Array
  const text = bytesToText(bytes); // "one two three"

Convert bytes to base64 and back

const { encode64, encode64Short, decode64 } = Universa;
const bytes = decode64("abc"); // Uint8Array
const base64str = encode64(bytes); // String

// short representation of base64 string
const base64ShortString = encode64Short(bytes);

Convert bytes to base58 and back

const { encode58, decode58 } = Universa;
const bytes = decode58("abc"); // Uint8Array
const base58str = encode58(bytes); // String

SHA

Supports SHA256, SHA512, SHA1, SHA3(256, 384, 512)

Get instant hash value for given byte array

const { SHA } = Universa;

// sha3 identifiers: "3_256", "3_384", "3_512"
const sha256 = new SHA(256);

const resultBytes = sha256.get(textToBytes('somevalue')); // Uint8Array

Get hash value for large data

const { SHA } = Universa;
const sha512 = new SHA(512);

sha512.put(dataPart1); // dataPart1 is Uint8Array
sha512.put(dataPart2);
// .....
sha512.put(dataPartFinal);

const resultBytes = sha512.get(); // Uint8Array

Get hash value in HEX

const { SHA } = Universa;
const sha256 = new SHA(256);
const hexResult = sha256.get(textToBytes("one two three"), 'hex'); // String

HMAC

const { SHA, HMAC } = Universa;
const data = textToBytes('a quick brown for his done something disgusting');
const key = textToBytes('1234567890abcdef1234567890abcdef');

const sha256 = new SHA('256');
const hmac = new HMAC(sha256, key);
const result = hmac.get(data) // Uint8Array

PBKDF2

const { hexToBytes, pbkdf2, SHA } = Universa;

const derivedKey = pbkdf2(new SHA('256'), {
  rounds: 1, // number of iterations
  keyLength: 20,  // bytes length
  password: 'password',
  salt: hexToBytes('abc123')
}); // Uint8Array

RSA Pair, keys helpers

Private key unpack

const { PrivateKey, decode64, BigInteger } = Universa;

const bossEncodedKey = decode64(keyPacked64);

const privateKey1 = new PrivateKey('BOSS', bossEncodedKey);
const privateKey2 = PrivateKey.unpack(bossEncodedKey);
const privateKey3 = new PrivateKey('EXPONENTS', {
  e: new BigInteger(eHex, 16),
  p: new BigInteger(pHex, 16),
  q: new BigInteger(qHex, 16)
});

// Read password-protected key
const privateKey4 = new PrivateKey('BOSS', {
  bin: bossEncodedKey,
  password: "somepassword"
})
const privateKey5 = PrivateKey.unpack(bossEncodedKey, password);

Public key unpack

const { PublicKey, PrivateKey, decode64, BigInteger } = Universa;

const bossEncodedKey = decode64(keyPacked64);
const privateKey2 = new PrivateKey('BOSS', privateEncoded);

const publicKey1 = new PublicKey('BOSS', bossEncodedKey);
const publicKey2 = privateKey2.publicKey;
const publicKey3 = new PublicKey('EXPONENTS', {
  n: new BigInteger(nHex, 16),
  e: new BigInteger(eHex, 16),
});
const publicKey4 = PublicKey.unpack(bossEncodedKey);

Public key fingerprint

publicKey.fingerprint(); // fingerprint (Uint8Array)

Public key bit strength

publicKey.getBitStrength(); // number

Public key address

publicKey.address();               // short address (Uint8Array)
publicKey.shortAddress();          // short address (Uint8Array)
publicKey.address({ long: true }); // long address (Uint8Array)
publicKey.longAddress();           // long address (Uint8Array)

Check if given address is valid

const { PublicKey } = Universa;

PublicKey.isValidAddress(publicKey.address()) // true

// accepts base58 representation of address too
PublicKey.isValidAddress(addressBase58) // true

Generate private key

const { PrivateKey, PublicKey, createKeys } = Universa;

const options = { bits: 2048, e: 0x10001 };

createKeys(options, (err, pair) => {
  console.log(pair.publicKey instanceof PublicKey); // true
  console.log(pair.privateKey instanceof PrivateKey); // true
});

Private(public) key - export

const { PrivateKey } = Universa;
const bossEncodedKey = decode64(keyPacked64);

const priv = new PrivateKey('BOSS', bossEncodedKey);

const hashWithExponents = priv.pack('EXPONENTS'); // hash map with exponents
const bossEncoded = priv.pack('BOSS'); // Uint8Array

const bossEncodedPublic = priv.publicKey.packed;

Password-protected Private key export

// default pbkdf2 rounds = 160000
const bossEncoded = privateKey.pack("BOSS", "somepassword");

// use custom pbkdf2 rounds
const bossEncodedFast = privateKey.pack("BOSS", {
  password: "somepassword",
  rounds: 16000
});

Get type of key package. There are 4 types of what key binary package may contain.

AbstractKey.TYPE_PRIVATE - binary package of private key without password AbstractKey.TYPE_PUBLIC - binary package of public key without password AbstractKey.TYPE_PRIVATE_PASSWORD_V2 - binary package of private key with password (actual version) AbstractKey.TYPE_PRIVATE_PASSWORD_V1 - binary package of private key with password (deprecated version)

const { AbstractKey } = Universa;

const bossEncoded = privateKey.pack("BOSS", "somepassword");

AbstractKey.typeOf(bossEncoded) === AbstractKey.TYPE_PRIVATE_PASSWORD_V2 // true

KEY INFO

Contains information about Key and helper to match keys compatibility

Supported algorithms: RSAPublic, RSAPrivate, AES256

Supported PRF: HMAC_SHA1, HMAC_SHA256, HMAC_SHA512

const { KeyInfo} = Universa;
const keyInfo = new KeyInfo({
  algorithm: KeyInfo.Algorithm.AES256,
  tag: decode64("abc"), // Uint8Array
  keyLength: 32,        // Int
  prf: KeyInfo.PRF.HMAC_SHA256,
  rounds: 16000,        // number of iterations
  salt: decode64("bcd") // Uint8Array
});

Pack to BOSS

const packed = keyInfo.pack(); // Uint8Array

Read from BOSS

// bossEncoded is Uint8Array
const keyInfo = KeyInfo.unpack(bossEncoded); // KeyInfo

Check that this key can decrypt other key

const canDecrypt = keyInfo.matchType(otherKeyInfo); // boolean

Derived key from password

const derivedKey = keyInfo.derivePassword("somepassword"); // Uint8Array

SYMMETRIC KEY

Symmetric key: main interface to the symmetric cipher. This implementation uses AES256 in CTR mode with IV to encrypt / decrypt.

const { SymmetricKey } = Universa;

// Creates random key (AES256, CTR)
const symmetricKey = new SymmetricKey();

// Creates key by derived key (Uint8Array) and it's info (KeyInfo)
const symmetricKey2 = new SymmetricKey({
  keyBytes: derivedKey,
  keyInfo: keyInfo
});

// Creates key by derived key (Uint8Array)
const symmetricKey2 = new SymmetricKey({
  keyBytes: derivedKey
});

// Creates key by password (String) and number of rounds (Int). Salt is optional
// Uint8Array, null by default
const symmetricKey3 = SymmetricKey.fromPassword(password, rounds, salt);

Pack symmetric key (get derived key bytes)

const { SymmetricKey } = Universa;

// Creates random key (AES256, CTR)
const symmetricKey = new SymmetricKey();

const derivedKey = symmetricKey.pack(); // Uint8Array

Encrypt / decrypt data with AES256 in CRT mode with IV

// data is Uint8Array
const encrypted = symmetricKey.encrypt(data); // Uint8Array
const decrypted = symmetricKey.decrypt(encrypted); // Uint8Array

Encrypt / decrypt data with EtA using Sha256-based HMAC

// data is Uint8Array
const encrypted = symmetricKey.etaEncrypt(data); // Uint8Array
const decrypted = symmetricKey.etaDecrypt(encrypted); // Uint8Array

RSA OAEP/PSS

OAEP encrypt/decrypt

You can pass hash types with instances or with string types. Supported types for SHA: sha1 sha256 sha384 sha512 sha512/256 sha3_256 sha3_384 sha3_512

const privateKey; // some PrivateKey instance
const publicKey = privateKey.publicKey;

// encrypt data
const data = decode64("abc123");
const options = {
  seed: decode64("abcabc"), // optional, default none
  mgf1Hash: new SHA(512), // optional, default SHA(256)
  oaepHash: 'sha512' // optional, default SHA(256)
};
const encrypted = publicKey.encrypt(data, options);
const decrypted = privateKey.decrypt(encrypted, options);

encode64(data) === encode64(decrypted); // true

OAEP max encryption message length

const privateKey; // some PrivateKey instance
const publicKey = privateKey.publicKey;

// encrypt data
const options = {
  seed: decode64("abcabc"), // optional, default none
  mgf1Hash: 'SHA512', // optional, default SHA(256)
  oaepHash: 'SHA512' // optional, default SHA(256)
};

const maxLength = publicKey.encryptionMaxLength(options);

OAEP default hash

publicKey.DEFAULT_OAEP_HASH // SHA1 instance

MGF1 default hash

publicKey.DEFAULT_MGF1_HASH // SHA1 instance

PSS sign/verify

You can pass hash types with instances or with string types. Supported types for SHA: sha1 sha256 sha384 sha512 sha512/256 sha3_256 sha3_384 sha3_512

const privateKey; // some PrivateKey instance
const publicKey = privateKey.publicKey;

const options = {
  salt: decode64("abcabc"), // optional
  saltLength: null, // optional, numeric
  mgf1Hash: 'sha512', // optional, default SHA(256)
  pssHash: 'sha512' // optional, default SHA(256)
};

const message = 'abc123';

const signature = privateKey.sign(message, options);
const isCorrect = publicKey.verify(message, signature, options);
console.log(isCorrect); // true

Extended signature

Sign/verify

const { ExtendedSignature } = Universa;
const data = decode64("abcde12345");
const privateKey; // some PrivateKey instance
const publicKey = privateKey.publicKey;

const signature = privateKey.signExtended(data);
const es = publicKey.verifyExtended(signature, data);

const isCorrect = !!es;
console.log(es.created_at); // Date - signature created at
console.log(es.key); // Uint8Array - PublicKey fingerprint
console.log(ExtendedSignature.extractPublicKey(signature)); // PublicKey instance

BOSS

Encode/decode

const { Boss } = Universa;
const boss = new Boss();

const data = {
  a: decode64("abc")
  b: new Date(),
  c: [1, 2, 'test'],
  d: { a: 1 }
};

const encoded = boss.dump(data); // Uint8Array
const decoded = boss.load(encoded); // original data

Encode stream

const writer = new Boss.writer();

writer.write(0);
writer.write(1);
writer.write(2);
writer.write(3);

const dump = writer.get(); // Uint8Array

Decode stream

const reader = new Boss.reader(hexToBytes('00081018'));

const arg1 = reader.read(); // 0
const arg2 = reader.read(); // 1
const arg3 = reader.read(); // 2
const arg4 = reader.read(); // 3
const arg5 = reader.read(); // undefined

AES

Encrypt/decrypt

const { AES } = Universa;
const key = decode64("abc"); // 16 bytes for aes128, 32 bytes for aes256
const message = textToBytes('some text');

const aes256 = new AES(key);
const encrypted = aes256.encrypt(message);   // Uint8Array
const decrypted = aes256.decrypt(encrypted); // Uint8Array

Create bundle

Run in package root folder

npm install
npm run build

In folder dist there will be universa.min.js and boss.min.js. Also there will be *.LICENSE files.

Running tests

npm test

NOTES

node-forge has broken method for encoding bytes, it should be replaced with:

util.binary.raw.encode = function(bytes) {
  return bytes.reduce(function (data, byte) {
    return data + String.fromCharCode(byte);
  }, '');
};

About

Minimalistic JavaScript library to perform basic cryptographic operations with Universa smart contracts and other objects

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages