我只想将ruby代码迁移到Java
这是我的红宝石代码
require 'openssl'
require 'base64'
key = '7c54367a45b37a192abc2cd7f45203042350406f8'
cipher = OpenSSL::Cipher::Cipher.new('aes-128-ecb')
cipher.encrypt()
cipher = OpenSSL::Cipher::Cipher.new('aes-256-ecb')
cipher.encrypt()
cipher.key = key
crypt = cipher.update('Rahul')
crypt << cipher.final()
puts (Base64.encode64(crypt))
以下是我在Java中尝试的内容
String getDecodedString(String key,String encodedValue,SupportedEncryptionAlgorithm algoInfo)
{
Cipher cipher = getCipherInstancenew(algoInfo, key,Cipher.DECRYPT_MODE);
try
{
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(encodedValue);
int ctLength = cipher.getOutputSize(dec.length);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(dec, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
return null;
}
catch (IllegalBlockSizeException e)
{
LoggerFactory.getLogger(EncryptionHelper.class).error("Security Alert",e);
}
catch (BadPaddingException e)
{
LoggerFactory.getLogger(EncryptionHelper.class).error("Security Alert",e);
}
return null;
}
public static byte[] stringToBytes(String s) {
byte[] b2 = new BigInteger(s, 36).toByteArray();
return Arrays.copyOfRange(b2, 1, b2.length);
}
public static Cipher getCipherInstancenew(SupportedEncryptionAlgorithm algoInfo,String keyString,int mode) throws IOException
{
byte[] decodedBytes;
Cipher cipher=null;
try
{
decodedBytes = getBase64FromHEX(keyString).getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(decodedBytes, "AES");
Security.addProvider(new BouncyCastleProvider());
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
cipher.init(mode, skeySpec );
}
catch (java.security.GeneralSecurityException e)
{
/*Strictly no logging as it is security class
* There seems to be some issue with the Keys so alert it */
//LoggerFactory.getLogger(EncryptionHelper.class).error("Security Alert",e);
throw new IOException("GetCipherInstance does not exsists");
}
return cipher;
}
public static String getBase64FromHEX(String input) {
byte barr[] = new byte[16];
int bcnt = 0;
for (int i = 0; i < 32; i += 2) {
char c1 = input.charAt(i);
char c2 = input.charAt(i + 1);
int i1 = intFromChar(c1);
int i2 = intFromChar(c2);
barr[bcnt] = 0;
barr[bcnt] |= (byte) ((i1 & 0x0F) << 4);
barr[bcnt] |= (byte) (i2 & 0x0F);
bcnt++;
}
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(barr);
}
private static int intFromChar(char c) {
char[] carr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
char clower = Character.toLowerCase(c);
for (int i = 0; i < carr.length; i++) {
if (clower == carr[i]) {
return i;
}
}
return 0;
}
它适用于32字节字符串,但不适用于Java中的41字节,但在Ruby中,它适用于大于32字节的任何长度。奇怪请帮助
答案 0 :(得分:2)
我怀疑你打电话给String.getBytes()
正在做你需要他们做的事。
getBytes()
方法使用平台的默认字符编码将String
的字符转换为字节序列。默认平台字符编码类似于UTF-8,US-ASCII或ISO-8859-1。它不是base-64或十六进制。
大多数字符编码无法处理加密操作中使用的随机8位值。因此,例如,您通常无法根据加密产生的字节创建新的String
。许多值将替换为 或?,具体取决于您的编码。而且,即使它恰好在您的计算机上工作,下一个桌面上的计算机也可能配置不同,并且在尝试解码该字符串时会失败。
如果您需要在二进制数据和文本之间进行转换,请使用类似Base-64的编码。
答案 1 :(得分:2)
以下Java代码输出完全相同的base 64编码结果,加密为Ruby代码并成功解密:
final Cipher encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
encryptCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("7c54367a45b37a192abc2cd7f4520304".getBytes(), "AES"));
final byte[] encrypt = encryptCipher.doFinal("This is my text".getBytes());
System.out.println(new String(Base64.encode(encrypt)));
final Cipher decryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
decryptCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec("7c54367a45b37a192abc2cd7f4520304".getBytes(), "AES"));
final byte[] decrypt = decryptCipher.doFinal(encrypt);
System.out.println(new String(decrypt));
Ruby OpenSSL API显然只使用密钥的前32个字节,因为key
的以下值返回与41字节版本相同的值:
key = '7c54367a45b37a192abc2cd7f4520304'
另外,我不确定为什么cipher
在Ruby代码中被初始化两次,因为据我所知,这是不必要的。