试图解密来自Java的attr_encrypted存储值

我有一个rails应用程序,在其中一个模型中加密(使用attr_encrypted)2个字段。

我的流程的另一部分,不是Web应用程序需要使用此数据执行某些任务(明文)。

我正在尝试从数据库中读取存储的值并解密它们但不能……

我的模型看起来像这样:

class SecretData mysecret, :algorithm => "aes-256-cbc" attr_encrypted :data2, :key=>mysecret, :algorithm => "aes-256-cbc" ... end 

数据库字段(encrypted_data1和encrypted_data2)充满了数据但是当我尝试解码base64(attr_encrypted默认情况下这样做)并解密时(我尝试使用命令行中的openssl并使用Java)我得到了“恶魔数”(openssl)或关于密钥长度的各种错误(在Java中)。 我花了很多时间试图解密这些字符串但却找不到方法。

这是我拥有的所有数据:
encrypted + base64字符串(对于data1和data2)是:

 cyE3jDkKc99GVB8TiUlBxQ== sqcbOnBTl6yy3wwjkl0qhA== 

我可以从它们中解码base64并得到一些字节数组。 当我尝试:

 echo cyE3jDkKc99GVB8TiUlBxQ== | openssl aes-256-cbc -a -d (and type "mylittlesecret" as the password) 

我得到:“恶魔号”

当我尝试以下Java代码时:

 Key key = generateKey(); Cipher c = Cipher.getInstance(ALGO); c.init(Cipher.DECRYPT_MODE, key); byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); byte[] decValue = c.doFinal(decordedValue); String decryptedValue = new String(decValue); 

我得到“java.security.InvalidKeyException:无效的AES密钥长度:14个字节”
我已经尝试了很多Java代码的变体,所以可能是这个特定的一个是完全错误的..

当我尝试ruby时:

 irb(main):069:0> Encryptor.decrypt(Base64.decode64("cyE3jDkKc99GVB8TiUlBxQ=="), ,key=>'mylittlesecret') => "data1-value" 

我得到正确的解密值(如你所见)。

我还注意到,当我尝试在Java中加密相同的字符串并在Base64中编码时,我得到一个更长的字符串(在base64之后)。 不知道为什么,但它可能相关..

我以为我也应该有加密值的salt / iv,但是我没有看到它存储在任何地方..我试图加密相同的值两次并得到相同的输出字符串,所以它不是随机的。

有谁知道attr_encrypted(它使用ruby的加密器)如何加密数据以及如何在外部解密它?

好吧,多亏了owlstead,我能够解决这个问题。 我在ruby和Java中发布代码,以防将来有人需要它:

正如owlstead所提到的,问题确实存在于EVP_BytesToKey(密码和盐的密钥生成)中。 Ruby由于某种原因不使用标准的,因此Java(或openssl)无法解码。

这是一个使用标准方法的ruby实现:

 def self.encrypt(options) plaintext = options[:value] return true if plaintext.blank? cipher = OpenSSL::Cipher::Cipher.new(@@cipher_type) cipher.encrypt iv = cipher.random_iv salt = (0 ... @@salt_length).map{65.+(rand(25)).chr}.join # random salt key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(@@password, salt, @@pkbdf_num_iters, cipher.key_len) cipher.key = key cipher.iv = iv enc_data = cipher.update(plaintext) enc_data << cipher.final final_data = salt << iv << enc_data Base64.strict_encode64(final_data) end def self.decrypt(options) ciphertext = options[:value] return true if ciphertext.blank? cipher = OpenSSL::Cipher::Cipher.new(@@cipher_type) cipher.decrypt cipher_data = Base64.decode64(ciphertext) salt = cipher_data[0 .. @@salt_length-1] iv = cipher_data[@@salt_length .. @@salt_length+cipher.iv_len] enc_data = cipher_data[@@salt_length+cipher.iv_len .. -1] # the rest key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(@@password, salt, @@pkbdf_num_iters, cipher.key_len) cipher.key = key cipher.iv = iv plaintext = cipher.update(enc_data) plaintext << cipher.final plaintext end 

我设置了以下参数: - cipher_type = aes-128-cbc(Java仅支持128但开箱即用。除此之外,您需要安装一些额外的软件包) - salt_length = 8 - pkbdf_num_iters = 1024

这是用于解码的Java方法:

 public String decrypt(String ciphertext) throws Exception { byte[] crypt = Base64.decodeBase64(ciphertext); // parse the encrypted data and get salt and IV byte[] salt = Arrays.copyOfRange(crypt, 0, saltLength); byte[] iv = Arrays.copyOfRange(crypt, saltLength, saltLength + ivLength); byte[] encryptedData = Arrays.copyOfRange(crypt, saltLength + ivLength, crypt.length); // generate key from salt and password SecretKeyFactory f = SecretKeyFactory.getInstance(secretKeyName); KeySpec ks = new PBEKeySpec(password.toCharArray(), salt, pbkdfNumIters, keyLength); SecretKey s = f.generateSecret(ks); Key keySpec = new SecretKeySpec(s.getEncoded(),"AES"); // initialize the cipher object with the key and IV Cipher cipher = Cipher.getInstance(cipherAlgo); IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); // decrypt byte[] decBytes = cipher.doFinal(encryptedData); return new String(decBytes); } 

为我工作。

希望它有助于(或将会对某人......)

扎克

您将需要-nosalt来使用OpenSSL解密数据。 对于Java,您需要实现OpenSSL EVP_BytesToKey方法。 一个实现可以在Ola Bini的博客上找到。 感谢您将此置于公共领域,Ola。

  public static byte[][] EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) { byte[][] both = new byte[2][]; byte[] key = new byte[key_len]; int key_ix = 0; byte[] iv = new byte[iv_len]; int iv_ix = 0; both[0] = key; both[1] = iv; byte[] md_buf = null; int nkey = key_len; int niv = iv_len; int i = 0; if (data == null) { return both; } int addmd = 0; for (;;) { md.reset(); if (addmd++ > 0) { md.update(md_buf); } md.update(data); if (null != salt) { md.update(salt, 0, 8); } md_buf = md.digest(); for (i = 1; i < count; i++) { md.reset(); md.update(md_buf); md_buf = md.digest(); } i = 0; if (nkey > 0) { for (;;) { if (nkey == 0) break; if (i == md_buf.length) break; key[key_ix++] = md_buf[i]; nkey--; i++; } } if (niv > 0 && i != md_buf.length) { for (;;) { if (niv == 0) break; if (i == md_buf.length) break; iv[iv_ix++] = md_buf[i]; niv--; i++; } } if (nkey == 0 && niv == 0) { break; } } for (i = 0; i < md_buf.length; i++) { md_buf[i] = 0; } return both; }