I'm trying to generate a "Secp256k1" keypair with java.
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
g.initialize(ecSpec, new SecureRandom());
KeyPair keyPair = g.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
But if i look at the Outputs, my keypair always looks simmular.
Try 0:
Pubkey: MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEx2WR3g1ytBdx8VJ+N121FFjn/YFbZ77ZumqVteTXAHnzN9fR+3NRD0EQ8kb+TnHvDMCtRR6a7GE8ckVVpajCrA==
Try 1:
Pubkey: MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEpzA5+Zd8xtD7UH0IxlIyIGIFCjctvzGMqBKEpqDf09PLTGcp9UrDHOB/uWH9VGA+nJAUjnPtxSR+njuDZy4JZw==
Try 2:
Pubkey: MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbXclGh0T7jScfGfJNhAw6MnFI4AcpAytdd7TsrEykbOVGsT8xBla7x7uYdlBp3KNVQPG7E9X5Ajftd1dOyTjeA==
Try 3:
Pubkey: MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACJKf861/P4yhsJnPMitSWiLNrbvBEYdB/pndY0ScUWdKfIPhA3qbHLTzYPROA7wiGbj2oS7joxYzhrrWb0rwA==
"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE" the beginning is always the same, and it ends with "=="
Im sure there is something im missing. Does anybody knows why it always beginns with the same 32 characters?
Since you are using BouncyCastle as the provider, your public key will be instance of BCECPublicKey. The getEncoded method of this class reuturns encoded SubjectPublicKeyInfo structure. This is defined in RFC5480 :
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
The first field of this structure is algorithm of type AlgorithmIdentifier. Since you do not change the algorithm for your keys - the bytes at the begining are the same (they designate the same algorithm) and this is expected behaviour.
Related
I have to use DSA (Digital Signature Algorithm) in my project, implementing using Java.I have a problem that I can't store the public and private key of DSA (of type PublicKey & PrivateKey). When I stored it as a blob, can't retrieve to its form (ie., PublicKey). Can anyone help me?
KeyPairGenerator pairgen = KeyPairGenerator.getInstance("DSA");
SecureRandom random = new SecureRandom();
pairgen.initialize(KEYSIZE, random);
KeyPair keyPair = pairgen.generateKeyPair();
PublicKey pu=keyPair.getPublic();
I have to store this up and have to retrieve
Store it as byte[] using pu.getEncoded().
To restore into PublicKey object you load the byte array and make the following call
KeyFactory kf = KeyFactory.getInstance("DSA");
PublicKey pu = kf.generatePublic(new X509EncodedKeySpec(keyBytes));
Optionally you can also encode it with base64.
This website describes a way to implement RSA in java using a library. Is it possible to have control over the value of the public exponent e? Java sets it to 65537. I know that it is an appropriate value but can I change it while still using the library?
This is how they implement it:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),
RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),
RSAPrivateKeySpec.class);
saveToFile("public.key", pub.getModulus(),
pub.getPublicExponent());
saveToFile("private.key", priv.getModulus(),
priv.getPrivateExponent());
Yes, you can, but you should be certain that it is a prime number (bounded by the size of the modulus):
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
// 17 is another often used value, beware to use proper RSA padding if you set it to 3
RSAKeyGenParameterSpec kpgSpec = new RSAKeyGenParameterSpec(2048, BigInteger.valueOf(3));
kpg.initialize(kpgSpec);
KeyPair kp = kpg.genKeyPair();
Note that you cannot change it after key generation. Also note that if your exponent is too large (or has many bits set to 1) that it will affect the speed of public key operations. 65537 - the default - is a good value that has only 2 bits set to 1 (the fourth number of Fermat, or F4).
I have two 32 byte long byte arrays representing the X and Y values for an EC Public Key. I know that the curve is the named curve "prime256v1".
How can I turn that into a Java PublicKey object?
The JCE appears to provide no facilities whatsoever to use named curves.
Bouncycastle's example code does not appear to compile with any version of bouncycastle I can find.
WTF?
It turns out that there is, in fact, another way to do this. The AlgorithmParameters class can apparently be used to translate an ECGenParameterSpec, with a named curve, into an ECParameterSpec object that you can use with a KeyFactory to generate a PublicKey object:
ECPoint pubPoint = new ECPoint(new BigInteger(1, x),new BigInteger(1, y));
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC");
parameters.init(new ECGenParameterSpec("secp256r1"));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
ECPublicKeySpec pubSpec = new ECPublicKeySpec(pubPoint, ecParameters);
KeyFactory kf = KeyFactory.getInstance("EC");
return (ECPublicKey)kf.generatePublic(pubSpec);
I don't see any way in JCE to use a named curve directly for a key, but it can be used for key generation, and the parameters can then be extracted from that key:
// generate bogus keypair(!) with named-curve params
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec gps = new ECGenParameterSpec ("secp256r1"); // NIST P-256
kpg.initialize(gps);
KeyPair apair = kpg.generateKeyPair();
ECPublicKey apub = (ECPublicKey)apair.getPublic();
ECParameterSpec aspec = apub.getParams();
// could serialize aspec for later use (in compatible JRE)
//
// for test only reuse bogus pubkey, for real substitute values
ECPoint apoint = apub.getW();
BigInteger x = apoint.getAffineX(), y = apoint.getAffineY();
// construct point plus params to pubkey
ECPoint bpoint = new ECPoint (x,y);
ECPublicKeySpec bpubs = new ECPublicKeySpec (bpoint, aspec);
KeyFactory kfa = KeyFactory.getInstance ("EC");
ECPublicKey bpub = (ECPublicKey) kfa.generatePublic(bpubs);
//
// for test sign with original key, verify with reconstructed key
Signature sig = Signature.getInstance ("SHA256withECDSA");
byte [] data = "test".getBytes();
sig.initSign(apair.getPrivate());
sig.update (data);
byte[] dsig = sig.sign();
sig.initVerify(bpub);
sig.update(data);
System.out.println (sig.verify(dsig));
You do get the parameters, but apparently no longer linked to the OID, which might make a difference.
In particular it may be treated as "arbitrary" or "explicit" in TLS and not work
even though the TLS parties support that same curve by name.
Note that openssl uses the name prime256v1 but not everyone does. Java (sun.) uses secp256r1, or the OID.
If you are actually getting this pubkey from openssl, note that JCE can directly read the X.509
SubjectPublicKeyInfo format, which openssl calls PUBKEY, including the named (OID) form.
I have this strange error which I can't find a solution to fix.
So I generate a public-private key pair, convert it to byte-array and after that recover the original key from that by array. No errors
{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
PublicKey pub = keyPair.getPublic();
byte[] pubBytes = pub.getEncoded();
try
{
// to recover the key
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub_recovered = kf.generatePublic(new X509EncodedKeySpec(pubBytes));
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
System.out.println("Finish");
After that I repeat the same steps, but before recovering the key, I convert the byte array to string and after that back. In this case I get error.
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
PublicKey pub = keyPair.getPublic();
byte[] pubBytes = pub.getEncoded();
try
{
String pub1 = new String(pubBytes, "UTF-8");
byte[] pub2 = pub1.getBytes("UTF-8");
// to recover the key
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub_recovered = kf.generatePublic(new X509EncodedKeySpec(pub2));
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
The error occurs a the line:
PublicKey pub_recovered = kf.generatePublic(new X509EncodedKeySpec(pub2));
and it says:
java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=111, too big.
Does anyone know how to fix and why in general this happens? The message says invalid key exception, however since it worked i the first case, I am more inclined that something wrong happens during byte conversion. It does not make sense at all.
A key contains arbitrary bytes. And those bytes don't necessarily represent valid UTF8 characters. So you shouldn't transform them to a String, because that is a lossy conversion. If you really need a String, then use Hex or Base64 encoding.
To make you realize what the error is, let's say that you use ASCII instead of UTF8. ASCII characters go from 0 to 127. All the other 128 byte values don't represent valid characters. So if the key contain any of those values, the transformation to a String loses them. It's basically the same thing with any encoding (except, IIRC, ISO8859-1).
I encountered a similar problem beforeļ¼ i forgot to import the configuration file which contains the key in project, my configuration file is conf/XX.properties
I have an issue with my java code. I'm trying to encrypt a file. However, when I run my java code I get "java.security.InvalidKeyException: Invalid AES key length: 162 bytes".
Here is the code:
byte[] rawFile;
File f = new File("./src/wonkybox.stl");
FileInputStream fileReader = new FileInputStream(f);
rawFile = new byte[(int)f.length()];
fileReader.read(rawFile);
/***** Encrypt the file (CAN DO THIS ONCE!) ***********/
//Generate the public/private keys
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG","SUN");
keyGen.initialize(1024, random);
KeyPair key = keyGen.generateKeyPair();
PrivateKey privKey = key.getPrivate();
PublicKey pubKey = key.getPublic();
//Store the keys
byte[] pkey = pubKey.getEncoded();
FileOutputStream keyfos = new FileOutputStream("./CloudStore/keys/pubkey");
keyfos.write(pkey);
keyfos.close();
pkey = privKey.getEncoded();
keyfos = new FileOutputStream("./CloudStore/keys/privkey");
keyfos.write(pkey);
keyfos.close();
//Read public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("AES");
FileInputStream keyfis = new FileInputStream("./CloudStore/keys/pubkey");
byte[] encKey = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
PublicKey pub1Key = keyFactory.generatePublic(pubKeySpec);
keyfis = new FileInputStream("./CloudStore/keys/privkey");
encKey = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
PrivateKey priv1key = keyFactory.generatePrivate(privKeySpec);
//Encrypt file using public key
Cipher cipher = Cipher.getInstance("AES");
System.out.println("provider= " + cipher.getProvider());
cipher.init(Cipher.ENCRYPT_MODE, pub1Key);
byte[] encryptedFile;
encryptedFile = cipher.doFinal(rawFile);
//Write encrypted file to 'CloudStore' folder
FileOutputStream fileEncryptOutput = new FileOutputStream(new File("./CloudStore/encrypted.txt"));
fileEncryptOutput.write(encryptedFile);
fileEncryptOutput.close();
The error occurs at the line "KeyPairGenerator keyGen = KeyPairGenerator.getInstance("AES");".
AES is a symmetric algorithm, hence they use of KeyPairGenerator is not supported. To generate a key with AES you call KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); //set keysize, can be 128, 192, and 256
By looking at the rest of your code, it looks like you are trying to achive asymmetric encryption (since you call getPublic() and getPrivate() etc), so I advice you to switch to using RSA or any other asymmetric algorithm that java supports. You will most likley only need to replace AES with RSA in your getInstance(); calls, and pherhaps some fine-tuning. Good luck
As far as I know, AES is symmetric encryption algorithm i.e. it needs only one key for encryption/decryption.
From the JavaDoc of java.security.KeyPairGenerator:
The KeyPairGenerator class is used to generate pairs of public and private keys.
Meaning that it should be used for asymmetric encryption algorithms. For symmetric encryption algorithms one should use javax.crypto.KeyGenerator.
However, I advise simply mimicking some tutorial on how to encrypt / decrypt byte array in Java using AES like this one.
It uses sun.misc.Base64Encoder / Base64Decoder classes to encode / decode byte array to / from String, however you may skip this step.
Hope this helps
How can you use a keypair generator for AES? AES is a symmetric key algorithm. Refer this link. That means if you encrypt data using a key "k", then you will have to decrypt it also using the same key "k". But when you generate key pair, as the name suggests, two keys are generated and if you encrypt using one of the keys, you can decrypt only using the other key. This is the base for PKI.
If you want to use keypair generator use an algorithm like "rsa" or "dsa" in the getInstance() method like this :
KeyPairGenerator keygen=KeyPairGenerator.getInstance("rsa");
I think your code should now work fine after making the above change.