Ruby的DES-EDE-CBC加密迁移至Java结果不一致如何解决?
问题修复方案
你当前加密结果不匹配是因为Ruby和Java两端的加密逻辑存在四处核心差异,逐一修复即可对齐结果:
核心差异点
- 密钥处理逻辑不匹配:Ruby端
key.split.pack("H*")是将key作为十六进制字符串解码为原始字节数组,Java端直接调用key.getBytes()是按UTF-8编码转字节,两者生成的密钥完全不同。 - IV未显式对齐:Ruby的OpenSSL::Cipher在CBC模式下默认会生成随机IV,Java端固定使用全0 IV,必须两端显式设置相同IV才能对齐结果。
- Padding规则不匹配:Ruby的OpenSSL::Cipher默认开启PKCS5Padding,Java端使用
NoPadding,即使输入刚好为8字节的块大小,Ruby默认会追加8字节的填充位,加密结果长度和内容都会不一致。 - 加密方法调用不规范:Java端仅调用
cipher.update()只会返回部分加密结果,Ruby端也未调用cipher.final补全输出,必须调用收尾方法获取完整的加密输出。
修正后的Ruby代码(对齐参数,避免默认值差异)
open_ssl_cipher = OpenSSL::Cipher.new("DES-EDE-CBC"); input = "abcdefgh"; key = "mytyyrxfmtmtmt23mtmtmqpmpm45t45" hex_input = input.unpack("H*").join.upcase cipher = open_ssl_cipher.encrypt cipher.padding = 0 # 关闭填充,和Java NoPadding对齐 cipher.iv = "\0" * 8 # 显式设置全0 IV,和Java对齐 cipher.key = [key].pack("H*") # 统一密钥解码逻辑 s = cipher.update([hex_input].pack("H*")) + cipher.final input_enc = s.unpack1("H*").upcase
修正后的Java代码
import org.bouncycastle.util.encoders.Hex; import javax.crypto.Cipher; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import java.nio.charset.StandardCharsets; import java.security.Key; public class EncService { private static final String TRANSFORMATION = "DESede/CBC/NoPadding"; private static final String ALGORITHM = "DESede"; public static void main(String[] args) { EncService service = new EncService(); service.encrypt(); } public String encrypt() { String data = "abcdefgh"; String key = "mytyyrxfmtmtmt23mtmtmqpmpm45t45"; try { Cipher cipher = Cipher.getInstance(TRANSFORMATION); IvParameterSpec ivParameterSpec = new IvParameterSpec(new byte[8]); // 修复密钥解码逻辑,和Ruby pack("H*")结果对齐 DESedeKeySpec spec = new DESedeKeySpec(Hex.decode(key)); Key secretKey = SecretKeyFactory.getInstance(ALGORITHM).generateSecret(spec); cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec); // 调用doFinal获取完整加密结果 byte[] bytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); String s = Hex.toHexString(bytes).toUpperCase(); System.out.printf("output: %s%n", s); return s; } catch (Exception e) { throw new RuntimeException(e); } } }
内容的提问来源于stack exchange,提问作者Nagendra Prasadu Gandla
相关产品推荐
相关产品推荐

