Kaynağa Gözat

adding method to export credentials

El RIDO 7 yıl önce
ebeveyn
işleme
9d2d7bde42

+ 52 - 0
js/privatebin.js

@@ -924,6 +924,58 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             };
         }
 
+        /**
+         * get PBKDF2 protected credentials for server to validate password
+         *
+         * @name   CryptTool.getCredentials
+         * @function
+         * @param  {string} key
+         * @param  {string} password
+         * @return {string} decrypted message, empty if decryption failed
+         */
+        me.getCredentials = async function(key, password)
+        {
+            let keyArray = stringToArraybuffer(key);
+            if (password.length > 0) {
+                let passwordArray = stringToArraybuffer(password),
+                    newKeyArray = new Uint8Array(keyArray.length + passwordArray.length);
+                newKeyArray.set(keyArray, 0);
+                newKeyArray.set(passwordArray, keyArray.length);
+                keyArray = newKeyArray;
+            }
+
+            // import raw key
+            const importedKey = await window.crypto.subtle.importKey(
+                'raw', // only 'raw' is allowed
+                keyArray.slice(16),
+                {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: keyArray.slice(0, 16), // salt used in HMAC
+                    iterations: 100000, // amount of iterations to apply
+                    hash: {name: 'SHA-256'} // can be "SHA-1", "SHA-256", "SHA-384" or "SHA-512"
+                },
+                importedKey,
+                {
+                    name: 'AES-GCM', // can be any supported AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH" or "HMAC")
+                    length: 256 // can be 128, 192 or 256
+                },
+                true, // the key can be exported
+                ['encrypt'] // we want to export it
+            );
+            return btoa(
+                arraybufferToString(
+                    await window.crypto.subtle.exportKey('raw', derivedKey)
+                )
+            );
+        }
+
         /**
          * compress, then encrypt message with given key and password
          *

+ 0 - 3
js/test/AttachmentViewer.js

@@ -4,9 +4,6 @@ var common = require('../common');
 describe('AttachmentViewer', function () {
     describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
         this.timeout(30000);
-        before(function () {
-            cleanup();
-        });
 
         jsc.property(
             'displays & hides data as requested',

+ 33 - 4
js/test/CryptTool.js

@@ -237,19 +237,48 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
         });
     });
 
+    describe('getCredentials', function () {
+        it('generates credentials with password', async function () {
+            const clean = jsdom();
+            window.crypto = new WebCrypto();
+            // choosen by fair dice roll
+            const key = atob('EqueAutxlrekNNEvJWB1uaaiwbk/GGpn4++cdk+uDMc='),
+                  // -- "That's amazing. I've got the same combination on my luggage."
+                  password = Array.apply(0, Array(6)).map((_,b) => b + 1).join('');
+            const credentials = await $.PrivateBin.CryptTool.getCredentials(
+                key, password
+            );
+            clean();
+            assert.strictEqual(credentials, 'JS8bJWFx1bAPI2LMxfWrw4AQ7cedNVl8UmjUd/pW7Yg=');
+        });
+
+        it('generates credentials without password', async function () {
+            const clean = jsdom();
+            window.crypto = new WebCrypto();
+            // choosen by fair dice roll
+            const key = atob('U844LK1y2uUPthTgMvPECwGyQzwScCwkaEI/+qLfQSE='),
+                  password = '';
+            const credentials = await $.PrivateBin.CryptTool.getCredentials(
+                key, password
+            );
+            clean();
+            assert.strictEqual(credentials, 'VfAvY7T9rm3K3JKtiOeb+B+rXnE6yZ4bYQTaD9jwjEk=');
+        });
+    });
+
     describe('getSymmetricKey', function () {
         this.timeout(30000);
-        var keys = [];
+        let keys = [];
 
         // the parameter is used to ensure the test is run more then one time
         jsc.property(
             'returns random, non-empty keys',
             'integer',
             function(counter) {
-                var clean = jsdom();
+                const clean = jsdom();
                 window.crypto = new WebCrypto();
-                var key = $.PrivateBin.CryptTool.getSymmetricKey(),
-                    result = (key !== '' && keys.indexOf(key) === -1);
+                const key = $.PrivateBin.CryptTool.getSymmetricKey(),
+                      result = (key !== '' && keys.indexOf(key) === -1);
                 keys.push(key);
                 clean();
                 return result;

+ 2 - 2
js/test/InitialCheck.js

@@ -22,7 +22,7 @@ describe('InitialCheck', function () {
                         '</body></html>'
                     );
                     $.PrivateBin.Alert.init();
-                    window.crypto = null;
+                    window.crypto = new WebCrypto();
                     const result1 = !$.PrivateBin.InitialCheck.init(),
                           result2 = !$('#errormessage').hasClass('hidden');
                     clean();
@@ -76,7 +76,7 @@ describe('InitialCheck', function () {
                     '</body></html>'
                 );
                 $.PrivateBin.Alert.init();
-                window.crypto = null;
+                window.crypto = new WebCrypto();
                 const result1 = $.PrivateBin.InitialCheck.init(),
                       result2 = isSecureContext === $('#httpnotice').hasClass('hidden');
                 clean();

+ 1 - 1
tpl/bootstrap.php

@@ -71,7 +71,7 @@ if ($MARKDOWN):
 endif;
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-Yq2HyT+H1PmQxCaDeh6E/ChOrTBSYsu8BuS4yb8UPHlyMVaxqSOtyfy6hx6vAsVT0G3bKeLRAuejhvPTOoz7fQ==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-GNjHU6N7D0xG0WHf1DSrJrGavV+ES+w2t0vgICKD2UJ6g40Y1W+3le0iX7GgC8G6ADBsepMSaEyh47a2adA2HA==" crossorigin="anonymous"></script>
 		<!--[if IE]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
 		<![endif]-->

+ 1 - 1
tpl/page.php

@@ -49,7 +49,7 @@ if ($MARKDOWN):
 endif;
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-Yq2HyT+H1PmQxCaDeh6E/ChOrTBSYsu8BuS4yb8UPHlyMVaxqSOtyfy6hx6vAsVT0G3bKeLRAuejhvPTOoz7fQ==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-GNjHU6N7D0xG0WHf1DSrJrGavV+ES+w2t0vgICKD2UJ6g40Y1W+3le0iX7GgC8G6ADBsepMSaEyh47a2adA2HA==" crossorigin="anonymous"></script>
 		<!--[if IE]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
 		<![endif]-->