java - 如何使用 Bouncy CaSTLe ElGamal 和 javax.crypto.Cipher 显式加密 (c1, c2) 元组

标签 java cryptography bouncycastle elgamal

要在 java 代码中使用 ElGamal 方案加密消息,我按以下步骤进行:

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

Cipher cipher = Cipher.getInstance("Elgamal/NOne/NoPadding", "BC");
KeyPaireGenerator generator = KeyPairGenerator.getInstance("ElGamal", "BC");
SecureRandom random = new SecureRandom();

generator.initialize(512, random);
KeyPair pair = generator.generateKeyPair();

String message = "myMessageToEncrypt";
cipher.init(Cipher.ENCRYPT_MODE, pair.getPublic(), random);
[]byte cipherText = cipher.doFinal(message);

我从 ELGamal 方案中知道 cipherText 字节数组包含 (c1, c2),我需要将 c1 作为 BigInteger 访问。

所以我的问题是:如何在字节数组和元组(c1, c2)之间进行转换?

谢谢

最佳答案

密文的byte[]的长度是 key 大小的两倍,前半部分对应c0,后半部分对应c1ci 的转换是可以实现的,例如与 new BigInteger(1, ci) .

通过使用以这种方式转换的 BigInteger 手动执行解密,可以轻松进行验证:

int keysizeBits = 512;

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

// Key generation
KeyPairGenerator generator = KeyPairGenerator.getInstance("ElGamal", "BC");
SecureRandom random = new SecureRandom();
generator.initialize(keysizeBits, random); 

KeyPair pair = generator.generateKeyPair();
BCElGamalPublicKey publicKey = (BCElGamalPublicKey)pair.getPublic();
BCElGamalPrivateKey privateKey = (BCElGamalPrivateKey)pair.getPrivate();

// Encryption
byte[] input = "abcdefgh".getBytes(StandardCharsets.UTF_8);
Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey, random);
byte[] ciphertext = cipher.doFinal(input);
System.out.println("Ciphertext: " + Hex.toHexString(ciphertext));//new String(cipherText));

// Decryption
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plaintext = cipher.doFinal(ciphertext);
System.out.println("Plaintext : " + new String(plaintext, StandardCharsets.UTF_8));

// Manual decryption 
// 1. Convert c0/c1 into BigInteger
byte[] c0 = new byte[keysizeBits/8];
byte[] c1 = new byte[keysizeBits/8];
System.arraycopy(ciphertext, 0,  c0, 0, keysizeBits/8);
System.arraycopy(ciphertext, c0.length,  c1, 0, keysizeBits/8);
System.out.println("c0        : " + Hex.toHexString(c0));
System.out.println("c1        : " + Hex.toHexString(c1));
BigInteger c0BI = new BigInteger(1, c0); 
BigInteger c1BI = new BigInteger(1, c1); 

// 2. Decrypt with c0BI^(-privBI) * c1BI
BigInteger privateKeyBI = privateKey.getX();
BigInteger pBI = privateKey.getParameters().getP();
BigInteger plaintextBI = c0BI.modPow(privateKeyBI.multiply(new BigInteger("-1")), pBI).multiply(c1BI).mod(pBI); 

System.out.println("Plaintext : " + new String(plaintextBI.toByteArray(), StandardCharsets.UTF_8));

例如以下输出:

Ciphertext: adc32bbd23d80489db5843e26b26c58062a2369912915025574fd8598b8c72665e0a922ad8897719e1f9b0e3fb76e275ed15194534399781017e43c24a92cc77b13a256ff27e12667cc0f5876d1873368449b5a60ecc7a60a6b92f2640608f21dc86e7effe1dc4038b02b8c6c9d7ac03bd2e7d66d803d2a19f459ffeedfcff46
Plaintext : abcdefgh
c0        : adc32bbd23d80489db5843e26b26c58062a2369912915025574fd8598b8c72665e0a922ad8897719e1f9b0e3fb76e275ed15194534399781017e43c24a92cc77
c1        : b13a256ff27e12667cc0f5876d1873368449b5a60ecc7a60a6b92f2640608f21dc86e7effe1dc4038b02b8c6c9d7ac03bd2e7d66d803d2a19f459ffeedfcff46
Plaintext : abcdefgh

请注意,如今 512 位的 key 大小太小了,参见例如here ,并且缺少填充是不安全的,例如here .

关于java - 如何使用 Bouncy CaSTLe ElGamal 和 javax.crypto.Cipher 显式加密 (c1, c2) 元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67126502/

相关文章:

java - 重置 JComboBox 的值

java - 如何对双向文本处理进行单元测试

.net - .Net 和 iPhone 之间的三重 DES 互操作性?

java.lang.ClassNotFoundException : org. bouncycaSTLe.asn1.ASN1Encodable

java - BouncyCaSTLe 签名值与 dotNET 签名值不匹配

java - 如何正确使用 bouncycaSTLe 的 PaddedBufferedBlockCipher?

java - 无法理解在 ConcurrentHashMap 中重写 equals 方法的优势

java - 由方法生成的数组

java - 使用 Java SecureRandom 进行洗牌以实现加密目的?

math - 破译 amsco 密码