AES java编码,ruby解码

pom*_*vdp 7 ruby java aes

我正在尝试对java中的数据进行AES编码,通过网络发送并在ruby中对其进行解码.

使用基本字符串可以正常工作,但是一旦字符串的长度为16个字节或更多,我就会在解码的ruby字符串的编码中产生垃圾.我想它与填充有关(不确定,因为它影响甚至大小为16的字符串)

我尝试使用PKCS或只是在我的字符串末尾添加空格以匹配确切的长度而没有运气

也有人可以解释为什么我必须在红宝石中做一个"aes-256-cbc"知道我的java代码使用aes 128?在ruby中尝试aes-128-cbc对任何字符串都不起作用

任何帮助是极大的赞赏

这是我的基本代码

Java的

byte[] raw = key.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(str.getBytes());
return new BASE64Encoder().encode(encrypted);
Run Code Online (Sandbox Code Playgroud)

红宝石

def aes_decrypt(key, encrypted)
decipher =OpenSSL::Cipher::Cipher.new("aes-256-cbc")
decipher.decrypt
decipher.padding = 0
decipher.key = key
d = decipher.update(encrypted)
d << decipher.final
logger.debug "email  #{d.to_s}"
return d.to_s
end
Run Code Online (Sandbox Code Playgroud)

Tho*_*nin 11

衬垫,有链接.你应该首先得到正确的链接.

AES加密16字节的块,不多也不少.如果要加密可能长于16个字节的消息,则必须决定如何将数据拆分为块并在之后重新组装.基本的分裂算法称为ECB:这只是"分裂"成单独加密的块.众所周知,ECB对现实世界的数据很脆弱,因为它泄漏了有关哪些明文块彼此相等的信息(它们将被加密相同),并且这种冗余经常发生在"正常"数据中.

因此,需要以某种方式"随机化"数据块,以便隐藏数据冗余.在CBC模式中执行通过"链":一个块的处理取决于前一个块的加密的结果.即,将加密的明文块与先前的块加密的输出(按位XOR)组合.

这里重要的一点是,第一个加密块(前16个字节的数据)没有"前一个块",因此没有任何与XOR相关的内容.这可以通过选择"随机IV",即16个随机字节的序列来解决,它将用作异常步骤的"块-1".解密方必须知道IV(否则它将不知道解密块的XOR是什么,并且前16个字节的数据将是不可理解的).光明的一面是IV不需要保密; 它必须统一选择(它不能是每个消息增加的计数器),但它可以"明确地"传输,通常沿着加密的消息本身传输.

所以你不得不担心IV,我在Java或Ruby代码中都没有看到它.通常,Java默认为ECB(因此根本没有IV).如果红宝石默认为CBC"全零IV"(这是概念上的,不安全的),那么它是正常的,你可以解密的第一个块(写下来,它"只是工程"),但同样正常它不适用于后续块.

因此,我建议您明确使用CBC(在Java中,"AES/CBC/PKCS5Padding"用作算法名称,而不是"AES")并管理IV(必须然后传输;您可以采用约定在加密消息之前连接IV).

其他几点说明:

  • 填充是关于向明文添加一些数据,以便您具有适当的输入长度.CBC要求输入长度具有块大小的长度倍数(16字节).PKCS#5填充是一种流行的方法,通过它您可以添加至少1个字节,最多16个字节,这样所有它们都具有值n,其中n是添加的字节数.接收器然后可以(明确地)知道添加了多少字节,并将其删除.Java可以为你添加填充,我想如果很好的话,Ruby也可以自动处理填充.

  • 在Java代码中,您使用key.getBytes().我想那key是一个String.知道getBytes()根据平台默认字符集对字符串进行编码,这在全球范围内并不总是相同.通过指定显式字符集,您将节省一些担心.另外,既然你想使用128位密钥,但是你只在Ruby端获得了"AES-256",那么我假设你实际上在Java端使用了256位密钥.我的猜测是你的key字符串是你的密钥的十六进制表示,为32个字符.key.getBytes()不解释十六进制数字; 它对字符本身进行编码,产生一个32字节的数组 - 和32字节,即256位,而不是128位.