Store and Retrieve DSA public and private keys in mysql - java

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.

Related

I had generate Public Key by Java spring security and I try to use that public key to encrypt data with Nodejs Crypto but it return error

I had generate public key using Java Spring Security, but I can not use that public key to encrypt the data using Nodejs crypto library. I think it is because of its format(X509).
My Nodejs code
module.exports.encryptRsa = (toEncrypt, pemPath) => {
let absolutePath = path.resolve(pemPath);
let publicKey = fs.readFileSync(absolutePath, "utf8");
let buffer = Buffer.from(toEncrypt);
let encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
My Java code
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgorithm);
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
String formatPrivate = privateKey.getFormat(); // PKCS#8
String formatPublic = publicKey.getFormat(); // X.509
FileWriter fos = new FileWriter("publicKey.pem");
fos.write("-----BEGIN RSA PUBLIC KEY-----\n");
fos.write(enc.encodeToString(publicKeyBytes));
fos.write("\n-----END RSA PUBLIC KEY-----\n");
fos.close();
Java's getEncoded() method returns the public key in format called 'spki' by Node crypto. Java's name for that format is "X.509", an unfortunate choice because it causes confusion with certificates of that name.
The proper PEM header for spki keys is simply -----BEGIN PUBLIC KEY-----. Just get rid of RSA in the header and footer.

Self generated Public Keys do have the same beginning

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.

Reconstructing private and public keys with Bouncy Castle?

If I get the actual key with getEncoded from a public or a private key in Bouncy Castle in Java (actual class seems to be BCECPublicKey and BCECPrivateKey). Is it possible to reconstruct the key objects to use them in code?
I found out here in Stack Overflow how to serialize the whole object to binary (and then to disk) and then back to binary and to an object of the appropriate class, but I believe that serialization contains implementation details and if I try to use those keys with anything else than Bouncy Castle, it'll fail. I'm not trying to do that now, but I want to future-proof my program.
This is how I'm creating the keys:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
keyPairGenerator.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
java.security.KeyPair keyPair = keyPairGenerator.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
The KeyFactory is used to convert between encoded keys and the Java classes that represent them. However, the KeyFactory instance doesn't convert directly between a byte array and a Key class. Instead, you must already know what format the encoding uses, and then create a KeySpec object using the byte array in the constructor. The format can be determined by called the getFormat() method on the key. Here is an example illustrating some of these points.
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class Main {
public static void main(String[] args) throws Exception{
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
keyPairGenerator.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
java.security.KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
System.out.println(privateKey.getFormat());
PublicKey publicKey = keyPair.getPublic();
System.out.println(publicKey.getFormat());
// A KeyFactory is used to convert encoded keys to their actual Java classes
KeyFactory ecKeyFac = KeyFactory.getInstance("EC", "BC");
// Now do a round-trip for a private key,
byte [] encodedPriv = privateKey.getEncoded();
// now take the encoded value and recreate the private key
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedPriv);
PrivateKey privateKey2 = ecKeyFac.generatePrivate(pkcs8EncodedKeySpec);
// And a round trip for the public key as well.
byte [] encodedPub = publicKey.getEncoded();
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedPub);
PublicKey publicKey2 = ecKeyFac.generatePublic(x509EncodedKeySpec);
System.out.println(publicKey2);
}
}

How to convert Byte array to PrivateKey or PublicKey type?

I am using RSA algorithm to generate public and private key
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(1024);
final KeyPair key = keyGen.generateKeyPair();
final PrivateKey privateKey=key.getPrivate();
final PublicKey publickey=key.getPublic();
after that these keys are encoded using Base64 encoder and save it into database.
How to convert this encoded String to Private and Public Key Type in java is to decrypt file.
when decoding this String using Base64Decoder will get a byte array. how to convert this Byte array to public or private key type?
If you have a byte[] representing the output of getEncoded() on a key, you can use KeyFactory to turn that back into a PublicKey object or a PrivateKey object.
byte[] privateKeyBytes;
byte[] publicKeyBytes;
KeyFactory kf = KeyFactory.getInstance("RSA"); // or "EC" or whatever
PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
PublicKey publicKey = kf.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

AES KeyPairGenerator Not Recognised

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.

Categories