Generating ECDSA public key at host side from W parameter - java

I want to send the public key of the private-public key pair (ECDSA) generated in my applet to the host application/terminal.
In RSA normally i would send the modulus and exponent and will generate the public key at the host side.
In ECDSA i read from the link that we can do the same if you take the W parameter bytes outside the card Click here: Stackoverflow Answer: encode public key on Java
I have the W bytes from the card now. can someone suggest how to create the public key from this?

I wrote this method to convert an EC Public key into java.security.interfaces.ECPublicKey key object. To do this I use Bouncy Castle provider (bcprov-ext-jdk16-1.46.jar). You can download the latest version from here.
/**
* This method converts the EC public key (ECPublicKey#getW()) into ECPublicKey
* #param cardPublicKey as W
* #param curveName (for example "P-224")
* #return java.security.interfaces.ECPublicKey
*/
public ECPublicKey ucPublicKeyToPublicKey(byte[] cardPublicKey, String curveName) {
//for example curveName = "P-224";
java.security.interfaces.ECPublicKey ecPublicKey = null; // java.security.interfaces.ECPublicKey
java.security.KeyFactory kf = null;
org.bouncycastle.jce.spec.ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
org.bouncycastle.math.ec.ECCurve curve = ecNamedCurveParameterSpec.getCurve();
java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecNamedCurveParameterSpec.getSeed());
java.security.spec.ECPoint ecPoint = ECPointUtil.decodePoint(ellipticCurve, cardPublicKey);
java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve, ecNamedCurveParameterSpec);
java.security.spec.ECPublicKeySpec publicKeySpec = new java.security.spec.ECPublicKeySpec(ecPoint, ecParameterSpec);
try {
kf = java.security.KeyFactory.getInstance("EC", "BC");
} catch (Exception e) {
System.out.println("Caught Exception kf : " + e.toString());
}
try {
ecPublicKey = (ECPublicKey) kf.generatePublic(publicKeySpec);
} catch (Exception e) {
System.out.println("Caught Exception public key: " + e.toString());
}
return ecPublicKey;
}

Related

RSA 512 bit implementation in android with NO PADDING

My question is that on how to use RSA 512 bit in Android; I was able to generate the public and private keys by looking up on the internet but not sure if its with NO padding as I could not find any solution for it.The public key would be sent to the server also with the integer encrypted with the private key.
I am new to it so it would be great to have some help. Thanks!
genreateKeys("RSA",512)
The following code:
private static void generateKeys(String keyAlgorithm, int numBits) {
try {
// Get the public/private key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgorithm);
keyGen.initialize(numBits);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("\n" + "Generating key/value pair using " + privateKey.getAlgorithm() + " algorithm");
// Get the bytes of the public and private keys
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// Get the formats of the encoded bytes
String formatPrivate = privateKey.getFormat(); // PKCS#8
String formatPublic = publicKey.getFormat(); // X.509
System.out.println("Private Key : " + HttpRequest.Base64.encode(String.valueOf(privateKeyBytes)));
System.out.println("Public Key : " + HttpRequest.Base64.encode(String.valueOf(publicKeyBytes)));
// The bytes can be converted back to public and private key objects
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey2 = keyFactory.generatePrivate(privateKeySpec);
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey2 = keyFactory.generatePublic(publicKeySpec);
// The original and new keys are the same
System.out.println(" Are both private keys equal? " + privateKey.equals(privateKey2));
System.out.println(" Are both public keys equal? " + publicKey.equals(publicKey2));
} catch (InvalidKeySpecException specException) {
System.out.println("Exception");
System.out.println("Invalid Key Spec Exception");
} catch (NoSuchAlgorithmException e) {
System.out.println("Exception");
System.out.println("No such algorithm: " + keyAlgorithm);
}
}
It gives me the output of public and private keys but its not with NO PADDING also how can I use the private key to encrypt my integer value?

Encrypt and decrypt a SecretKey with RSA public and private keys

