i have a problem with RSA encryption and decryption. I'm developing in android and would like to outsource the RSA encryption and decryption. My source code worked well before i tried to outsource it.
I created a private key and public key and saved it as private.key and public.key. The error is a ClassNotFoundException caused by this method:
public Key getPrivateKey(){
try {
InputStream fis = activity.getResources().openRawResource(R.raw.private);
ObjectInputStream ois = new ObjectInputStream(fis);
Key RSAprivateKey = (Key)ois.readObject();
return RSAprivateKey;
}
catch (FileNotFoundException e) {
Log.e("FileNotFound","FileNotFound");
e.printStackTrace();
} catch (IOException e) {
Log.e("IOEXception","IOEXception");
e.printStackTrace();
} catch (ClassNotFoundException e) {
Log.e("ClassNotFound","ClassNotFound");
Log.e("Errro", "Error: "+ e.getMessage());
Log.e("error", e.toString());
e.printStackTrace();
}
return null;
}
I looked at the logcat and got this error message:
E/ClassNotFound(1205): ClassNotFound
03-19 13:54:52.176: E/Errro(1205): Error:
com.android.org.bouncycastle.jce.provider.JCERSAPrivateCrtKey
03-19 13:54:52.176: E/error(1205): java.lang.ClassNotFoundException:
com.android.org.bouncycastle.jce.provider.JCERSAPrivateCrtKey
I hope you understand my problem, because English is not my native language.
Edit: I found out that the problem is not caused by outsourcing the code. So i guess the topic can be marked as solved.
RSAPublicKey and RSAPrivateKey are interfaces. When you get a Key you actually receive an implementation by the cryptographic provider of this interface. These providers differ for different Java platforms (although, at least officially, Android/Dalvik isn't even a Java platform). So you should never expect serialization to work unless you are working on the same platform.
There are however ways to serialize public and private keys in Java; the Key interface contains the getEncoded() method which returns the most common binary encoding of the key. In the case of RSAPublicKey this is the PKCS#1 encoding within X5.09 SubjectKeyIdentifier. In the case of RSAPrivateKey this is the inner PKCS#8 encoding wrapped around the PKCS#1 defined structure. These can be represented using X509EncodedKeySpec and PKCS8EncodedKeySpec and converted back into keys using an RSA KeyFactory.
Note that the private key will not be encrypted if you call getEncoded. Normally you don't want to transport private keys at all, and if you do you should really encrypt them. You can do this using the Cipher.wrap and Cipher.unwrap methods.
Related
I am trying to convert my private key string to a PrivateKey object in my Android application. I have read a lot of posts on StackOverflow about this topic, but I just can solve my issue.
I am using the following function to convert my key:
String privateKey = "MIGkAgEBBDCAHpFQ62QnGCEvYh/pE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGgBwYFK4EEACKhZANiAAQLW5ZJePZzMIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=";
#Nullable
private static PrivateKey getKey(String key) {
try {
byte[] byteKey = Base64.decode(key.getBytes(), Base64.DEFAULT);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(byteKey));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
According to ASN.1 JavaScript decoder, I do have a valid private key.
Nonetheless, getKey() always fails with the following exception:
java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0c0000be:ASN.1 encoding routines:OPENSSL_internal:WRONG_TAG
I cannot make sense of this error message. Even after a lot of googling. Does anybody know, what I am doing wrong? Am I using the wrong key spec (though many of the answers here suggest the use of PKCS8EncodedKeySpec().
The private key you see in the code above was generated by jwt.io using an ES384 algorithm.
I search a lot but I didn't find the useful answer. I develop java and android security application. I found some problem that when I create RSA key on PC and I transfer RSA public key to android. When I encrypt my data with public key on android and I decrypt the data by using private key on PC, it shows Badpadding Exception. I search on the google on this exception. I found some user that has the same problem to me but the answer is no use. They told me to use Base64 to encode it but the key is still wrong. here is my code.
public void generateKeys(){
try {
KeyPairGenerator generator;
generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(1024, new SecureRandom());
KeyPair pair = generator.generateKeyPair();
pubKey = pair.getPublic();
privKey = pair.getPrivate();
//================================================
System.out.println("My Public KEY "+pubKey.toString());
System.out.println("My Private KEY "+privKey.toString());
byte[]pk_byte = pubKey.getEncoded();
byte[]sk_byte = privKey.getEncoded();
FileOutputStream keyfos_pub = new FileOutputStream(new File(Environment.getExternalStorageDirectory(),"RSAKey/publicKey.txt"));
keyfos_pub.write(pk_byte);
keyfos_pub.close();
FileOutputStream keyfos_pri = new FileOutputStream(new File(Environment.getExternalStorageDirectory(),"RSAKey/privateKey.txt"));
keyfos_pri.write(sk_byte);
keyfos_pri.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I print out the key, it looks like this.
RSA Private CRT Key
modulus: dba017a7653612c53f3a46bb99f5098c7bf9012d06f3d20f8f01a67d17aeefd83070a2ff181468679a2d5abae6f7c074b7b3888a4a57533acc3d2d1dfdd86cdc032d3eafd6cf8423edfa3451333bf1d7377352dd3feb9268032831abd72c5c932fed9b4c667f3da062f4beb7a321f2c434d232ee746885dce13a1656eb42fe6b
public exponent: 10001
private exponent: 72f10f5019653a5fa6de9e0432e80e4e4ad79fe8ebd99157793598e7a10c7a14000e0310548ee1b14efc6b9ea3a08845cd9a955c22da1f0207c000abd09d83228e05a42f9bd88733afc2a4c1e30770e7ac3c41c55adae734e4f8126da494a88f362d716d6b37a2d7bfbe53824cfb9dc7a0289aa432226bbece49129f47de2a61
primeP: efa2665a1e08dce4450ad608e17df1e3650ab2cfc44e9b3b6a346611b270b245e21c28f71971d5062368e66b99297085f23104577e529ef08b263e63387cf17b
primeQ: ea9fde740a15d7f68f5aadb72a588f65da3761119b0c73930f111a43d513d19f42185afcd0291f03a9861a7757108f0e83d4d904ddf541a2debd79344387bbd1
primeExponentP: 45202ab84a3bb244a2e9fa4dfb861235cf5ae3b3ed63e381a32454613c8127dbe2daceb26103a638ac14418bbe55e6e0acb99910081f9b3bb65824dd08597a6b
primeExponentQ: 53ca665a90a37e6e1a822ad9e8309a7da871f0a3a5f8cb69b08ece0f7d90476395ea36cc64d6dab1a72032617e6176859b852f3ff2b8bd091a7d164518fce791
crtCoefficient: 695a3707d033aa2474a7a64959589842099a220540167b48f42bbbd1d786d1a84c378f9a1bc0311948287cbf7669aa44156dd9f24bfe88baf931e5da70a06c4
RSA Public Key
modulus: dba017a7653612c53f3a46bb99f5098c7bf9012d06f3d20f8f01a67d17aeefd83070a2ff181468679a2d5abae6f7c074b7b3888a4a57533acc3d2d1dfdd86cdc032d3eafd6cf8423edfa3451333bf1d7377352dd3feb9268032831abd72c5c932fed9b4c667f3da062f4beb7a321f2c434d232ee746885dce13a1656eb42fe6b
public exponent: 10001
I send my key to PC and print out it looks like this
Sun RSA private CRT key, 1024 bits
modulus: 133510687177139403090984227659818165988216147752229771757259279456909046924729578431711819486905574365970242930474912203422914618872480707080105400973005394104312017850522474151319747965391515392091886771183127658574637486403332621957057719375091145573274843838361168501101321026667287976397870949812555235301
public exponent: 65537
private exponent: 9980146428442039393666657480590341260299844482325612277626580558453963728645653672535456363067433797990268399780224833064816191126482490562360748269935354262219600344146818595176602910809143102802601846580823241077395526479491554799584457750285244532837191028964347562514222968145677820868899082320352227173
prime p: 12299841631131712301068734715117232218530765196368758184959862403767638338760002562429845237522849739220962134079733702092483313582445665328865919334315231
prime q: 10854667172235374767842313747899047475769598966944705527971116954964144369647441254504149073040778536441723902849901407264741891511747045046848533162966971
prime exponent p: 9681923647204217071082501281466465900019303827612974308340469989251337818636053102684450861548877311242977166683023364260601327205871598989662862911311993
prime exponent q: 1654443602597908945419791446477006656323336803344838236704510234877044083623118096514059921732827819407607611968318128037101282547428799502158627916518563
crt coefficient: 8339065711012644104593134475846199184972354402766421557421676186133596071951423663692155855342215056476322973047333984032026031966395156454879551656339085
It is clear that the key was changed because there is a word "1024 bits" appear in the key and the number of modulas is not the same as well
How can I manage this problem. I'd like a professional to help me please
That does look like a different key. Please try again as you've probably send an old key or something. Make sure you don't regenerate the key pair, it will be different each time. Use the private key to print out the modulus as BigInteger instead; BigInteger instances will always print out as decimals making for an easier comparison. Or even better, use BigInteger.toString(16) to get a hexadecimal representation.
If you use a good random number generator (like the default one in Java) then the modulus should be unique for the key pair. Therefore it, or the SHA1 hash over the modulus is normally used to identify the key.
They're the same thing, but Android prints it out in base 16 (hexadecimal) whereas your desktop's Java is printing it in base 10 (decimal). You'll see variations of the output of toString() between different implementations.
For instance, look at the public exponent and note that hex 0x10001 is equal to decimal 65537. This exponent is commonly known as RSA F4. However as this public exponent is used for a lot of keys, you cannot use it to distinguish between keys.
I want to know:
Can we use Context.MODE_PRIVATE in SQLite while Database creating to protect from unwanted Database access.
I am not getting any example on google.
How to use this Context.MODE_PRIVATE in Database.
Please assist me. Provide any link or sample.
IN THIS LINK they are talking about file. so Database is also file.
How can i implement this?
As commonsware mentioned, SQLite databases on internal storage are private by default. But as mentioned by others rooted phone as always access to your file.
Rather you can use any encryption algorithm to save the data in DB which will help you to restrict the readability unless intruder know the encryption algorithm.
You cant set "Context.MODE_PRIVATE" flag in SQLite.
While creating database, following syntax is useful
openOrCreateDatabase(String path, int mode, SQLiteDatabase.CursorFactory factory)
For example,
openOrCreateDatabase("StudentDB",Context.MODE_PRIVATE,null);
See my tutorial on this site.
Option 1: Use SQLcipher.
Option 2: Secure Method Ever No Chance To Hack. It is not perfect, but it is better than nothing.
1) Insert data using this Function:
public static String getEncryptedString(String message) {
String cipherText = null;
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(("YOUR-SECURE-PASSWORD-KEY").getBytes(), "AES"));
byte[] bytes = cipher.doFinal(message.getBytes());
cipherText = Base64.encodeToString(bytes, Base64.DEFAULT);
} catch(Exception ex) {
cipherText = "Error in encryption";
Log.e(TAG , ex.getMessage());
ex.printStackTrace();
}
return cipherText;
}
2) Get data from the database and pass into this function parameter:
//This function returns output string
public static String getDecryptedString(String encoded) {
String decryptString = null;
try {
byte[] bytes = Base64.decode(encoded, Base64.DEFAULT);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(("YOUR-SECURE-PASSWORD-KEY").getBytes() , "AES"));
decryptString = new String(cipher.doFinal(bytes), "UTF-8");
} catch(Exception ex) {
decryptString = "Error in decryption";
ex.printStackTrace();
}
return decryptString;
}
3) Benefits of these methods:
- Not possible to decrypt without the right Key.
- AES Encryption is a very secure encryption method.
4) Store your AES key in the c++ file.
I'm writing both a server and an Android client application. The Android client sends measurements to the server. In order to ensure the data integrity, a digital signature is appended to each measurement.
Since I need everything to be Gson-compatible, storing the public key itself is not possible. I'm storing the G, P, Q and Y factors instead.
Here's a snippet from the request class:
public PublicKey getPublicKey() {
try {
DSAPublicKeySpec keySpec = new DSAPublicKeySpec(publicKeyY, publicKeyP,
publicKeyQ, publicKeyG);
KeyFactory fact = KeyFactory.getInstance("DSA");
PublicKey pubKey = fact.generatePublic(keySpec); // A
return pubKey;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void setPublicKey(PublicKey publicKey) {
try {
KeyFactory fact = KeyFactory.getInstance("DSA");
DSAPublicKeySpec pub = fact.getKeySpec(publicKey, DSAPublicKeySpec.class); // B
publicKeyG = pub.getG();
publicKeyP = pub.getP();
publicKeyQ = pub.getQ();
publicKeyY = pub.getY();
} catch (Exception e) {
e.printStackTrace();
}
}
The constructor makes use of the setPublicKey-method. When I create such request on the client side and send it to the server, both result in an exception.
On the client:
java.lang.RuntimeException: not implemented yet DSA Public Key
y: 2f9286201b266f38d682e99814612f7d37c575d3a210de114bdf02092f4a835109f28a590cfc568bb6525d59b8275fe791f3ddf20e85df44fd2e8622289f6dbc27c73d31d1769feae19573df22a9ca8ef80a9f7230b0b4a2671cc03fdb2788b55b4e9a68a7a5a93a214cc5aa39ccb5155a13354870d45a38760a80fd34333073
class java.security.spec.DSAPublicKeySpec
at org.bouncycastle.jce.provider.JDKKeyFactory.engineGetKeySpec(JDKKeyFactory.java:148)
at java.security.KeyFactory.getKeySpec(KeyFactory.java:210)
Next thing in the stack trace points at the rule I marked as B
On the server:
java.lang.NullPointerException
at sun.security.provider.DSAPublicKey.<init>(DSAPublicKey.java:74)
at sun.security.provider.DSAPublicKeyImpl.<init>(DSAPublicKeyImpl.java:46)
at sun.security.provider.DSAKeyFactory.engineGeneratePublic(DSAKeyFactory.java:86)
at java.security.KeyFactory.generatePublic(KeyFactory.java:304)
at sensserve.protocol.StartSessionRequest.getPublicKey(StartSessionRequest.java:66)
Nextly pointing to the rule A.
I absolutely have no clue what I did wrong and what these messages mean. How can I solve these? Anyone who can tell me what I'm doing wrong?
Thanks a lot.
You should be able to store the public key in Base64 encoded from and still get valid JSON. You should be able to use DSAPublicKeySpec directly without calling getKeySpec() which apparently is not implemented in Bouncy Castle (Android's JCE provider). Not sure why you are getting NPE on the server, maybe wrong format. BTW, it will probably be easier if you are dealing with a single provider, so you might want to use Bouncy Castle on the server as well.
i'm looking very hard for a possibility to encrypt my sqlite database on Android devices, but I was't able to find a satisfying solution.
I need something like a libary to reference, in order to have a "on the fly" encryption/decryption of my database, while using the normal sqlite functions.
I don't want to encrypt data before storing.
I don't want to encrypt the whole databasefile, in order to decrypt it before using.
I know about the following projects:
SEE
wxSQLite
SQLCipher
SQLiteCrypt
Botan
But I can't find any working example for this stuff.
Btw, I'm absolutly willing to purchase a commercial build, but I have to test ist before spending a few hundred dollars.
Did anyone solve this issue for his own?
Try the SQLCipher port to Android instead of the regular SQLCipher.
litereplica supports encryption using the ChaCha cipher, faster than AES on portable devices.
There are bindings for Android.
To create and open an encrypted database we use an URI like this:
"file:/path/to/file.db?cipher=...&key=..."
If anyone is still looking:
Override SQLiteOpenHelper function as below:
void onConfigure(SQLiteDatabase db){
db.execSQL("PRAGMA key = 'secretkey'");
}
private String encrypt(String password) {
try {
SecretKeySpec keySpec = generateKey(password);
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE,keySpec);
byte[] encVal = c.doFinal(password.getBytes());
String encryptedValue = Base64.encodeToString(encVal,Base64.DEFAULT);
return encryptedValue;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private SecretKeySpec generateKey(String password) throws Exception {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
digest.update(bytes,0,bytes.length);
byte[] key = digest.digest();
SecretKeySpec secretKeySpec = new SecretKeySpec(key,"AES");
return secretKeySpec;
}
I just used the encrypt function to encrypt the password. Here I used the user's password as a key. Therefore I don't need to keep the key inside the application. When the user wants to log in, simply encrypt the password and try to match with the encrypted password in the database and allow them to log in.