Исходя из названия здесь, я собираюсь предположить, что вы хотите иметь возможность шифровать сообщение в Java, а затем расшифровать это сообщение в Ruby, используя пароль- на основе шифрования AES-CBC.
Теперь стандартная библиотека openssl
в Ruby легко поддерживает * 2 8 * основанную на пароле функцию извлечения ключей 2 на основе PKCS5 . Вы можете значительно упростить код для расшифровки Ruby , если используете его в своем шифровании Java .
Вот как вы должны шифровать, используя PBKDF2 в PKCS5 в Java:
// in Java-land
import java.security.AlgorithmParameters;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
...
static String printHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", (b & 0xFF)));
}
return sb.toString();
}
public static Map<String,String> encrypt(String msg, String pwd, byte[] salt)
throws Exception {
Map<String,String> retval = new HashMap<String,String>();
// prepare to use PBKDF2/HMAC+SHA1, since ruby supports this readily
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
// our key is 256 bits, and can be generated knowing the password and salt
KeySpec spec = new PBEKeySpec(pwd.toCharArray(), salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
// given key above, our cippher will be aes-256-cbc in ruby/openssl
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
// generate the intialization vector
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
retval.put("iv", printHex(iv));
byte[] ciphertext = cipher.doFinal(msg.getBytes("UTF-8"));
retval.put("encrypted", printHex(ciphertext));
return retval;
}
public static void main(String[] args) throws Exception {
String msg = "To Ruby, from Java, with love...";
String pwd = "password";
String salt = "8 bytes!"; // in reality, you would use SecureRandom!
System.out.println("password (plaintext): " + pwd);
System.out.println("salt: " + salt);
Map<String,String> m = encrypt(msg, pwd, salt.getBytes());
System.out.println("encrypted: " + m.get("encrypted"));
System.out.println("iv: " + m.get("iv"));
}
Выполнение вышеуказанного приведет к чему-то вроде следующего:
password (plaintext): password
salt: 8 bytes!
encrypted: 4a39f1a967c728e11c7a5a3fb5d73ad07561f504c9d084d0b1ae600cc1f75137cbb82a4d826c060cb06e2e283449738d
iv: ecbc985b3550edc977a17acc066f2192
Шестнадцатеричные строки используются для зашифрованного сообщения и вектора инициализации, поскольку вы можете использовать OpenSSL для проверки процесса шифрования / дешифрования (настоятельно рекомендуется).
Теперь из Ruby-программы вы должны использовать шифр AES-256-CBC
и получать секретный ключ из строк password
и salt
(не byte[]
в соответствии с Java). Используя вывод вышеупомянутой Java-программы, мы имеем:
# from Ruby-land
require 'openssl'
d = OpenSSL::Cipher.new("AES-256-CBC")
d.decrypt
key = OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "8 bytes!", 1024, d.key_len)
d.key = key
d.iv = "ecbc985b3550edc977a17acc066f2192".scan(/../).map{|b|b.hex}.pack('c*')
data = "4a39f1a967c728e11c7a5a3fb5d73ad07561f504c9d084d0b1ae600cc1f75137cbb82a4d826c060cb06e2e283449738d".scan(/../).map{|b|b.hex}.pack('c*')
d.update(data) << d.final
=> "To Ruby, from Java, with love..."
ПРИМЕЧАНИЕ. Часть этого кода, написанная на Ruby, во многом дословно взята из документации на японском языке стандартной библиотеки openssl
.