我正在尝试对要通过不安全通道发送或存储在不安全位置的文件进行安全加密。我使用充气城堡框架,我的代码是用scala编写的。我决定使用aes -256(更具体地说 - 具有 256 位块大小的 Rinjael,这就是原因)。似乎我可以使用任何 (128|160|192|256) 块长度的 Rinjael。
我无法正确理解整个过程概述。这是一个很好的答案,在这个问题中有一些特定于充气城堡的有用代码。但两者都给我留下了一些未回答的问题(下面的问题)。
所以这就是我理解工作流程的方式:
为了创建一个分组密码实例,我必须获得一个带有一些输出反馈的填充分组密码实例:
// create an instance of the engine val engine = new RijndaelEngine(bitLength) // wrap engine with some feedback-blocking cipher mode engine val ofb = new OFBBlockCipher(engine , bitLength) // wrap this with some padded-blocking cipher mode val cipher = new PaddedBufferedBlockCipher(ofb, new PKCS7Padding())
现在我必须
init()
在密码引擎上运行2.1。首先生成一个密钥,要做到这一点,这里建议的最佳解决方案是使用
Scrypt
从密码中派生一个秘密,而不是使用PBKDF2-HMAC-xxx
. 在关于 Scrypt 的俄罗斯维基百科文章中,据说 Scrypt的推荐参数如下:N = 16384, r = 8, p = 1
所以我编写了这段代码来生成密码:SCrypt.generate(password.getBytes(encoding), salt, 16384, 8, 1, bitLength / 8)
2.2. 这导致我需要盐。Salt应该是一个随机字节数组。这里的大多数答案使用8 个字节。所以我愿意
// helper method to get a bunch of random bytes def getRandomBytes(size: Int) = { val bytes = Array.ofDim[Byte](size) val rnd = new SecureRandom() rnd.nextBytes(bytes) bytes } // generate salt val salt = getRandomBytes(8)
2.3. 为了初始化密码,我们需要一个初始化向量(请看下面我的问题(2))。
val iv = getRandomBytes(bitLength / 8)
2.4. 现在我们准备初始化密码。
cipher.init(mode, params(password, salt, iv, bitLength))
问题:
- 盐的大小应该是多少?为什么这里的大多数受访者使用
8
字节,而不是更多? - IV的大小应该是多少?它应该与密码块大小相同是否正确?是喜欢从这里的密码中获取:
cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
还是像我一样随机? - 我需要盐和 IV 是否正确,或者我可以只使用其中一种?例如,使用随机 IV 作为盐。
- 主要问题:我必须将盐和 IV 传递给另一方,否则无法解密消息。我需要以某种方式通过未加密的通道。在加密消息(作为标头)之前添加两者是否安全?
提前致谢!