Problem with the way gfpcrypt HMAC's the encoding parameters' length in DHAES_MODE

504 views
Skip to first unread message

Jesse Wilson

unread,
Apr 11, 2013, 12:32:16 PM4/11/13
to cryptop...@googlegroups.com

Cryptopp folks,

I'm attempting to interop ECIES encryption between bouncy castle and cryptopp. Unfortunately, I've run into a problem and I think it's a bug in cryptopp.

When cryptopp creates the digest for ECIES, it sends the payload, followed by the encoding parameters, followed by the encoding parameters' size in bytes as an 8-byte value. For example, if the encoding parameter is 4 bytes long, it writes the length as 00 00 00 00 00 00 00 04. If its 32 bytes long it writes00 00 00 00 00 00 00 20.

This is driven by code in gfpcrypt.h:

        mac.Update(encodingParameters.begin(), encodingParameters.size());
        if (DHAES_MODE)
        {
            byte L[8] = {0,0,0,0};
            PutWord(false, BIG_ENDIAN_ORDER, L+4, word32(encodingParameters.size()));
            mac.Update(L, 8);
        }

Bouncy castle writes the encoding parameter size in bits as a 4-byte value. For example, if the encoding parameter is 4 bytes long it writes 00 00 00 20. If its 32 bytes long, bouncy castle writes 00 00 01 00.

This is driven by code in IESEngine.java:

        byte[] L2 = new byte[4];

        if (V.length != 0)
        {
            if (P2 != null)
            {
                Pack.intToBigEndian(P2.length * 8, L2, 0);
            }
            else
            {
                Pack.intToBigEndian(0, L2, 0);
            }
        }

        ...

        if (V.length != 0)

        {
            mac.update(L2, 0, L2.length);
        }

I cross posted this message to the bouncy castle list, and David Hook replied with a quote from Victor Shoup's paper:

In particular, we multiply |L| by 8 so as to encode the length of L in bits, rather than bytes, since the IEEE P1363a version of ECIES allows (in theory, but not really in practice) messages and labels that are bit strings rather than byte strings.

Is it a bug?

Thanks!

Mouse

unread,
Dec 18, 2013, 9:01:07 PM12/18/13
to cryptop...@googlegroups.com
This patch does not seem to bring results with CryptoPP-5.6.2 and BouncyCastle-1.50. After applying the patch, the result still is:

javax.crypto.BadPaddingException: Invalid MAC.
at org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2145)
at uijr7.decECAESKey(uijr7.java:482)
at uijr7.main(uijr7.java:565)

MAC doesn't get computed correctly.

It is possible that I don't create/use the ECIES correctly - would appreciate any example of (a) reading ECIES-encrypted file, and (b) creating an ECIES-encrypted byte array.

Thanks!

On Thursday, April 11, 2013 1:02:26 PM UTC-4, Daniele Perito wrote:
Jesse and I think we have found the problem. Here is the patch to fix it. This has been confirmed to work and we were able to encrypt in CryptoPP and decrypt in Bouncy Castle.

Jesse Wilson

unread,
Dec 26, 2013, 1:14:10 PM12/26/13
to Mouse, cryptop...@googlegroups.com

Here’s a full encryption and decryption with a golden private key.

    Security.addProvider(new BouncyCastleProvider());
    KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");

    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(fromHex("3059301306072a8648ce3d020106"
        + "082a8648ce3d03010703420004b629e654f0df6ebb559c8fa0a2e7902777030f4871b76d048beee5f505b556"
        + "8f32084eacf91eef6cce758f47bc82f8cb2137b28e33975ac26c052a1cbca22140"));
    PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(fromHex("308193020100301306072a864"
        + "8ce3d020106082a8648ce3d0301070479307702010104209219a2380634f27db6e7a0871b377765f4630db76"
        + "d9ac73f5e6bc0c443bdecdba00a06082a8648ce3d030107a14403420004b629e654f0df6ebb559c8fa0a2e79"
        + "02777030f4871b76d048beee5f505b5568f32084eacf91eef6cce758f47bc82f8cb2137b28e33975ac26c052"
        + "a1cbca22140"));
    PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
    KeyPair keys = new KeyPair(publicKey, privateKey);

    byte[] data = randomByteString(100);
    Cipher encryptCipher = Cipher.getInstance("ECIES/DHAES/NOPADDING", "BC");
    encryptCipher.init(Cipher.ENCRYPT_MODE, keys.getPublic(), new SecureRandom());
    byte[] ciphertext = encryptCipher.doFinal(data);

    IESParameterSpec parameterSpec = new IESParameterSpec(null, new byte[0], 128, 128);
    Cipher decryptCipher = Cipher.getInstance("ECIES/DHAES/NOPADDING", "BC");
    decryptCipher.init(Cipher.DECRYPT_MODE, keys.getPrivate(), parameterSpec, new SecureRandom());
    byte[] decrypted = decryptCipher.doFinal(ciphertext);

    assertThat(decrypted).isEqualTo(data);

And this will generate a new key pair:

    Security.addProvider(new BouncyCastleProvider());
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
    keyPairGenerator.initialize(256, new SecureRandom());
    KeyPair keys = keyPairGenerator.generateKeyPair();
Reply all
Reply to author
Forward
0 new messages