<!doctype html>
<html>
    <head>
        <meta charset='UTF-8'>
    </head>
    <body>
        <div class='test'></div>
        <script type="text/javascript">
 
            function encrypt(data, keyJSON){
                var data = new TextEncoder("UTF-8").encode(data);
                var randomsKeys = geneRandomHexStr(64); // 128 bit keys
                var encryptedKey = hexStringToUint8Array(randomsKeys);
                var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
                return crypto.subtle.importKey("jwk", keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}},true, ['encrypt'])
                    .then(function(publicKey){
                        return crypto.subtle.encrypt({name: "rsa-oaep"}, publicKey, encryptedKey);
                    }).then(function(res){
                        encryptedKey = bytesToHexString(res)
                        // use aes to encrypt data
                        // import aes key
                        return crypto.subtle.importKey('raw', 
                            hexStringToUint8Array(randomsKeys) , aesAlgo, false, ['encrypt', 'decrypt']);
                         
                    }).then(function(result){
                        // use aes to encode
                        return crypto.subtle.encrypt(aesAlgo,
                         result, data);
                    }).then(function(encryptedData){
                        return Promise.resolve({
                            'encrypted': bytesToHexString(encryptedData),
                            'encryptedKey': encryptedKey,
                        });
                    });
 
                //console.log(new TextDecoder("UTF-8").decode(data));
                // use server public key to encrypt
                 
            }
 
            function decrypt(data, keyJSON){
                // use local private key to decrypt
                var encryptedKey = new hexStringToUint8Array(data.encryptedKey);
                var encryptedData = new hexStringToUint8Array(data.encrypted);
                var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
                // decrypt key
                return crypto.subtle.importKey('jwk', keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}}, true,
                    ['decrypt']).then(function(privateKey){
                        return crypto.subtle.decrypt({name: 'rsa-oaep'}, privateKey, encryptedKey);
                    }).then(function(decryptedKey){
                        // import aes key
                        return crypto.subtle.importKey('raw', 
                            decryptedKey, aesAlgo, false, ['encrypt', 'decrypt']);
                    }).catch(function(){
                        console.error("decrypt error");
                    }).then(function(result){
                        // decode encrypted data
                        return crypto.subtle.decrypt(aesAlgo, result, encryptedData);
                    }).then(function(data){
                        return Promise.resolve(new TextDecoder("UTF-8").decode(new Uint8Array(data)));
                    })
 
            }
 
            function createNewUserKey(){
                var algorithmKeyGen = {
                    name: "RSA-OAEP",
                    hash: {name: "sha-256"},
                    // RsaKeyGenParams
                    modulusLength: 2048,
                    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),  // Equivalent to 65537
                };
                var nonExtractable = false;
                 
                var publicKey = "";
                var privateKey = "";
                var keyPairs = "";
                return crypto.subtle.generateKey(algorithmKeyGen, true, ['encrypt', 'decrypt']).then(function(result) {
                    // gene key pair
                    keyPairs = result;
                    return Promise.all([crypto.subtle.exportKey("jwk", keyPairs.publicKey),
                        crypto.subtle.exportKey("jwk", keyPairs.privateKey)]);
                })
                 
            }
 
            function _arrayBufferToBase64( buffer ) {
                var binary = '';
                var bytes = new Uint8Array( buffer );
                var len = bytes.byteLength;
                for (var i = 0; i < len; i++) {
                    binary += String.fromCharCode( bytes[ i ] );
                }
                return window.btoa( binary );
            }
 
            function hexStringToUint8Array(hexString) {
                if (hexString.length % 2 != 0)
                    throw "Invalid hexString";
                var arrayBuffer = new Uint8Array(hexString.length / 2);
                for (var i = 0; i < hexString.length; i += 2) {
                    var byteValue = parseInt(hexString.substr(i, 2), 16);
                    if (byteValue == NaN)
                        throw "Invalid hexString";
                    arrayBuffer[i/2] = byteValue;
                }
                return arrayBuffer;
            }
 
            function bytesToHexString(bytes) {
                if (!bytes)
                    return null;
                bytes new Uint8Array(bytes);
                var hexBytes = [];
                for (var i = 0; i < bytes.length; ++i) {
                    var byteString = bytes[i].toString(16);
                    if (byteString.length < 2)
                        byteString = "0" + byteString;
                    hexBytes.push(byteString);
                }
                return hexBytes.join("");
            }
 
            function geneRandomHexStr(length){
                var text = "";
                var possible = "0123456789abcdef";
 
                forvar i=0; i < length; i++ )
                    text += possible.charAt(Math.floor(Math.random() * possible.length));
 
                return text;
            }
 
            createNewUserKey().then(function(keyPairs){
                encrypt("this is origin text", keyPairs[0]).then(function(res){
                    console.log('public', JSON.stringify(keyPairs[0]));
                    console.log('private', JSON.stringify(keyPairs[1]));
                    decrypt(res, keyPairs[1]).then(function(decrypted){
                        console.log('decrypted', decrypted);
                    });
                });
            })
 
        </script>
    </body>
</html>