Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
试图从Java解密attr_加密的存储值_Java_Ruby On Rails_Ruby_Encryption_Attr Encrypted - Fatal编程技术网

试图从Java解密attr_加密的存储值

试图从Java解密attr_加密的存储值,java,ruby-on-rails,ruby,encryption,attr-encrypted,Java,Ruby On Rails,Ruby,Encryption,Attr Encrypted,我有一个rails应用程序,它在其中一个模型中加密(使用attr_加密)2个字段 我的流程的另一部分不是web应用程序需要使用这些数据(纯文本)执行某些任务 我正试图从数据库中读取存储的值并对其进行解密,但就是做不到 我的模型如下所示: class SecretData < ActiveRecord::Base mysecret = "mylittlesecret" attr_encrypted :data1, :key=>mysecret, :algorithm =>

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

我的流程的另一部分不是web应用程序需要使用这些数据(纯文本)执行某些任务

我正试图从数据库中读取存储的值并对其进行解密,但就是做不到

我的模型如下所示:

class SecretData < ActiveRecord::Base
  mysecret = "mylittlesecret"

  attr_encrypted :data1, :key=>mysecret, :algorithm => "aes-256-cbc"
  attr_encrypted :data2, :key=>mysecret, :algorithm => "aes-256-cbc"

  ...
end
我可以从他们两个解码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的Encryptor)是如何加密数据的吗?我应该如何从外部解密数据?

您需要
-nosalt
使用OpenSSL解密数据。对于Java,您需要一个OpenSSL
EVP\u BytesToKey
方法的实现。可以在上找到一个实现。谢谢你把这个公开,奥拉

    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;
    }
public static byte[]EVP_BytesToKey(int key_len,int iv_len,MessageDigest md,
字节[]盐,字节[]数据,整数计数){
字节[][]两者=新字节[2][];
字节[]键=新字节[键];
int key_ix=0;
字节[]iv=新字节[iv_len];
int iv_ix=0;
两个[0]=键;
两者[1]=iv;
字节[]md_buf=null;
int nkey=钥匙;
int niv=iv_len;
int i=0;
如果(数据==null){
两者都返回;
}
int addmd=0;
对于(;;){
md.reset();
如果(addmd++>0){
md.update(md_buf);
}
md.update(数据);
if(null!=salt){
md.update(salt,0,8);
}
md_buf=md.digest();
对于(i=1;i0){
对于(;;){
如果(nkey==0)
打破
如果(i==md_buf.长度)
打破
key[key_ix++]=md_buf[i];
恩基——;
i++;
}
}
如果(niv>0&&i!=总长度){
对于(;;){
如果(niv==0)
打破
如果(i==md_buf.长度)
打破
iv[iv_ix++]=md_buf[i];
niv--;
i++;
}
}
如果(nkey==0&&niv==0){
打破
}
}
对于(i=0;i
多亏了owlstead,我才解决了这个问题。我正在用ruby和Java发布代码,以防将来有人需要它:

正如owlstead提到的,问题确实存在于EVP_BytesToKey(从密码和salt生成密钥)中。出于某种原因,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
为我工作

希望它能帮助(或将帮助某人)


Zach

尝试openssl的
-nosalt
选项…首先,您好-非常感谢
我试过使用-nosalt,现在我得到了“坏解密140556892792480:错误:06065064:数字信封例程:EVP_decrypt最终_ex:坏解密:EVP_enc.c:539:”
试过用谷歌搜索它,发现了一些外观,但都没有帮我解决它(但再一次,我真的不是这方面的专家……)
至于Java,我需要在我的另一台机器上试用它:)
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
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);
}