Reputation: 151
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.
Upvotes: 10
Views: 22876
Reputation: 1140
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>
Upvotes: 0
Reputation: 1015
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);
Upvotes: 20