如何将AESCrypt中的IV与JAVA和RUBY相匹配

我将加密ID和昵称放到数据库中。 但是当我需要在ruby中获取ID和昵称时会出现问题,因为ruby中的AESCrypt不起作用。

我认为问题是IV与ruby和java不一样

这是我用在java代码中(实际上在android中)

public class AESCrypt { private final Cipher cipher; private final SecretKeySpec key; private AlgorithmParameterSpec spec; public AESCrypt(String password) throws Exception { // hash password with SHA-256 and crop the output to 128-bit for key MessageDigest digest = MessageDigest.getInstance("SHA-256"); digest.update(password.getBytes("UTF-8")); byte[] keyBytes = new byte[16]; System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length); cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); key = new SecretKeySpec(keyBytes, "AES"); spec = getIV(); } public AlgorithmParameterSpec getIV() { byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; IvParameterSpec ivParameterSpec; ivParameterSpec = new IvParameterSpec(iv); return ivParameterSpec; } public String encrypt(String plainText) throws Exception { cipher.init(Cipher.ENCRYPT_MODE, key, spec); byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8")); String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8"); return encryptedText; } public String decrypt(String cryptedText) throws Exception { cipher.init(Cipher.DECRYPT_MODE, key, spec); byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT); byte[] decrypted = cipher.doFinal(bytes); String decryptedText = new String(decrypted, "UTF-8"); return decryptedText; } 

}

我需要解密ruby中的数据,所以我使用下面的代码

 require 'openssl' require 'base64' module AESCrypt def self.encrypt(message, password) Base64.encode64(self.encrypt_data(message.to_s.strip, self.key_digest(password), nil, "AES-256-CBC")) end def self.decrypt(message, password) base64_decoded = Base64.decode64(message.to_s.strip) self.decrypt_data(base64_decoded, self.key_digest(password), nil, "AES-256-CBC") end def self.key_digest(password) OpenSSL::Digest::SHA256.new(password).digest end def self.decrypt_data(encrypted_data, key, iv, cipher_type) aes = OpenSSL::Cipher::Cipher.new(cipher_type) aes.decrypt aes.key = key aes.iv = "0000000000000000" aes.update(encrypted_data) + aes.final end def self.encrypt_data(data, key, iv, cipher_type) aes = OpenSSL::Cipher::Cipher.new(cipher_type) aes.encrypt aes.key = key aes.iv = "0000000000000000" aes.update(data) + aes.final end end 

如何将ruby中的IV与Java相匹配? 这是一个IV问题吗?

此代码存在许多问题:

  1. 将初始化向量初始化为16个字节的0 。 不幸的是,这被推荐在互联网上的许多地方,但它违背了IV的目的 – 一个随机和不可预测的值来播种Cipher Block Chain 操作模式 。 此值不需要保密 (即您可以将其添加到密文并通过明确的通道进行传输),但对于使用相同密钥加密的每个值,它必须是随机唯一的。
    • 你不仅会在类构造过程中产生静态IV,所以即使你要修改getIV()的代码以返回一个随机的IV,它对于由这个类加密的所有值都是常量; 再一次,打败了目的。
  2. 你的密钥推导函数(KDF)很弱 – 很弱,与防止暴力攻击无关。 一个强大的解决方案就像bcryptscryptPBKDF2 with HMAC/SHA-256 。 我假设这段代码仅用于演示/学习
  3. 在您的Ruby代码中, encryptdecrypt方法接受未使用的iv参数。 而是将一个常量字符串值分配给密码IV。 您应该将该字符串值的字节值分配给IV (请参阅下面的示例代码)。
  4. 看来你正在实现“绿地”开发 – 即这个代码不必向后兼容一些现有的实现,因为你正在编写Java和Ruby客户端。 我建议从经过validation的密码开始吗? “使用关联数据进行身份validation加密”(AEAD)是必要的,以避免密文操作和未授权密文的解密。 这可能导致恶意行为者通过暴力强制填充oracle进行数据损坏或数据解密。 长话短说 – 有人可以更改系统中存储的信息或拦截并恢复明文。 考虑AES / GCM (伽罗瓦/计数器模式),或者如果您需要使用AES / CBC,添加HMAC / SHA-256结构,其中MAC是密文, 而不是明文
  5. 密码学是一个学习,好奇和探索非常必要和有价值的领域。 但是,它也非常危险,因为在保护敏感数据时必须使用加密。 很容易偶然发现似乎正确的魔术咒语组合以使某些东西起作用,但它很容易受到旁道攻击,定时攻击,密钥泄漏,选择明文或密文攻击或填充神谕的影响。 如果您使用它来保护您关心的数据(客户,用户,财务,PII等),请不要自己编写此代码。 加密的第一条规则是不这样做 。 滚 。 你自己的加密 。 使用由专家编写的可信,经过validation的强大库,并定期更新以确保减轻任何漏洞。 BouncyCastle或KeyCzar for Java和NaCL for Ruby是强烈推荐和经过充分测试的。

下面是示例代码(取自Apache NiFi测试资源并针对此示例进行了修改),它使用您正在使用的相同KDF并加密和解密简单消息。 注意注释行将生成随机IV并将其用于更安全的操作。 有关Ruby中字节操作的更多信息(即("\0" * 16).unpack('c*').pack('s*') )请参阅Ruby中的字节操作 。

 #!/usr/bin/env ruby # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'openssl' def bin_to_hex(s) s.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join end plaintext = "This is a plaintext message." puts "Plaintext: #{plaintext}" cipher = OpenSSL::Cipher.new 'AES-128-CBC' cipher.encrypt # iv = cipher.random_iv # This creates a string of 16 0x00 bytes iv = ("\0" * 16) key_len = cipher.key_len digest = OpenSSL::Digest::SHA256.new key = digest.digest(plaintext)[0..15] puts "" puts " IV: #{bin_to_hex(iv)} #{iv.length}" puts " Key: #{bin_to_hex(key)} #{key.length}" cipher.key = key cipher.iv = iv # Now encrypt the data: encrypted = cipher.update plaintext encrypted << cipher.final puts "Cipher text length: #{encrypted.length}" puts "Cipher text: #{bin_to_hex(encrypted)}" cipher.decrypt cipher.iv = iv cipher.key = key decrypted = cipher.update encrypted decrypted << cipher.final puts "Plaintext length: #{decrypted.length}" puts "Plaintext: #{decrypted}" 

结果输出:

 $ ./openssl_aes.rb Plaintext: This is a plaintext message. IV: 00000000000000000000000000000000 16 Key: c72943d27c3e5a276169c5998a779117 16 Cipher text length: 32 Cipher text: 4f6ab6c5a6c628693f77aa9e2c63b3c5366f433fcad9fbd623510c2ba517381f Plaintext length: 28 Plaintext: This is a plaintext message. 

您现在可以将此数据反馈到Java类中(请注意Ruby输出是hex编码的,而不是Base64)以进行validation。