【问题标题】:How to Make Encryption (c1, c2) Tuple Explicit using Bouncy Castle ElGamal and javax.crypto.Cipher如何使用 Bouncy Castle ElGamal 和 javax.crypto.Cipher 使加密(c1,c2)元组显式
【发布时间】:2021-07-11 13:19:28
【问题描述】:

要在 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)之间进行转换?

谢谢

【问题讨论】:

    标签: java cryptography bouncycastle elgamal


    【解决方案1】:

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

    使用以这种方式转换的BigIntegers 手动执行解密很容易验证:

    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 位的密钥大小太小了,请参见例如here,缺少填充是不安全的,例如here.

    【讨论】:

    • 在哪里可以找到算法的规范?我在充气城堡源代码中找不到它...
    • @Golddy - 为此我根本不需要 BouncyCastle 的实现,只需要 ElGamal 的定义,s。例如ElGamal encryption - Decryption。我假设 BC 正确地实现了它;-)
    猜你喜欢
    • 1970-01-01
    • 2017-04-30
    • 2011-01-26
    • 2015-06-13
    • 1970-01-01
    • 2012-05-10
    • 2011-08-20
    • 2020-01-17
    • 2020-09-01
    相关资源
    最近更新 更多