Crypto JS:你能在文件大小不呈指数增长的情况下放慢解密速度吗?
Crypto JS: Can you slow down decryption, without an exponential file size increase?
我有以下内容:
let original = 'something'
let passphrase = uuidv4()
// will take place on the server
let encrypted = CryptoJS.AES.encrypt(original, passphrase)
// will take place on the browser
// I want this part to take ≈ 10 minutes *minimum*
let decrypted = CryptoJS.AES.decrypt(encrypted, passphrase)
我尝试了一种迭代方法。控制所需的解密迭代意味着您还可以在一定程度上控制解密时间:
// increase this until we reach the desired decryption time on the browser
let numberOfEncryptions = 2
// will take place on the server
let encrypted = CryptoJS.AES.encrypt(original, passphrase).toString()
let i = 0
while (i < numberOfEncryptions) {
encrypted = CryptoJS.AES.encrypt(encrypted, passphrase).toString()
i++
}
// will take place on the browser:
let decrypted = CryptoJS.AES.decrypt(encrypted, passphrase).toString(CryptoJS.enc.Utf8)
i = 0
while (i < numberOfEncryptions) {
decrypted = CryptoJS.AES.decrypt(decrypted, passphrase).toString(CryptoJS.enc.Utf8)
i++
}
await checkWithServer(decrypted) // returns true
结果令人失望。
增加服务器上的加密数量也会增加浏览器上的解密时间,这很好,因为这就是我想要的。
但它也会以指数方式增加加密文件的大小,这很可怕,因为用户不可能下载这么大的文件来解密它。
还有其他解决方案吗?
更新:
@SlavaKnyazev 建议我应该改为加密用于加密数据的密码并向最终用户发送 提示 以便他们暴力破解密码。
用户无需花时间解密数据本身,而是花时间暴力破解密码。
这就是我尝试实现它的方式(作为测试):
const KEY = 'ab' // uuidv4()
const dataToEncrypt = 'The Message'
const md5key = CryptoJS.MD5(KEY).toString()
const encrypted = CryptoJS.AES.encrypt(dataToEncrypt, md5key)
const sha1keyHint = CryptoJS.SHA1(KEY).toString()
let pool = 'abcdefghijklmnopqrstuvwxyz'.split('')
let before = Date.now()
let after
let md5keyFromHint
bruteForce(pool, (value) => {
if(CryptoJS.SHA1(value).toString() === sha1keyHint) {
md5keyFromHint = CryptoJS.MD5(value).toString()
after = Date.now()
console.log(`KEY is ${value}`)
console.log(`Found after ${(after - before) / 1000} seconds`)
return true
}
return false
})
const decrypted = CryptoJS.AES.decrypt(encrypted, md5keyFromHint).toString(CryptoJS.enc.Utf8)
console.log(dataToEncrypt === decrypted) // returns true
我发现 KEY
必须相当“简单”,而不是我最初认为的 uuidv4()
。否则,它可能需要永远。另外,我使用的暴力破解方法需要一个字符“池”来查看,我想池越大,花费的时间就越长。
我的问题又是用户不会花时间解密实际数据。所以感觉像 PoW,即伪造它。
但我会考虑这次回答的问题,并且会在这里停止。 :-)
我最初的目标显然是不可能的。感谢您的帮助。
不要给出密钥,给出密钥的散列。暴力破解的密钥长度将为您提供所需的粒度。
加密过程:
- 生成密钥(例如:hunter2)并使用它加密您的数据。
- Hash hunter2 使用 SHA1 等算法 (f3bbbd66a63d4bf1747940578ec3d0103530e21d)
- 让客户端暴力破解密钥
密钥越长,找到它所需的时间就越长,而有效负载的大小保持不变。
然而,这有一个缺陷 -- 暴力破解不是必需的,因为暴力破解 AES 加密将同样简单。这也可以通过使密钥成为散列来加盐来解决。
不使用“hunter2”加密您的数据,而是使用 MD5(hunter2)
(使用不同的算法)。
在散列中加入一些盐以防止彩虹表的有效使用。
伪代码:
// Encrypt
let key = "password";
let aesKey = md5(password);
let hint = sha1(password);
let encryptedData = data.encrypt(aesKey);
let decryptedData = data.decrypt(md5(bruteForceSha1(hint));
我有以下内容:
let original = 'something'
let passphrase = uuidv4()
// will take place on the server
let encrypted = CryptoJS.AES.encrypt(original, passphrase)
// will take place on the browser
// I want this part to take ≈ 10 minutes *minimum*
let decrypted = CryptoJS.AES.decrypt(encrypted, passphrase)
我尝试了一种迭代方法。控制所需的解密迭代意味着您还可以在一定程度上控制解密时间:
// increase this until we reach the desired decryption time on the browser
let numberOfEncryptions = 2
// will take place on the server
let encrypted = CryptoJS.AES.encrypt(original, passphrase).toString()
let i = 0
while (i < numberOfEncryptions) {
encrypted = CryptoJS.AES.encrypt(encrypted, passphrase).toString()
i++
}
// will take place on the browser:
let decrypted = CryptoJS.AES.decrypt(encrypted, passphrase).toString(CryptoJS.enc.Utf8)
i = 0
while (i < numberOfEncryptions) {
decrypted = CryptoJS.AES.decrypt(decrypted, passphrase).toString(CryptoJS.enc.Utf8)
i++
}
await checkWithServer(decrypted) // returns true
结果令人失望。
增加服务器上的加密数量也会增加浏览器上的解密时间,这很好,因为这就是我想要的。
但它也会以指数方式增加加密文件的大小,这很可怕,因为用户不可能下载这么大的文件来解密它。
还有其他解决方案吗?
更新:
@SlavaKnyazev 建议我应该改为加密用于加密数据的密码并向最终用户发送 提示 以便他们暴力破解密码。
用户无需花时间解密数据本身,而是花时间暴力破解密码。
这就是我尝试实现它的方式(作为测试):
const KEY = 'ab' // uuidv4()
const dataToEncrypt = 'The Message'
const md5key = CryptoJS.MD5(KEY).toString()
const encrypted = CryptoJS.AES.encrypt(dataToEncrypt, md5key)
const sha1keyHint = CryptoJS.SHA1(KEY).toString()
let pool = 'abcdefghijklmnopqrstuvwxyz'.split('')
let before = Date.now()
let after
let md5keyFromHint
bruteForce(pool, (value) => {
if(CryptoJS.SHA1(value).toString() === sha1keyHint) {
md5keyFromHint = CryptoJS.MD5(value).toString()
after = Date.now()
console.log(`KEY is ${value}`)
console.log(`Found after ${(after - before) / 1000} seconds`)
return true
}
return false
})
const decrypted = CryptoJS.AES.decrypt(encrypted, md5keyFromHint).toString(CryptoJS.enc.Utf8)
console.log(dataToEncrypt === decrypted) // returns true
我发现 KEY
必须相当“简单”,而不是我最初认为的 uuidv4()
。否则,它可能需要永远。另外,我使用的暴力破解方法需要一个字符“池”来查看,我想池越大,花费的时间就越长。
我的问题又是用户不会花时间解密实际数据。所以感觉像 PoW,即伪造它。
但我会考虑这次回答的问题,并且会在这里停止。 :-)
我最初的目标显然是不可能的。感谢您的帮助。
不要给出密钥,给出密钥的散列。暴力破解的密钥长度将为您提供所需的粒度。
加密过程:
- 生成密钥(例如:hunter2)并使用它加密您的数据。
- Hash hunter2 使用 SHA1 等算法 (f3bbbd66a63d4bf1747940578ec3d0103530e21d)
- 让客户端暴力破解密钥
密钥越长,找到它所需的时间就越长,而有效负载的大小保持不变。
然而,这有一个缺陷 -- 暴力破解不是必需的,因为暴力破解 AES 加密将同样简单。这也可以通过使密钥成为散列来加盐来解决。
不使用“hunter2”加密您的数据,而是使用 MD5(hunter2)
(使用不同的算法)。
在散列中加入一些盐以防止彩虹表的有效使用。
伪代码:
// Encrypt
let key = "password";
let aesKey = md5(password);
let hint = sha1(password);
let encryptedData = data.encrypt(aesKey);
let decryptedData = data.decrypt(md5(bruteForceSha1(hint));