10

So I have this piece of code which I'm trying to do some conversions in so firstly I generate a public key and print it, and then convert in byte, then to string. After then I am converting it back to bytes, but when I convert it back to bytes the value changes for the byte so the public key generated isn't the same as the top one, as you can see in the output below.

//generating public key PublicKey public_key = CryptographyHelper.ellipticCurveCrypto().getPublic(); System.out.println("PUBLIC KEY::" + public_key); //converting public key to byte byte[] byte_pubkey = public_key.getEncoded(); System.out.println("\nBYTE KEY::: " + byte_pubkey); //converting byte to String String str_key = Arrays.toString(byte_pubkey); System.out.println("\nSTRING KEY::" + str_key); //converting string to Bytes byte_pubkey = str_key.getBytes(); System.out.println("BYTE KEY::" + byte_pubkey); //converting it back to public key KeyFactory factory = KeyFactory.getInstance("ECDSA", "BC"); public_key = (ECPublicKey) factory.generatePublic(new X509EncodedKeySpec(byte_pubkey)); System.out.println("FINAL OUTPUT" + public_key); 

Output

 PUBLIC KEY::EC Public Key [4d:53:40:86:3f:a8:91:49:b6:27:b5:58:14:b8:8b:f1:ff:8a:78:70] X: c8e1028cad7b105814d4a2e0e292f5f7904aad7b6cbc46a5 Y: 312272321a1ba4ff14caa73b42acb35eb025d9f6fc2ca6b3 BYTE KEY::: [B@1a1d6a08 STRING KEY::[48, 70, 48, 16, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 5, 43, -127, 4, 0, 31, 3, 50, 0, 4, -56, -31, 2, -116, -83, 123, 16, 88, 20, -44, -94, -32, -30, -110, -11, -9, -112, 74, -83, 123, 108, -68, 70, -91, 49, 34, 114, 50, 26, 27, -92, -1, 20, -54, -89, 59, 66, -84, -77, 94, -80, 37, -39, -10, -4, 44, -90, -77] BYTE KEY[B@37d31475 Exception in thread "main" java.security.spec.InvalidKeySpecException: encoded key spec not recognized: failed to construct sequence from byte[]: Extra data detected in stream at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source) at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.engineGeneratePublic(Unknown Source) at java.security.KeyFactory.generatePublic(KeyFactory.java:328) at blahblah.Driver.main(Driver.java:44) C:\Users\blahblah\AppData\Local\NetBeans\Cache\8.1\executor-snippets\run.xml:53: Java returned: 1 BUILD FAILED (total time: 1 second) 

I have an error because when I am converting it back to bytes the second time and then when it convert backs to public key it becomes invalid, hence the error.

Additional Infornmation

But when I just do this it works fine, but my goal is to first convert the public key to a string somehow, then convert that string to type public key. The only way I can do that is by converting the public key, which is in string type, to a byte type and then converting it back to a public key. I can not convert a string directly to a public key as it won't work.

2
  • 1
    You should have a look at the charset used when creating and parsing the bytes Commented Sep 18, 2018 at 10:50
  • Can u mention which all libraries you are using ? Commented Sep 18, 2018 at 11:06

2 Answers 2

20

You need to use Base64 encoding system while converting to String type.
tostring() method uses JVM default encoding which does not support your characters.

PublicKey public_key = CryptographyHelper.ellipticCurveCrypto().getPublic(); System.out.println("PUBLIC KEY::" + public_key); //converting public key to byte byte[] byte_pubkey = public_key.getEncoded(); System.out.println("\nBYTE KEY::: " + byte_pubkey); //converting byte to String String str_key = Base64.getEncoder().encodeToString(byte_pubkey); // String str_key = new String(byte_pubkey,Charset.); System.out.println("\nSTRING KEY::" + str_key); //converting string to Bytes byte_pubkey = Base64.getDecoder().decode(str_key); System.out.println("BYTE KEY::" + byte_pubkey); //converting it back to public key KeyFactory factory = KeyFactory.getInstance("ECDSA", "BC"); public_key = (ECPublicKey) factory.generatePublic(new X509EncodedKeySpec(byte_pubkey)); System.out.println("FINAL OUTPUT" + public_key); 
Sign up to request clarification or add additional context in comments.

2 Comments

I tried using my own implementation for the rest of the missing part, you need to post your entire code and also mention libraries to be on the same page and resolve this issue
What about the privateKey? I tried this code but it keeps giving me this error: Exception in thread "main" java.security.spec.InvalidKeySpecException: Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:335) at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:212) at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
0

Here's a complete example of generating public and private keys via JCE using ECDSA from Bouncy Castle.

import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import static org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec; public class PublicPrivateKeyExample { static { Security.addProvider(new BouncyCastleProvider()); } private static final SecureRandom DEFAULT_SECURE_RANDOM; static { DEFAULT_SECURE_RANDOM = new SecureRandom(); DEFAULT_SECURE_RANDOM.nextBytes(new byte[64]); } public static void main(String[] args) throws Exception { // ----- // Create a random key-pair using ECDSA provided by bcprov-jdk15on from Bouncy Castle and encode as base64 // strings // ----- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC"); keyPairGenerator.initialize(getParameterSpec("secp521r1"), DEFAULT_SECURE_RANDOM); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); Base64.Encoder encoder = Base64.getEncoder(); String publicKeyStr = encoder.encodeToString(publicKey.getEncoded()); String privateKeyStr = encoder.encodeToString(privateKey.getEncoded()); // ----- // Decode the base64 public and private keys back to a JCE's PublicKey and PrivateKey // ----- KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC"); Base64.Decoder decoder = Base64.getDecoder(); PublicKey decodedPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decoder.decode(publicKeyStr))); PrivateKey decodedPrivateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decoder.decode(privateKeyStr))); assert publicKey.getEncoded() == decodedPublicKey.getEncoded(); assert privateKey.getEncoded() == decodedPrivateKey.getEncoded(); } } 

This was tested using Java 8 with the following:

<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version> </dependency> 

1 Comment

Thanks this comment was useful for bouncycastle implementation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.