El RIDO 7 лет назад
Родитель
Сommit
4c3fb3fe63
3 измененных файлов с 61 добавлено и 80 удалено
  1. 59 78
      js/privatebin.js
  2. 1 1
      tpl/bootstrap.php
  3. 1 1
      tpl/page.php

+ 59 - 78
js/privatebin.js

@@ -693,35 +693,23 @@ jQuery.PrivateBin = (function($, RawDeflate) {
         }
 
         /**
-         * compress, then encrypt message with given key and password
+         * derive cryptographic key from key string and password
          *
-         * @name   CryptTool.cipher
+         * @name   CryptTool.deriveKey
          * @async
          * @function
+         * @private
+         * @param  {string} mode of AES (ctr, cbc, cmac, gcm, cfb, kw)
          * @param  {string} key
          * @param  {string} password
-         * @param  {string} message
-         * @return {string} data - JSON with encrypted data
+         * @param  {string} salt used in HMAC
+         * @param  {int} iterations amount to apply
+         * @param  {int} keysize (128, 192 or 256)
+         * @return {CryptoKey} derived key
          */
-        me.cipher = async function(key, password, message)
+        async function deriveKey(mode, key, password, salt, iterations, keysize)
         {
-            // AES in Galois Counter Mode, keysize 256 bit, authentication tag 128 bit, 10000 iterations in key derivation
-            const iv     = getRandomBytes(16),
-                  salt   = getRandomBytes(8);
-            let object   = {
-                    iv:     btoa(iv),
-                    v:      1,
-                    iter:   10000,
-                    ks:     256,
-                    ts:     128,
-                    mode:   'gcm',
-                    adata:  '', // if used, base64 encode it with btoa()
-                    cipher: 'aes',
-                    salt:   btoa(salt)
-                },
-                keyArray = StrToArr(key);
-            const algo   = 'AES-' + object.mode.toUpperCase();
-
+            let keyArray = StrToArr(key);
             if ((password || '').trim().length > 0) {
                 keyArray += await window.crypto.subtle.digest(
                     {name: 'SHA-256'},
@@ -739,33 +727,61 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             );
 
             // derive a stronger key for use with AES
-            const derivedKey = await window.crypto.subtle.deriveKey(
+            return await window.crypto.subtle.deriveKey(
                 {
                     name: 'PBKDF2', // we use PBKDF2 for key derivation
-                    salt: StrToArr(atob(object.salt)), // salt used in HMAC
-                    iterations: object.iter, // amount of iterations to apply
+                    salt: StrToArr(atob(salt)), // salt used in HMAC
+                    iterations: iterations, // amount of iterations to apply
                     hash: {name: 'SHA-256'} // can be "SHA-1", "SHA-256", "SHA-384" or "SHA-512"
                 },
                 importedKey,
                 {
                     // can be any supported AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH" or "HMAC")
-                    name: algo,
-                    length: object.ks // can be 128, 192 or 256
+                    name: 'AES-' + mode.toUpperCase(),
+                    length: keysize // can be 128, 192 or 256
                 },
                 false, // the key may not be exported
                 ['encrypt'] // we may only use it for decryption
             );
+        }
+
+        /**
+         * compress, then encrypt message with given key and password
+         *
+         * @name   CryptTool.cipher
+         * @async
+         * @function
+         * @param  {string} key
+         * @param  {string} password
+         * @param  {string} message
+         * @return {string} data - JSON with encrypted data
+         */
+        me.cipher = async function(key, password, message)
+        {
+            // AES in Galois Counter Mode, keysize 256 bit, authentication tag 128 bit, 10000 iterations in key derivation
+            const iv     = getRandomBytes(16);
+            let object   = {
+                    iv:     btoa(iv),
+                    v:      1,
+                    iter:   10000,
+                    ks:     256,
+                    ts:     128,
+                    mode:   'gcm',
+                    adata:  '', // if used, base64 encode it with btoa()
+                    cipher: 'aes',
+                    salt:   btoa(getRandomBytes(8))
+                };
 
             // finally, encrypt message
             const encrypted = await window.crypto.subtle.encrypt(
                 {
                     // can be any supported AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH" or "HMAC")
                     name: algo,
-                    iv: StrToArr(atob(object.iv)), // the initialization vector you used to encrypt
+                    iv: StrToArr(iv), // the initialization vector you used to encrypt
                     additionalData: StrToArr(atob(object.adata)), // the addtional data you used during encryption (if any)
                     tagLength: object.ts // the length of the tag you used to encrypt (if any)
                 },
-                derivedKey,
+                await deriveKey(object.mode, key, password, object.salt, object.iter, object.ks),
                 StrToArr(compress(message)) // compressed plain text to encrypt
             );
             object.ct = btoa(ArrToStr(encrypted));
@@ -786,56 +802,21 @@ jQuery.PrivateBin = (function($, RawDeflate) {
         me.decipher = async function(key, password, data)
         {
             try {
-                let keyArray = StrToArr(key);
-                if ((password || '').trim().length > 0) {
-                    keyArray += await window.crypto.subtle.digest(
-                        {name: 'SHA-256'},
-                        StrToArr(password)
-                    );
-                }
-
-                // import raw key
-                const object = JSON.parse(data),
-                      algo   = 'AES-' + object.mode.toUpperCase(),
-                      importedKey = await window.crypto.subtle.importKey(
-                        'raw', // only 'raw' is allowed
-                        keyArray,
-                        {name: 'PBKDF2'}, // we use PBKDF2 for key derivation
-                        false, // the key may not be exported
-                        ['deriveKey'] // we may only use it for key derivation
-                      );
-
-                // derive a stronger key for use with AES
-                const derivedKey = await window.crypto.subtle.deriveKey(
-                    {
-                        name: 'PBKDF2', // we use PBKDF2 for key derivation
-                        salt: StrToArr(atob(object.salt)), // salt used in HMAC
-                        iterations: object.iter, // amount of iterations to apply
-                        hash: {name: 'SHA-256'} // can be "SHA-1", "SHA-256", "SHA-384" or "SHA-512"
-                    },
-                    importedKey,
-                    {
-                        // can be any supported AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH" or "HMAC")
-                        name: algo,
-                        length: object.ks // can be 128, 192 or 256
-                    },
-                    false, // the key may not be exported
-                    ['decrypt'] // we may only use it for decryption
-                );
-
-                // finally, decrypt message
-                const decrypted = await window.crypto.subtle.decrypt(
-                    {
-                        // can be any supported AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH" or "HMAC")
-                        name: algo,
-                        iv: StrToArr(atob(object.iv)), // the initialization vector you used to encrypt
-                        additionalData: StrToArr(atob(object.adata)), // the addtional data you used during encryption (if any)
-                        tagLength: object.ts // the length of the tag you used to encrypt (if any)
-                    },
-                    derivedKey,
-                    StrToArr(atob(object.ct)) // cipher text to decrypt
+                const object = JSON.parse(data);
+                return decompress(
+                    ArrToStr(
+                        await window.crypto.subtle.decrypt(
+                            {
+                                name: algo, // can be any supported AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH" or "HMAC")
+                                iv: StrToArr(atob(object.iv)), // the initialization vector you used to encrypt
+                                additionalData: StrToArr(atob(object.adata)), // the addtional data you used during encryption (if any)
+                                tagLength: object.ts // the length of the tag you used to encrypt (if any)
+                            },
+                            await deriveKey(object.mode, key, password, object.salt, object.iter, object.ks),
+                            StrToArr(atob(object.ct)) // cipher text to decrypt
+                        )
+                    )
                 );
-                return decompress(ArrToStr(decrypted));
             } catch(err) {
                 return '';
             }

+ 1 - 1
tpl/bootstrap.php

@@ -70,7 +70,7 @@ if ($MARKDOWN):
 endif;
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.7.js" integrity="sha512-VnKJHLosO8z2ojNvWk9BEKYqnhZyWK9rM90FgZUUEp/PRnUqR5OLLKE0a3BkVmn7YgB7LXRrjHgFHQYKd6DAIA==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-kn3yqj5KEEjhNS3Z/2WZT/e9vLtpxOXmeBbn1liPgw8EUvlSbDLdrSbcGKrDX16Zochji2pDMNMZOTLuTm9CFA==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-JNheFJ1QBN8s4U4lfDXguGVvnqJtrnt508Ew5PgAKWOTA2osRDgDJJYViz/A7XEd1NVAafN/qMDnIz/oqJkH/g==" crossorigin="anonymous"></script>
 		<!--[if lt IE 10]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->

+ 1 - 1
tpl/page.php

@@ -48,7 +48,7 @@ if ($MARKDOWN):
 endif;
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.7.js" integrity="sha512-VnKJHLosO8z2ojNvWk9BEKYqnhZyWK9rM90FgZUUEp/PRnUqR5OLLKE0a3BkVmn7YgB7LXRrjHgFHQYKd6DAIA==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-kn3yqj5KEEjhNS3Z/2WZT/e9vLtpxOXmeBbn1liPgw8EUvlSbDLdrSbcGKrDX16Zochji2pDMNMZOTLuTm9CFA==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-JNheFJ1QBN8s4U4lfDXguGVvnqJtrnt508Ew5PgAKWOTA2osRDgDJJYViz/A7XEd1NVAafN/qMDnIz/oqJkH/g==" crossorigin="anonymous"></script>
 		<!--[if lt IE 10]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->