Source: crypto/aerogear.crypto.js

/* AeroGear JavaScript Library
* https://github.com/aerogear/aerogear-js
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
    AeroGear.Crypto is used to provide various crypto methods
    @status Experimental
    @class
    @augments AeroGear.Core
    @returns {object} agCrypto - The created Crypto Object
    @example
    // Create a AeroGear.Crypto Object

    var agCrypto = AeroGear.Crypto();
 */
AeroGear.Crypto = function() {

    if( !window.crypto || !window.crypto.getRandomValues ) {
        throw "Your browser does not support the Web Crypto API";
    }

    // Allow instantiation without using new
    if ( !( this instanceof AeroGear.Crypto ) ) {
        return new AeroGear.Crypto();
    }

    // Local Variables
    var privateKey, publicKey, IV, salt;

    /**
        Returns the value of the salt var
        @private
        @augments Crypto
        @returns {Object}
     */
    this.getSalt = function() {
        return salt;
    };
    /**
        Returns the value of the IV var
        @private
        @augments Crypto
        @returns {Object}
     */
    this.getIV = function() {
        return IV;
    };
    /**
        Returns the value of the private key var
        @private
        @augments Crypto
        @returns {Object}
     */
    this.getPrivateKey = function() {
        return privateKey;
    };

    /**
        Returns the value of the public key var
        @private
        @augments Crypto
        @returns {Object}
     */
    this.getPublicKey = function() {
        return publicKey;
    };

    // Method to retrieve random values
    /**
        Returns the random value
        @status Experimental
        @return {Number} - the random value
        @example
        // Random number generator:
        AeroGear.Crypto().getRandomValue();
    */
    this.getRandomValue = function() {
        var random = new Uint32Array( 1 );
        crypto.getRandomValues( random );
        return random[ 0 ];
    };
    // Method to provide key derivation with PBKDF2
    /**
        Returns the value of the key
        @status Experimental
        @param {String} password - master password
        @param {Number} providedSalt - salt provided to recreate the key
        @return {bitArray} - the derived key
        @example
        // Password encryption:
        AeroGear.Crypto().deriveKey( 'mypassword', 42 );
     */
    this.deriveKey = function( password, providedSalt ) {
        salt = providedSalt || ( salt ? salt : this.getRandomValue() );
        var utf8String = sjcl.codec.utf8String,
            count = 2048;
        return sjcl.misc.pbkdf2( password, utf8String.toBits( salt ), count );
    };

    // Method to provide symmetric encryption with GCM by default
    /**
        Encrypts in GCM mode
        @status Experimental
        @param {Object} options - includes IV (Initialization Vector), AAD
            (Additional Authenticated Data), key (private key for encryption),
            plainText (data to be encrypted)
        @return {bitArray} - The encrypted data represented by an array of bytes
        @example
        // Data encryption:
        var options = {
            IV: myIV,
            AAD: myAAD,
            key: mySecretKey,
            data: message
        };
        AeroGear.Crypto().encrypt( options );
     */
    this.encrypt = function( options ) {
        options = options || {};
        var gcm = sjcl.mode.gcm,
            key = new sjcl.cipher.aes ( options.key );

        IV = options.IV || ( IV ? IV : this.getRandomValue() ); // this will always use the value in options.IV if available
                                                                    // or it will check to see if the local var IV is not null/undefined
                                                                    // it that is there, then it uses it, else it gets a randomValue
                                                                    // what ever it uses,  it stores in the local var IV

        return gcm.encrypt( key, options.data, IV, options.aad, 128 );
    };

    // Method to provide symmetric decryption with GCM by default
    /**
        Decrypts in GCM mode
        @status Experimental
        @param {Object} options - includes IV (Initialization Vector), AAD
            (Additional Authenticated Data), key (private key for encryption),
            ciphertext (data to be decrypted)
        @return {bitArray} - The decrypted data
        @example
        // Data decryption:
        var options = {
            IV: myIV,
            AAD: myAAD,
            key: mySecretKey,
            data: ciphertext
        };
        AeroGear.Crypto().decrypt( options );
     */
    this.decrypt = function( options ) {
        options = options || {};
        var gcm = sjcl.mode.gcm,
            key = new sjcl.cipher.aes ( options.key );
        return gcm.decrypt( key, options.data, options.IV || IV, options.aad, 128 );
    };

    // Method to provide secure hashing
    /**
        Generates a hash output based on SHA-256
        @status Experimental
        @param {bitArray|String} data to hash.
        @return {bitArray} - Hash value
        @example
        // Data hashing:
        AeroGear.Crypto().hash( options );
     */
    this.hash = function( data ) {
        return sjcl.hash.sha256.hash( data );
    };

    // Method to provide digital signatures
    /**
        Sign messages with ECDSA
        @status Experimental
        @param {Object} options - includes keys (provided keys to sign the message),
            message (message to be signed)
        @return {bitArray} - Digital signature
        @example
        // Message sign:
        var options = {
            keys: providedKey,
            message: PLAIN_TEXT
        };
        AeroGear.Crypto().sign( options );
     */
    this.sign = function( options ) {
        options = options || {};
        var keys = options.keys || sjcl.ecc.ecdsa.generateKeys( 192 ),
            hash = sjcl.hash.sha256.hash( options.message );
        return keys.sec.sign( hash );
    };

    // Method to verify digital signatures
    /**
        Verify signed messages with ECDSA
        @status Experimental
        @param {Object} options - includes keys (provided keys to sign the message),
            message (message to be verified), signature (Digital signature)
        @return {bitArray} - Signature
        @example
        // Message validation
        var options = {
            keys: sjcl.ecc.ecdsa.generateKeys(192),
            signature: signatureToBeVerified
        };
        AeroGear.Crypto().verify( options );
     */
    this.verify = function ( options ) {
        options = options || {};
        var message = sjcl.hash.sha256.hash( options.message );
        return options.keys.pub.verify( message, options.signature );
    };

    // A pair of cryptographic keys (a public and a private key) used for asymmetric encryption
    /**
        Initialize the key pair with the keys provided
        @status Experimental
        @param {Object} prKey - private key
        @param {Object} pubKey - public key
        @returns {Object} the object containing the key pair
        @example
        AeroGear.Crypto().KeyPair();
     */
    this.KeyPair = function( prKey, pubKey ) {

        var keys, pub;

        if ( prKey && pubKey ) {
            privateKey = prKey;
            publicKey = pubKey;
        } else {
            keys = sjcl.ecc.elGamal.generateKeys( 192,0 );
            // kem - key encapsulation mechanism
            pub = keys.pub.kem();
            publicKey = pub.key;
            privateKey = keys.sec.unkem( pub.tag );
        }

        return this;
    };
};