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

问题描述

要在java代码中使用ElGamal方案加密消息,我进行如下操作:

DECLARE
order_id_ NUMBER;

BEGIN
    -- note here that you're now assigning the return value to anything
    insert_order(p_order_id => 4,p_order_num => 'O223PS56',p_name => 'Test Test',p_email => 'test@test.co.uk',p_address => '123 Test Street',p_city => 'Newcastle Upon Tyne',p_province => 'Tyne and Wear',p_postcode => 'NE98 4TN',p_telephone => '123456789',p_total => 7.97,p_order_date => to_date('11-apr-2021','DD-mon-YYYY'));
    FOR i IN 1..order_items
    LOOP
      insert_order_items(order_id_,order_items(i) => 5,order_items(i) => 2,order_items(i) => 3073748221,order_items(i) => 'Brand New',order_items(i) => 1.99,order_items(i) => 1.99);
     COMMIT;
   END LOOP;
END;
/

我从 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); 字节数组包含 (c1,c2) 并且我需要将 c1 作为 BigInteger 访问。

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

谢谢

解决方法

密文的byte[]是密钥长度的两倍,前半部分对应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,c0,keysizeBits/8);
System.arraycopy(ciphertext,c0.length,c1,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 位的密钥大小太小了,请参见例如here,缺少填充是不安全的,例如here

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...