Ruby实现DES ECB加密适配Java项目需求遇问题求助
如何在Ruby中实现与Java一致的DES ECB加密
最近我在把一个Java项目里的DES ECB加密功能迁移到Ruby时踩了坑,折腾了好一会儿才解决。这里把我的问题和解决方案分享出来,希望能帮到遇到同样问题的人。
Java 原加密代码
首先先贴出Java侧的实现,这是我们要对齐的基准:
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class DESEncryptor { public static String encrypt(String data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "DES"); Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8")); return bytesToHex(encryptedBytes); } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } public static void main(String[] args) throws Exception { // 示例:密钥"12345678",明文"testcontent" System.out.println(encrypt("testcontent", "12345678")); // 预期输出:b42e3dbfffd4bb5487a27fd702f079e287e6325767bfdd20 } }
我的Ruby尝试与报错
一开始我直接用Ruby的openssl库写了代码,以为能直接跑,结果报错了:
require 'openssl' def des_encrypt(data, key) cipher = OpenSSL::Cipher.new('DES-ECB') cipher.encrypt cipher.key = key.encode('UTF-8') encrypted = cipher.update(data.encode('UTF-8')) + cipher.final encrypted.unpack('H*').first end # 调用测试 puts des_encrypt("testcontent", "12345678")
终端返回的错误是:
OpenSSL::Cipher::CipherError: bad key length from (irb):4:in `key=' from (irb):4:in `des_encrypt' from (irb):9
问题分析与解决办法
问题出在哪?
仔细对比Java和Ruby的实现后发现:
- 密钥长度要求:DES的密钥必须是8字节(64位),Java的
SecretKeySpec会自动截取密钥的前8字节来适配,但Ruby的OpenSSL库不会做这个自动处理,只要密钥长度不对就直接报错。 - 填充模式倒是一致的,Java用的
PKCS5Padding和Ruby默认的PKCS#5填充是一样的,但为了保险起见最好明确指定。
修正后的Ruby代码
调整后的代码如下,完美匹配Java的加密结果:
require 'openssl' def des_encrypt(data, key) # 和Java对齐:截取密钥的前8字节,确保密钥长度符合DES要求 key_bytes = key.encode('UTF-8').bytes.take(8).pack('C*') cipher = OpenSSL::Cipher.new('DES-ECB') cipher.encrypt cipher.key = key_bytes # 明确设置PKCS#5填充(和Java的PKCS5Padding一致) cipher.padding = 1 encrypted = cipher.update(data.encode('UTF-8')) + cipher.final # 转成十六进制字符串输出 encrypted.unpack('H*').first end # 测试验证 result = des_encrypt("testcontent", "12345678") puts result # 输出正好是预期的:b42e3dbfffd4bb5487a27fd702f079e287e6325767bfdd20
几个关键细节
- 密钥处理:一定要确保密钥是8字节,Java会自动截断,所以Ruby也要做同样的截取操作,不然会触发密钥长度错误。
- 填充模式:虽然Ruby默认是PKCS#5,但显式设置
cipher.padding = 1能避免版本或环境差异带来的问题。 - ECB模式:ECB不需要IV,所以不用设置初始化向量,这点和Java的实现保持一致。
内容的提问来源于stack exchange,提问作者Vini Gabriel
相关产品推荐
相关产品推荐