I am trying to encrypt a secretKey with my publicKey, then decrypt it somewhere else with the private key. I can encrypt and decrypt fine, However I am getting a completely different key back when I do this.
Here is the code that creates the public/ private keypair
public static KeyPair generateKeyPair()
{
KeyPair returnPair = null;
try
{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunJSSE");
System.out.println("provider:" + kpg.getProvider().getName());
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
kpg.initialize(1024, random);
returnPair = kpg.generateKeyPair();
}catch(Exception e)
{
e.printStackTrace();
}
return returnPair;
}
I specified the SunJSSE provider, although I am not getting any different result than when I ran with DiffieHellman from SunJCE or the RSA/ SunRSASign provider. I am new to java security so these concepts are still a little above my head.
Here is the code I use to generate the secret key
public static SecretKey generateSecretKey(String keyPassword)
{
SecretKey key = null;
try
{
SecretKeyFactory method = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
//System.out.println("salt length: " + new SaltIVManager().getSalt().length);
PBEKeySpec spec = new PBEKeySpec(keyPassword.toCharArray(), new SaltIVManager().getSalt(), 10000, 128);
key = method.generateSecret(spec);
System.out.println("generate secret key length: " + key.getEncoded().length);
}catch(Exception e)
{
e.printStackTrace();
}
return key;
}
And here are the two methods I use to encrypt/ decrypt my secret key
public static byte[] encryptSecretKey(SecretKey secretKey, PublicKey publicKey)
{
byte[] encryptedSecret = null;
try
{
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
System.out.println("provider: " + cipher.getProvider().getName());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
System.out.println("original secret key: " + Base64.getEncoder().encodeToString(secretKey.getEncoded()) + " \n secretkey encoded length: " + secretKey.getEncoded().length);
encryptedSecret = cipher.doFinal(secretKey.getEncoded());
System.out.println("encrypted secret: " + Base64.getEncoder().encodeToString(encryptedSecret));
}catch(Exception e)
{
e.printStackTrace();
}
return encryptedSecret;
}
public static SecretKey decryptSecretKey(byte[] encryptedKey, PrivateKey privateKey)
{
SecretKey returnKey = null;
try
{
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
System.out.println("provider: " + cipher.getProvider().getName());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
System.out.println("encryptedkey length: " + encryptedKey.length);
byte [] encodedSecret = cipher.doFinal(encryptedKey);
System.out.println("encoded Secret after decrypt: " + Base64.getEncoder().encodeToString(encodedSecret));
returnKey = new SecretKeySpec(encodedSecret, 0, encodedSecret.length, "PBEWithMD5AndDES");
System.out.println("secret key: " + Base64.getEncoder().encodeToString(returnKey.getEncoded()));
System.out.println("secret key length post decrypt: " + returnKey.getEncoded().length);
}catch(Exception e)
{
e.printStackTrace();
}
return returnKey;
}
The RSA algorithm is the only one I have gotten to work with my keys. If I specify the DiffieHellman alg. for the keypair, I am unable to encrypt/ decrypt at all. If anyone has any insight into what I have done wrong, any help would be greatly appreciated. When I call this in its current state, I start with a secretkey of this value = cGFzczEyMw== and end with a key of this value after encryption/ decryption
SvMNufKu2JA4hnNEwuWdOgJu6FxnNmuLYzxENhTsGgFzc/i3kQIXbeVaJUkJck918BLCnm2u2QZCyVvJjYFXMLBFga0Zq0WMxSbIZvPz1J/EDi9dpsAkbFhLyBWmdDyPr+w7DMDsqHwKuA8y/IRKVINWXVrp3Hbt8goFZ0nGIlKVzMdJbGhNi3HZSAw4R6fXZNKOJ3nN6wDldzYerEaz2MhJqnZ3Dz4psA6gskomhjp/G0yhsGO8pllMcgD0jzhL86RGrBhjj04Bj0ps3AAACkQLcCwisso8dWigvR8NX9dnI0C/gc6FqmNenWI1/AoPgmcRyFdlO7A2i9JXoSj+YQ==
You first should know what you are trying to do before doing it:
RSA without padding is completely insecure;
you use a key for Password Based Encryption which only makes sense with - well - a password;
you come out with a DES key, which again is completely insecure;
you probably generate it with a salt, which is random, so the output is random.
The whole protocol doesn't make sense. That you're trying to encrypt directly with DH (a scheme to perform key agreement) shows that you haven't studied crypto enough.
With cryptography it's not about getting things to work. It's about getting things secure. You cannot do that by just trying things out. Learn at least the basics of cryptography then code.
The issue in fact was the way in which I was storing/ retrieving my keys. I had used a keystore for the private and a file for the public. The way in which I retrieved these keys was causing them to become malformed, thus the failure in my cipher and the need to run with NOPADDING in order to get any sort of output.
Here is the new storage code I am using for RSA keys- writing them to a file.
public static boolean saveKeys(Key privateKey, Key publicKey, char[] password, String alias)
{
boolean saved = false;
try
{
KeyPair kp = generateKeyPair();
KeyFactory kf = KeyFactory.getInstance("RSA");
if(privateKey != null)
{
File privKeyFile = new File(System.getProperty("user.home") + "/.etc/privkey");
if(!privKeyFile.exists())
{
privKeyFile.createNewFile();
}
System.out.println("private key: " + Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
RSAPrivateKeySpec pubSpec = kf.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(System.getProperty("user.home") + "/.etc/privkey")));
oout.writeObject(pubSpec.getModulus());
oout.writeObject(pubSpec.getPrivateExponent());
oout.close();
}if(publicKey != null)
{
File pubKeyFile = new File(System.getProperty("user.home") + "/.etc/pubkey.pub");
if(!pubKeyFile.exists())
{
pubKeyFile.createNewFile();
}
System.out.println("public key: " + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
RSAPublicKeySpec pubSpec = kf.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(System.getProperty("user.home") + "/.etc/pubkey.pub")));
oout.writeObject(pubSpec.getModulus());
oout.writeObject(pubSpec.getPublicExponent());
oout.close();
}
}catch(Exception e)
{
e.printStackTrace();
}
return saved;
}

