Because of the rich content inside the library, and the active development and debugging, this article will be continously updated. The title indicates the version number. A chinese version is available.
0.1 enigma system
This library is a result of developing the enigma system. To understand this library, the enigma system is firstly briefly described. Enigma system is designed as a service running on embedded systems:
- For requests inputed from the outside of the embedded system via API, it
does following operations:
- display the request to the user, ask for approval, encrypt and/or sign the data within the request, and return the result to the outside.
- treat the input as ciphertext or signed plaintext from another enigma, decrypt the content and validate it, display the result to the user, and return the result to the outside under user approval.
- under request and user approval, transfer the identity public key to the outside.
- under request and user approval, improve an identity public key from other user.
- Besides, users are able to do following operations with interacting with IO
devices connected to the embedded system, e.g. keyboards, mouses, screens:
- manage(including listing, generating, deleting, importing, exporting) the stored identity public keys(public and secret) within the embedded system.
- edit the drafts for sending. When approving requests from the outside, use drafts to replace given data.
- view the received and stored decrypted data.
- edit and save a type of special drafts, which is the signature on the dentity keys of the others(named token).
Engima system serves as the core component of many communicating tools and protocols. For example, in cooperation with plugins in instant messaging softwares, it provides peer-to-peer(p2p) encryption. It may also works as an component of automatic doors. By signing the given challenge, user proves its identity to the door.
0.2 neoatlantis-crypto-js library
In developing the engima system, the author realized, that it is necessary to separate the cryptographic part of this system into one library, in which features like secure random generators, symmetric encryptions, asymmetric encryptions and signatures, hash functions are covered. The library covers also 2 data structures for constructing the engima system: identity key and message.
Another highlight point of this library is, considering that even though these 2 data structures are included, it is still not so easy to construct an enigma system since one have to deal with storage and the complex logic reading the ciphertext, there is an interface, which is in fact a nearly complete implementation of the enigma system. The job of programmers are therefore now only to ask the user with user interface with questions emitted from this library, and the output is there. Using this implementation, the programmer shall construct a complete or reduced engima system, retaining the compatibility.
In short, the neoatlantis-crypto-js library provides user not only the basic features doing cryptography, but also the rich logic prepared for peer-to-peer encryption.
0.3 list of features
Here is a complete list of features shipped together with this library.
- with algorithms of BLAKE2s、WHIRLPOOL、RIPEMD160,
- and use them to calculate MAC(Message Authentication Code) of some message,
- and use them to do PBKDF2 key derivation. There is however speed limitations.
- Encryption / Signature
- symmetrically. This library ships AES and Salsa20/20, but they are not exposed to end user. The symmetric cipher is constructed based upon these algorithms but there is more.
- asymmetrically. There is an implementation within this library of asymmetric ciphers, that is not compatible with any existing standards. These ciphers utilize ECDH and ECDSA. Beginning from the basic seed secret, it derives secrets for initializing ECDH and ECDSA. Notice that the ECDH are primarily used for exchanging keys. In our library, the public key used in ECDH is the public key, the peer key is attached to the ciphertext for constructing shared secrets, which is laterly used for encrypting the actually payload.
- enigma system
- A data structure of identity key. Identity key is constructed with a subject within 256 characters, a public key and a self-signature on the subject and the public key.
- A message data structure. A message data structure is either a payload,
or an envelope carrying an encrypted payload and information for
- Payload carries the signer, signature and the plaintext.
- Envelope carries the encrypted payload, the decryptor(fingerprint), and information for the decryptor(s) to recover the key, and a sign of compression.
- An abstract implementation of the enigma system
- Functionalities are called via API
- Functionalities are called using Q&A, parameters are asked, and exceptions are thrown.
- The user uses only a few logic to forward the question to the user, or answer them by themselve, and the task is completed.
- The storage, based on interfaces the same of localStorage, are managed by the implementation. The user needs only to maintain a localStorage.
- Acceleration modules
- based upon platforms running this library, these modules replaces some native features with interfaces provided by the platform.
- for example, use the
cryptolibrary from NodeJS to hash, or use the interface on a customized browser to do random numbers more securely.
- operate on ArrayBuffer, to concat, do XOR, test if equal, and reverse.
- generate random bytes.
- generate UUID.
- test variable types.
- (not complete) LZW compression.
- serialize and unserialize JSON with predefined data structures.
1 Basic knowledgements
1.1 Initializing the neoatlantis-crypto-js library
To initialize the library in NodeJS, use:
Use RequireJS in browsers:
Most of the time, the IOs are in format of
To read its content, use code like followings:
To construct an
2 Use the utilities
Utilities as functions are provided under
crypto.util. They are also used
by our library itself.
2.1 Obtain random data
The most common variant is obtaining random bytes of length n:
You may use following code to make the data more random.
touch function, you affect the internal state of the random generator
globally, although you have used
new to generate
rand. The random data are
more unpredictable after that. You can bind this event to user inputs like
mouse moves and keyboard types. The time of calling
touch affects the random
generator, not the type of your choosen input.
2.2 Dealing with ArrayBuffer
crypto.util.buffer, and process the
ArrayBuffer type of data.
XOR. To xor 2
ArrayBuffers with same
byteLength, use following code:
Concatenation. To get a comprised
ArrayBuffer, use following code:
If equal. To see if 2
ArrayBuffer are equal in content, use following code:
Reverse. Swap the first item with the last item, the second with the one before last, etc.
2.3 Test variable type
Use following code, to test if a variable is of a given type:
2.4 Encoding conversion
Use following code, to get a encoded output, with an input of a string or
2.5 UUID generation
Use following code, to get an UUID out of
2.6 Serialization and De-serialization
This library contains a serialization tool dealing with structured data. You may define a template of a structure, and fill with data, to get the serialized output, or reverse.
You have following choices to define a data structure:
- binary, byte streams.
shortBinarytakes one byte to save the length of stream, saves at most 255 bytes, and can be null.
binarytakes 2 bytes, saves at most 65535 bytes, allows null.
longBinarytakes 4 bytes, saves at most 2^32-1 bytes(about 4GB), can be null.
boolean, a boolean variable, takes one byte.
constant, sets a given
ArrayBufferinto the serialized result. Takes the same length of
constantin bytes. In deserialization, it will be asserted that a same field exists in the input, or an exception will be thrown.
enum, takes a selection of a predefined list. The list contains at most 255 items. Takes one byte in serialized result. During deserialization, the result will be translated into one string in the enumerate list.
datetime, takes a Date object as input. The resolution is one second. Takes 7 bytes in the result. Can record years from 0 to 65535.
- array, an array of binaries. Supports
array, respectively 255 and 65535 items. CAUTION:
2.6.1 Define a template for serialization
Use following code to define a serializing template:
Object. In the example,
signature are defined. When this template is used in
generating result, use such keys. But the key names are excluded from final
algorithm is a enum type.
_ is a constant.
Therefore when deserializing, it will be asserted that at
_ a defined value
could be read. This is used to distinguish an expected data structure at first
2.6.2 To serialize a piece of data
Use following code to serialize:
2.6.3 To deserialize a piece of data
Use following code, to deserialize from a given
Remember to handle possible exceptions during deserialization with try-catch. This happens when the data doesn’t match a given template.
The library provides an interface for doing hashes on data, for calculating MAC(Message Authentication Code), and for doing a slow PBKDF2. The internal implementation is done with Whirlpool algorithm, the output length can be configured from 1 byte to 64 bytes.
3.1 Calculate hashes of an ArrayBuffer
Use following code to calculate hashes of an
3.2 Calculate MAC of an ArrayBuffer
MAC(Message Authentication Code) is another hash with an external key input. You may use it to authenticate the integrity of a message against a known key.
3.3 PBKDF2 key derivation
PBKDF2 key derivation consumes computing resources, and can make a stronger key basing on a weaker password(from user input, for example). This may be useful against brute forces, or to improve the quality(randomness) of the key.
PBKDF2 algorithms calls internally MAC algorithms, as specified in 3.2. In such calls, the MAC algorithm are not configured to slice its results, they are called with full bytes output.
4 Symmetric Encryptions
This library provides a single symmetric encryption interface. By entering the key, the data can be encrypted or decrypted. ArrayBuffer of any length can be treated.
The symmetric encryption algorithm contains following steps. Take encryption as an example:
- choose a 10-bit salt
- derive intermediate keys from key at input for all actual algorithms
- use hash algorithms to calculate the MAC of plaintext(against a key produced in previous step) with a length of 6 bytes. It will be attached to plaintext at beginning.
- pad the result plaintext into a length which is the multiple of 16 bytes(RFC5652).
Then encrypt it first using
Salsa20/20 is used, using
AES-128 in ECB mode will not introduce its
security flaws. MAC is used to validate if a successful decryption.
To use symmetric encryptions:
5 Asymmetric Encryptions and Signatures
The asymmetric algorithms provides by this library are in suites. Their implementations and output formats are not obeying any existing standards.
Each suite of algorithm has a name. By specifying this name, you are specifying the actual algorithms for encryptions and signatures(as well as their parameters), and the hash algorithm before doing a signature. Thanks to this definition, each algorithm can be used to both encryption and signature.
And, as by design to ease the secret key management, the secret key of a user is always some random bytes that can be assigned outside the library. By specifying the secret key and the algorithm, the public key can be derived.
Currently supported suites of algorithms are listed as follows:
|Name||Encrypt Algorithm||Sign Algorithm||Hash Algorithm||Private Key Length(bit)|
|NECRAC256||ECDH/secp521r1||ECDSA/secp521r1||WHIRLPOOL||64 x 8 = 512|
|NECRAC192||ECDH/secp384r1||ECDSA/secp384r1||BLAKE2s||48 x 8 = 384|
|NECRAC128||ECDH/secp256k1||ECDSA/secp256r1||BLAKE2s||32 x 8 = 256|
|NECRAC112||ECDH/secp224r1||ECDSA/secp224r1||RIPEMD160||28 x 8 = 224|
|NECRAC96||ECDH/secp192r1||ECDSA/secp192k1||RIPEMD160||24 x 8 = 192|
By selecting any suite and initializing the asymmetric cipher instance, random inputs can be proceeded, aka be encrypted/decrypted/signed/verified.
5.1 Initializing an asymmetric cipher instance