Bouncy Castle Curve25519 private key from Scrypt output

1.4k Views Asked by At

I am trying to achieve ECIES encryption, for which below code is working.

X9ECParameters ecP = CustomNamedCurves.getByName("curve25519");
ECParameterSpec ecSpec = EC5Util.convertToSpec(ecP);

BigInteger d = new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990");

ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec(
                    d, // d
                    ecSpec);
ECPoint Q = new FixedPointCombMultiplier().multiply(params.getG(), d.multiply(BigInteger.valueOf(-1)));

Q = Q.normalize();

ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
                    new ECPoint(Q.getAffineXCoord().toBigInteger(), Q.getAffineYCoord().toBigInteger()), // Q
                    ecSpec);

KeyFactory factTrial = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
BCECPrivateKey          sKey = (BCECPrivateKey) factTrial.generatePrivate(priKeySpec);
PublicKey           vKey = factTrial.generatePublic(pubKeySpec);

Cipher c = Cipher.getInstance("ECIESwithAES-CBC",BouncyCastleProvider.PROVIDER_NAME);
byte[] encodeBytes = c.doFinal(data.getBytes());
String encrypt = Base64.getEncoder().encodeToString(encodeBytes);

Cipher c2 = Cipher.getInstance("ECIESwithAES-CBC",BouncyCastleProvider.PROVIDER_NAME);
c2.init(Cipher.DECRYPT_MODE,sKey, c.getParameters()); 
byte[] decodeBytes = c2.doFinal(encodeBytes);
String deCrypt = new String(decodeBytes,"UTF-8");

Issue is the private key element 'd'. If I try to replace it with output of scrypt hash, private key fails to be converted in PrivateKey instance.

I have gone through net resources https://github.com/bcgit/bc-java/issues/251, https://crypto.stackexchange.com/questions/51703/how-to-convert-from-curve25519-33-byte-to-32-byte-representation, https://crypto.stackexchange.com/questions/72134/raw-curve25519-public-key-points.

Above resources suggest the way Bouncy Castle for Curve25519 interprets private key is different from the ways some internet resource suggest. In post https://crypto.stackexchange.com/questions/51703/how-to-convert-from-curve25519-33-byte-to-32-byte-representation there is mention as follows.

According to the curve25519 paper a x25519 public key can be represented in 32 bytes.

The x25519 library I'm using (bouncycastle) however gives me a 33 byte representation according to this standard.

I am very new to ECC, these resources are confusing me, the difference between lengths, the style of encoding big vs. little.

I have tried libSodium 'crypto_box_easy' and 'crypto_box_open_easy' via its Java binding and it works all fine. The 32 byte scrypt output is used by 'crypto_box_seed_keypair' to generate key pair which is used for encryption process.

As I see some maths is involved here which I lack at present or I am failing to see the conversion.

I have to go this route Scrypt output -> key pair -> use for encryption

Using directly KeyGenerator from BC is working, but that utilises SecureRandom, but I need the output of Scrypt to behave as private key.

Questions:

  1. I'll really appreciate someone helps me understand the difference between libSodium and Bouncy Castle approach. libSodium mentions it uses X25519. When I try to create X25519 key from 32 bytes, but BC Cipher(ECIESwithAES-CBC) then complaints it is not a EC Point, from this resource 'https://github.com/bcgit/bc-java/issues/251' it seems there are differences in that too (Curve25519 vs X25519).

  2. The private key 'd', how to interpret it. I have seen these random values in Bouncy Castle documentation and test cases, is this simply a number in the prescribed range for valid keys? This number is treated (little vs. big endian) before creating BigInteger instance. I mean the raw value of 'd' in the my code example was converted from some other number?

The struggle between understanding different mechanism of Curve25519 and BC API itself, I am really confused.

Some pointers to further my research would be of great help.

0

There are 0 best solutions below