Base64 encoded string to Public Key using RSA From C# to Java

I am converting legacy application from .net to java. Legacy method using encryption using public key.
string text = "<base64encodedstring here>";
IBuffer buffer = CryptographicBuffer.DecodeFromBase64String(text);
AsymmetricKeyAlgorithmProvider asymmetricKeyAlgorithmProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.get_RsaPkcs1());
CryptographicKey cryptographicKey = asymmetricKeyAlgorithmProvider.ImportPublicKey(buffer, 3);
IBuffer buffer2 = CryptographicBuffer.ConvertStringToBinary(data, 0);
IBuffer buffer3 = CryptographicEngine.Encrypt(cryptographicKey, buffer2, null);
byte[] array;
CryptographicBuffer.CopyToByteArray(buffer3, ref array);
//return CryptographicBuffer.EncodeToBase64String(buffer3);
Here is my Java code to convert the given text into the public key
public static PublicKey getKey(String key) throws Exception{
try{
byte[] byteKey = Base64.getDecoder().decode(key);
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA","BC");
return kf.generatePublic(X509publicKey);
}
catch(Exception e){
throw e;
}
}
Here is my main method
public static void main(String[] args) {
String text = "base64encodedstring";
try {
Security.addProvider(new BouncyCastleProvider());
decode(text);
PublicKey pubKey=getKey(text);
byte[] input = "plaintext".getBytes();
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(input);
System.out.println("cipher: " + new String(cipherText));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But When I try to get the public key I get the exception below
java.security.spec.InvalidKeySpecException: encoded key spec not recognised
at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(Unknown Source)
at com.test.EncryptionUtil.getKey(EncryptionUtil.java:38)
at com.test.EncryptionUtil.main(EncryptionUtil.java:60)
Am I doing something wrong? I am new to cryptography.
With some more research I found the way how it is doing in C#, but not able to convert it into java
public static CryptographicKey GetCryptographicPublicKeyFromCert(string strCert)
{
int length;
CryptographicKey CryptKey = null;
byte[] bCert = Convert.FromBase64String(strCert);
// Assume Cert contains RSA public key
// Find matching OID in the certificate and return public key
byte[] rsaOID = EncodeOID("1.2.840.113549.1.1.1");
int index = FindX509PubKeyIndex(bCert, rsaOID, out length);
// Found X509PublicKey in certificate so copy it.
if (index > -1)
{
byte[] X509PublicKey = new byte[length];
Array.Copy(bCert, index, X509PublicKey, 0, length);
AsymmetricKeyAlgorithmProvider AlgProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptKey = AlgProvider.ImportPublicKey(CryptographicBuffer.CreateFromByteArray(X509PublicKey));
}
return CryptKey;
}
What is the purpose of EncodeOID method and how it can be achieved in Java. The link below explains the creation of base64 encoded public key string and decode it in C#
http://blogs.msdn.com/b/stcheng/archive/2013/03/12/windows-store-app-how-to-perform-rsa-data-encryption-with-x509-certificate-based-key-in-windows-store-application.aspx
There is no direct way to read microsoft Capi1PublicKey into java. I first converted the Capi1PublicKey to X509-encoded public key in WinRT. then I used created key in java.
Obviously the key isn't X509-encoded. Find out how it is encoded and use an appropriate KeySpec.
C# uses AsymmetricAlgorithmNames.get_RsaPkcs1 you need to find equivalent for your JAVA code.
You may want to have look at this Import Public RSA Key From Certificate

How to send and receive a DSA public/private signed message in Java

I cannot find any good (complete) documentation on how to exchange a public/private key signed message in Java.
I have yet to find a concise document on the minimum steps needed to generate a public key and private key using DSA, sign a byte[], and verify it.
The documentation from Oracle is too broken up and requires running across multiple JVMs.
I have successfully signed a byte array with a private key and verified it with a public key.
Example.
byte[] data = "hello.".getBytes();
/* Test generating and verifying a DSA signature */
try {
/* generate a key pair */
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024, new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
/* create a Signature object to use
* for signing and verifying */
Signature dsa = Signature.getInstance("SHA/DSA");
/* initialize the Signature object for signing */
PrivateKey priv = pair.getPrivate();
dsa.initSign(priv);
/* Update and sign the data */
dsa.update(data);
/* Now that all the data to be signed
* has been read in, sign it */
byte[] sig = dsa.sign();
/* Verify the signature */
/* Initialize the Signature object for verification */
PublicKey pub = pair.getPublic();
dsa.initVerify(pub);
/* Update and verify the data */
dsa.update(data);
boolean verifies = dsa.verify(sig);
Assert.assertTrue(verifies);
} catch (Exception e) {
System.err.println("Caught exception " + e.toString());
}
In this version, I serialize the public key into a byte array and then create a PublicKey from that byte array.
byte[] data = "hello.".getBytes();
/* Test generating and verifying a DSA signature */
try {
/* generate a key pair */
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024, new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
/* create a Signature object to use
* for signing and verifying */
Signature dsa = Signature.getInstance("SHA/DSA");
/* initialize the Signature object for signing */
PrivateKey priv = pair.getPrivate();
dsa.initSign(priv);
/* Update and sign the data */
dsa.update(data);
/* Now that all the data to be signed
* has been read in, sign it */
byte[] sig = dsa.sign();
/* Verify the signature */
/* Initialize the Signature object for verification */
PublicKey pub = pair.getPublic();
/* Encode the public key into a byte array */
byte[] encoded = pub.getEncoded();
/* Get the public key from the encoded byte array */
PublicKey fromEncoded = KeyFactory.getInstance("DSA", "SUN").generatePublic(new X509EncodedKeySpec(encoded));
dsa.initVerify(fromEncoded);
/* Update and verify the data */
dsa.update(data);
boolean verifies = dsa.verify(sig);
Assert.assertTrue(verifies);
} catch (Exception e) {
System.err.println("Caught exception " + e.toString());
}

How to convert public key and signature value in human readable format

I am trying to generate public key and signature in readable format which can be used in rest service .i have write following code .
public static void GenearetSignature(String url,String signatureValue,String publicKey){
KeyPairGenerator keyGen;
try {
keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
KeyPair pair = keyGen.generateKeyPair();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();
System.out.println("Priavte key"+priv);
System.out.println("Public key");
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initSign(priv);
dsa.update(url.getBytes());
byte[] signatureValueArray = dsa.sign();
signatureValue=new String(signatureValueArray,"UTF8");
byte[] publicKeyArray=pub.getEncoded();
publicKey = new String(publicKeyArray);
System.out.println("publicKey is "+publicKey);
System.out.println("signatureValue is "+signatureValue);
} catch (NoSuchAlgorithmException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}
But this is not generating in alphanumeric value .how can i achieve that .please help me
If you want hexadecimal represenation of byte array use
javax.xml.bind.DatatypeConverter.printHexBinary(byte[] array)
You can use base64 for communicating over rest. Another example is HTTP Basic authentication that encode password using base64 to putting it in HTTP header

Categories

Resources