I am able to generate Public key and Private key using spongy castle in Android by using the following code
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", "SC");
ECGenParameterSpec ecSpecCurve163k1 = new ECGenParameterSpec("sect163r2"); // Curve: B-163
keyGen.initialize(ecSpecCurve163k1);
aKeyPair = keyGen.generateKeyPair();
String pubStr = Crypto.base64Encode(aKeyPair.getPublic().getEncoded());
String privStr = Crypto.base64Encode(aKeyPair.getPrivate().getEncoded());
I get Affine coordinates by using the following code
PublicKey otherKey // key generated by the code above
ECPublicKey ecPubKey = (ECPublicKey) otherKey;
Log.d("public key Wx", ecPubKey.getW().getAffineX().toString(16));
Log.d("public key Wy", ecPubKey.getW().getAffineY().toString(16));
I am trying to get the projective coordinates for the above coordinates by using spongy castle. Is there any way to get it?
Related
I have android application which has payment gateway and another services.Iam using AES Model to encrypt and decrypt data between the app and the server.Iam using KEY and IV constants which stored in android class. My problem is how to encrypt these constants ( IV and Key) in the android application to prevent any attacker to make decompile for the APK file and show these constants.
You have to Encrypt the Key with a RSA Public Key and only the Server knows the privatekey for this public key and can decrypt it.
You decrypt the AES Key with the private key on the serverside and use the decrypted AES Key to decrypt your original message.
//Edit
This is an example for the Java Code in Android Studio. My RSA Public key is stored in the shared preferences.
When the app is installed it makes a call to a Server, where a RSA Key pair is produced, both keys are saved in a Database and the Public Key is sent to the Device and saved in the shared preferences. Whenever something Needs to be Encrypted the stored Public Key is created and used for Encryption and only the Server knows the private key.
byte[] ENCRYPTED_AES_KEY_IN_BYTE = null;
String ENCRYPTED_AES_KEY;
cipher = null;
cipher = Cipher.getInstance("RSA/NONE/OAEPwithSHA-1andMGF1Padding");
// Get the shared preferences where the public key is stored
// SharedPreferences preferences = getApplicationContext().getSharedPreferences(preferences,Context.MODE_PRIVATE);
// get the Publickey stored as string in the shared preferences
String stringkey = preferences.getString(PUBLICKEY,"");
// create a public RSA Key from the stored key
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(stringkey,Base64.DEFAULT));
KeyFactory keyFactory;
PublicKey key =null;
keyFactory = KeyFactory.getInstance("RSA");
key = keyFactory.generatePublic(spec);
//Encrypt the AES key with the RSA public key
cipher.init(Cipher.ENCRYPT_MODE, key);
ENCRYPTED_AES_KEY_IN_BYTES = AES_KEY.getEncoded();
ENCRYPTED_AES_KEY_IN_BYTE = cipher.doFinal(ENCRYPTED_AES_KEY_IN_BYTE);
ENCRYPTED_AES_KEY = Base64.encodeToString(ENCRYPTED_AES_KEY_IN_BYTE,Base64.DEFAULT);
//ENCRYPTED_AES_KEY is now the Encrypted AES Key as string
// EDIT #2
Create a RSA KEY pair at the server
$rsa = new Crypt_RSA();
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS8);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
extract($rsa->createKey());
$publickey = str_replace("-----BEGIN PUBLIC KEY-----\r\n","",$publickey);
$publickey = str_replace("-----END PUBLIC KEY-----","",$publickey);
$privatekey = str_replace("-----BEGIN PRIVATE KEY-----\r\n","",$privatekey);
$privatekey = str_replace( "-----END PRIVATE KEY-----","",$privatekey);
the privatekey is saved to a Database and the Publickey is sent to the Client to Encrypt data.
To Decrypt the Data on the Serverside again
$rsa = new Crypt_RSA();
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS8);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setEncryptionMode( CRYPT_RSA_ENCRYPTION_OAEP);
$IV = base64_decode($IV);
$AESkey = base64_decode($AESkey);
$rsa->loadKey($privatekey);
$AESkey = $rsa->decrypt($AESkey);
// replace empty spaces with a + , this is something which can happen when you use a http request
$encrypteddata = str_replace(" ", "+", $encrypteddata);
$encrypteddata = base64_decode($encrypteddata);
$method = "AES-256-CBC";
$decrypteddata = openssl_decrypt($encrypteddata, $method, $AESkey, OPENSSL_RAW_DATA,$IV);
In this Code is not included how you store the privatekey in a Database and how you get it back from the Database.
Which method stores Private and Public keys in AndroidKeyStore?
I have implemented below code to initialise keystore and generate private and public keys.
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyPair keyPair;
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 50);
KeyPairGenerator generator= KeyPairGenerator.getInstance("RSA","AndroidKeyStore");
KeyPairGeneratorSpec keyPairGeneratorSpec = new KeyPairGeneratorSpec.Builder(context).
setAlias("alias").
setSubject(new X500Principal("O=Authority")).
setSerialNumber(BigInteger.ONE).
setStartDate(start.getTime()).
setEndDate(end.getTime()).build();
if (generator != null) {
generator.initialize(keyPairGeneratorSpec);
}
keyPair = generator.generateKeyPair();
To your question, this line
generator.generateKeyPair(); implement the keypair generating and storing processs.
You might be confused when seeing codes in java.security.KeyPairGenerator like this
public KeyPair generateKeyPair() {
// ...
return null;
}
But actually since KeyPairGenerator is an abstract class, the 'true' class here using is
java.security.KeyPairGenerator$Delegate, which delegates the generateKeyPair like this
You can also check the difference of alias list in "AndroidKeyStore" before and after this process.
I would like to share the gist about how to view alias list of any keystore. Hope it might help you testing: https://gist.github.com/davidkhala/4aa1d6b44f287699aeac028786633c7a
When you generate a key pair with AndroidKeyStore, it is already automatically stored. You can retrieve it when you need it using the alias you specified ("alias" in your example).
Note, however, that when you get the PrivateKey, you do not actually get the private key secrets. Those stay in secure hardware and never leave it, so they can't leak. But you get a PrivateKey object which you can use just as though you had the secrets; your requests to encrypt or sign are sent to the secure hardware, which uses the secrets to perform the operation and hands the result back to you.
I have been using the keystore to generate RSA key/pair and the code has been working for API levels 18-22.
Today when I ran it on API-23, I am not able to retrieve the Private key from the keystore.
Below is the code that I have been using:
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(utility.getConfigValue(configuration, OuterKeys.KEYSTORE_NAME))
.setSubject(
new X500Principal("CN=Sample Name, O=Android Authority"))
.setSerialNumber(BigInteger.ONE).setStartDate(start.getTime())
.setEndDate(end.getTime()).build();
KeyPairGenerator generator = null;
generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] publicKeyBytes = publicKey.getEncoded();
String pubKeyStr = Base64.encodeToString(publicKeyBytes, Base64.NO_PADDING);
byte[] privKeyBytes = privateKey.getEncoded();
String privKeyStr = Base64.encodeToString(privKeyBytes, Base64.NO_PADDING);
Log.d("^^^^^^^^^1",pubKeyStr);
Log.d("^^^^^^^^^2",privKeyStr);
I debugged this and found that the private key generated is null.
Whereas I can print the public key string as it is being retrieved.
Can anyone help out please.
It looks like you are retrieving the PrivateKey instance from Android Keystore just fine. You should be able to use this PrivateKey instance with Cipher and Signature primitives just fine too.
What's "not working" is that that PrivateKey instance's getEncoded returns null. As James K Polk mentioned, this is working as intended. getEncoded is supposed to return the private key's key material (usually in PKCS#8 DER-encoded format) or null if key material export is not supported. Android Keystore by design does not reveal/export key material of private keys and thus getEncoded returns null. On older Android platform versions it may have been returning an empty byte array instead.
I have followed this below code that I need to generate a keypair stored in KeyStore
// generate a key pair
Context ctx = getContext();
Calendar notBefore = Calendar.getInstance()
Calendar notAfter = Calendar.getInstance();
notAfter.add(1, Calendar.YEAR);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(ctx)
.setAlias("key1")
.setSubject(
new X500Principal(String.format("CN=%s, OU=%s", alais,
ctx.getPackageName())))
.setSerialNumber(BigInteger.ONE).setStartDate(notBefore.getTime())
.setEndDate(notAfter.getTime()).build();
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
kpGenerator.initialize(spec);
KeyPair kp = kpGenerator.generateKeyPair();
By this way, my keypair is generated and stored into Keystore but when calling this function: getPrivateKey.encoded() , it will return a null bytes array.
My will is I want generate normally, I can get both PrivateKey and PublicKey Encode (This is my own purpose). Then I want to store them into KeyStore to keep secret.
I have tried this: keyStore.setEntry(alias, privateKey, cert) but I got exception due to wrong params maybe. I don't understand what certificate I should get from?
I really appreciate your comments
I'm currently trying to develop an encryption app for Android using ECDH and BouncyCastle. So far what I've implemented is Public and Private Key generation on the application as per the code below.
My next task is to send the public keys over SMS. I would like to find out what methods can be used to get the job done. Currently I'm trying it out by assigning the generated keys to a string then I'm sending the string out but I'm still unable to get it to work properly.
Any assistance would be greatly appreciated
Thanks and Happy Holidays!
try
{
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDH", "SC");
//Define the Elliptic Curve Field, Points A and B
EllipticCurve curve = new EllipticCurve(new ECFieldFp(Presets.CurveQ),Presets.PointA,Presets.PointB);
//Define the points on the Elliptic Curve
ECParameterSpec ecSpec = new ECParameterSpec(
curve,
ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
1); // h
//Generate the random point on the Elliptic Curve
g.initialize(ecSpec, new SecureRandom());
//Generate Private Key for User A
KeyPair aKeyPair = g.generateKeyPair();
aKeyAgree = KeyAgreement.getInstance("ECDH", "SC");
aKeyAgree.init(aKeyPair.getPrivate());
//Save Personal Keys
Presets.myPrivateKey = aKeyPair.getPrivate().getEncoded().toString();
Presets.myPublicKey = aKeyPair.getPublic().getEncoded().toString();
I managed to find out what I was doing wrongly.
The output I was getting from
Presets.myPublicKey = aKeyPair.getPublic().getEncoded().toString();
was something along the lines of [#B1ef9157 which could not be sent over SMS like I hoped for.
Java: Syntax and meaning behind "[B#1ef9157"? Binary/Address?
Instead I did this
byte[] pubEnc = aKeyPair.getPublic().getEncoded();
String s = Base64.encodeBytes(pubEnc);
making use of the Base64 encoder from http://iharder.sourceforge.net/current/java/base64/
and now I am able to successfully send the string over sms.
Thanks Craigy!