How to verify the identity of the app sending an POST request - java

I am making an server API which will return some confidential keys to my app.
Then the app will use these key to perform a particular action. I would be sending the Keys over SSL so that any Man In the Middle attack could not read them.
To start first I will be first everything the Package name and then I also want to verify the something which assures me that my app has not been decompiled and recompiled and the package is not fake.
Basically I want to avoid these issues:
1) Someone is not creating a fake package name and then sending the request
2) Someone has not recompiled my app and then sending the request
3) Someone if not tracking the response of the server via MIM
Till now I have thought the best way would be to use a HASH key and then compare it within my server to see if the POST key is the same as stored in my server.
But I have not been able to find a key which is attached to the signing key of the app and which cannot be accessed by anyone having the APK of my app.
Any help would be grateful.

You can add extra layer of protection if you create keys in your app using C++ code available on android's NDK libraries. Here's an amazing tutorial for that. Basically, this protects your app from de-compiling tools which commonly de-compiles java files. Also, I recommend adding AES encryption on your keys before sending it through the post request of your SSL server.
On your onCreate() method, get the key from native C++ implementation:
String nativeKey = invokeNativeFunction()
then encrypt it:
byte[] keyStart = nativeKey.getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
// encrypt
byte[] encryptedData = encrypt(key,b);
Encrypt method:
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
Edit for CSRF:
There's an interesting answer from here: Authenticity_token in Rails + Android, also on Wikipedia, there are quite suggestions as to how to counter cross site request forgery. which includes:
Synchronizer token pattern
Cookie-to-header token
to name a few.
Here's a layer of extra security to identify the authenticity of the app request as well.

Related

How to wrap secret key from KeyStore by public key?

I'm interested in Android programming. I'm working with symmetric and asymmetric encryption and I wanted to wrap secret key from Android Key Store by public key but I failed. I'm able to get secret key from Key Store but I can't wrap it.
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.WRAP_MODE, publicKey);
SecretKey secret = (SecretKey) keyStore.getKey("key",null);
byte[] encrypted = cipher.wrap(secret);
Error:
InvalidKeyException:Cannot wrap key,null encoding
I tried to work with this key pair and secret key in code above - I successfully encrypted and decrypted some String by symmetric and asymmetric encryption.
What's interesting? I tried to generate new secret key by KeyGenerator and wrapping was successful. I'm little bit confused. I can't wrap it by secret key, which is loaded from KeyStore.
Could you help me please?
I believe that you got this error while using BouncyCastle since I also just received this error.
I found that BouncyCastle is calling the following code which throws the error:
byte[] encoded = key.getEncoded();
if (encoded == null) {
throw new InvalidKeyException("Cannot wrap key, null encoding.");
}
The Android KeyStore won't allow you to access the value of the private keys and will instead return null when you try to do so, which is why the above error is thrown.

Java decrypting RSA encrypted data ArrayIndexOutOfBoundsException: too much data for RSA block

I'm encrypting some data on a Phoenix webserver:
private_key = ExPublicKey.load!("private.pem")
token = %{username: user.username, mobile_phone: user.mobile_phone, email: user.email}
payload = Poison.encode!(token)
{:ok, signature} = ExPublicKey.encrypt_private(payload, private_key)
And decrypting it on the Java (actually Android) client as follows:
try {
byte[] keyBytes = Base64.decode(Constants.RSA_PUBLIC_KEY.getBytes(), Base64.DEFAULT);
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec) ;
Cipher cipher = Cipher.getInstance("RSA") ;
cipher.init(Cipher.DECRYPT_MODE, publicKey) ;
//
Log.e(DEBUG_TAG, jwt) ; // received token
String payload = new String(Base64.decode(jwt, Base64.DEFAULT), "UTF-8") ; // java does UTF16, elixir does UTF8
Log.e(DEBUG_TAG, payload) ; // base64 decoded token
byte[] cipherText = cipher.doFinal(payload.getBytes("UTF-8")) ; // decrypt
String token = new String(Base64.decode(cipherText, Base64.URL_SAFE), "UTF-8") ; // cipher text is urlencoded
Log.e(DEBUG_TAG, token) ;
return null ;
} catch (Exception e) {
e.printStackTrace();
}
There are no exceptions on the Phoenix side but trying to decrypt the token on java results in the exception:
java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(CipherSpi.java:459)
at javax.crypto.Cipher.doFinal(Cipher.java:1502
If the input is too large for the RSA modulus it should have resulted in error on the webserver. So I'm wondering what is actually wrong.
UPDATE: seems like there was an issue with library. The output produced by signing the SHA256 digest of some data returns 344 bytes, whereas its supposed to be 256 bytes for the key length used. Reverted to using Erlang's public_key module and it works fine now.
Is not clear the real purpose and that makes things difficult, but if you are trying to issue JSON Web Tokens, as it seems, your implementation is completely wrong
JWT is digitally signed, not encrypted
encrypt with private key != Digital signature
you are "decrypting" the entire token instead of verifying the signature, which should be the last part of a JSON Web Token like this hhhh.pppp.ssss.
#zaph described the error, but it would not occur if you use digital signature. It is not possible to fix your code so consider to re-implement it
Signing is not the same as encrypting using a private key. Although both would be using modular exponentiation with the private exponent signing and encryption use different padding methods. More information here. You should basically not see hashing and signing as separate operations: the hashing is part of the signature generation and verification.
The reason why your code failed is however different: the signature is likely encoded using base64. Base64 will generate an output size of ceiling(256/3)×4. This of course equals 344 characters / bytes. So you first would have to decode the result before decrypting it.
The solution to this problem is to use hybrid encryption. Namely, this involves using RSA to asymmetrically encrypt a symmetric key.
Randomly generate a symmetric encryption (say AES) key and encrypt the plaintext message with it. Then, encrypt the symmetric key with RSA. Transmit both the symmetrically encrypted text as well as the asymmetrically encrypted symmetric key.
The receiver can then decrypt the RSA block, which will yield the symmetric key, allowing the symmetrically encrypted text to be decrypted.
This can be shown more formally as the following. Let MM be the plaintext, KAESKAES be the randomly chosen AES key, and KPuKPu be the receiver's public RSA key you already have.
C1=EAES(M,KAES)
C1=EAES(M,KAES)
C2=ERSA(KAES,KPu)
C2=ERSA(KAES,KPu)
Then, send both C1C1 and C2C2.
Let KPrKPr be the receiver's private RSA key. The receiver can then recover MM as
KAES=DRSA(C2,KPr)
KAES=DRSA(C2,KPr)
M=DAES(C1,KAES)
M=DAES(C1,KAES)
(To allow streaming decryption or large messages, you would usually send C2C2 first and then (the much larger) C1C1.)

Checking tag and associated data in an AEAD cipher in Java

I need to use AEAD to share information between two users, part of which must be encrypted and part of which should be kept in cleartext.
Is there an API to check the ciphertext tag and access the associated data once a message has been encrypted with AES/GCM ?
In more detail:
I'm using Java 7 with bouncycastle as a provider and I have managed to encrypt and decrypt my data successfully, using the corresponding API:
private byte[] encrypt(SecretKey key, byte[] nonce, byte[] message, byte[] associatedData) throws ... {
Cipher aeadCipher = Cipher.getInstance(AES_GCM_NOPADDING);
aeadCipher.init(Cipher.ENCRYPT_MODE, kint, new GCMParameterSpec(GCM_MAC_SIZE, nonce);
aeadCipher.updateAAD(associatedData);
return aeadCipher.doFinal(message);
}
private byte[] decrypt(SecretKey key, byte[] nonce, byte[] cipherText, byte[] associatedData) throws ... {
Cipher aeadCipher = Cipher.getInstance(AES_GCM_NOPADDING);
aeadCipher.init(Cipher.DECRYPT_MODE, kint, new GCMParameterSpec(GCM_MAC_SIZE, nonce);
aeadCipher.updateAAD(associatedData);
return aeadCipher.doFinal(cipherText);
}
However, it is my understanding that AES/GCM ciphertexts should already contain the parameters that could affect decryption (nonce and associatedData).
Therefore, I would like to be able to retrieve them from the ciphertext, rather than having to store them alongside the ciphertext and pass them along to the decryption function. Furthermore, I'd like to be able to run integrity checks (computing the tag) and run some checks on the associated data without having to completely decrypt the message.
Is there an API that would allow this and that I might have missed ?
So far, I've checked:
The Cipher API: http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
This very informative blog post on AES/GCM implementations in Java: http://blog.philippheckel.com/2014/03/01/cipherinputstream-for-aead-modes-is-broken-in-jdk7-gcm/
Since the Java API automatically places the tag at the end, you only have to extract this tag from the your encryption result as follow:
private byte[] getTag(SecretKey key, byte[] nonce, byte[] message, byte[] associatedData) throws ... {
Cipher aeadCipher = Cipher.getInstance(AES_GCM_NOPADDING);
aeadCipher.init(Cipher.ENCRYPT_MODE, kint, new GCMParameterSpec(GCM_MAC_SIZE, nonce);
aeadCipher.updateAAD(associatedData);
byte[] encrypted = aeadCipher.doFinal(message);
// Assuming you have an AAD_SIZE = 128 bits (16 bytes)
return Arrays.copyOfRange (encrypted, encrypted.length-16, encrypted.length)
}
There is no implicit format that stores all the input data of GCM in a specific location. The Java API is already a bit strange in
the sense that it automatically places the tag at the end. This makes the
algorithm more compatible with the Cipher class, but in principle the tag just
needs to be kept with the ciphertext - where does not matter. Now you have the
issue that you don't know where the AAD ends and the ciphertext starts for instance.
So what you can do is either to create your own format (maybe your AAD has a
static size, so you can just concatenate) or you can use a predefined container format.
There is an internet draft
that specifies how to use both modes in the Cryptographic Message Syntax (CMS).
The AAD can then be stored in authenticated atributes, which should also include the required
parameters (including the IV comprising of the nonce).
If you feel masochistic you could also try and use XML-encryption with GCM mode, but beware of the many pitfalls with regard to verifying XML authenticity (e.g. beware that you are actually verifying the data you are going to use).
Bouncy Castle seems to offer support for CMS using GCM.

Android App Retrieve Data from Server but in a Secure way

Obviously I am no android or java expert. What I want to do in my Android app is, load data from a server. I already got working this part and sourcecode is attached. But I want to do it in a way which is secure. As a first step, instead of http://thisismyurl.com/a.php?action=get I want to do it with username/password like this: http://username:password#thisismyurl.com/a.php?action=get How would I do it? Should I just add the username and password part to the url?
Lets say I've accomplished that this will not be of any of use, because someone can just open the apk and decompile the sourcecode and get the url and the username/password. so is there a truly secure way of doing that?
I hope I am getting understood here.
String url = "http://thisismyurl.com/a.php?action=get";
String result = Web.executeWeb(url);
public class Web {
public static String executeWeb(final String url) {
final StringBuilder sb = new StringBuilder();
Thread thread = new Thread(new Runnable() {
public void run()
{
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
//System.out.println(result);
//Log.i("My Response :: ", result);
} catch (Exception e)
{
// TODO: handle exception
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
}
To start with, you should firstly consider what you want to achieve and how and afterwards decide what you need.
Firstly, you have to be clear that malicious users will try to crack your app, and if your app stores financial, personal or other kind of sensitive data, the persistence will increase exponencially.
That being said, a few considerations:
Hardcoding keys into your code is a bad idea. If you do that, it's just matter of time for a cracker to decipher what key have you used.
Hardcoding keys in the URL is even a worse idea. Keep in mind your URL will travel through a lot of places before reaching the end point (your server) and meanwhile anyone who was access to see that traffic will see your credentials, and even without effort as you're sending them unencrypted.
Depending on how will you generate your keys, I'd suggest using either symmetric or asymmetric encryption:
If you plan to store an unique password for all your clients (which is, by the way, also a bad idea, because if the malicious user breaks your key, they might have all your client's information), you could use a symmetric encryption method like AES. You simply encrypt your messages, send them via HTTP POST (for example) and decrypt it on the other side. Pretty easy concept.
If you plan to generate a key for each of your clients, you have the additional handicap that you somehow need to make your server know the key you have generated, or your client know which key has generated for the client (dependind on how you face it). In this context you could use the next points approach (which is basically the one I would recommend from amongst all these).
You could simply use an assymetric encryption method. That means that the server generates a pair of keys, one public and one private. Users (clients) will have the public one to encrypt messages and send them to the server. You might be wondering: And how do I protect my messages so noone can decrypt them but my server? That's where the private key joins, you can just decrypt messages if you have the private key. That's why you don't want to share it with anyone (that's where its name comes from). This way, your clients may have your public key at anytime without any obfuscation needs, then you use it to encrypt some text and send it. The server will decrypt the message using its private key and process it accordingly.
Advantages of this last approach are:
You don't have to worry on how to make your key reach the other party securely, as it will be encrypted and just the server is able to decrypt.
You don't need to generate a key for each of your clients.
If you choose a good asymmetric algorithm such as SSL/TLS, you don't need to worry about its cracking (or at least, not as much as if you had chosen some other approach).
Replacing an old pair of keys is such easy as generating a new pair, replacing the old private key and make your clients have the new public key.
You might want to have a look at these links:
Public-key cryptography
Symmetric-key algorithm
Advanced Encryption Standard (AES)
Transport Layer Security
what I did is that , I used AES encryption for this. whenever user register i send an encryption key and version in the header to the appliation so all communication will be encrypted.server always check for the version of key and then decrypt accordingly. if new key available server send new key to the application and then application update key and then decrypt with that.
i used these method to decrypt and encrypt in android.
public byte[] decrypt(byte[] cipherText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec);
cipherText = cipher.doFinal(cipherText);
return cipherText;
}
public byte[] encrypt(byte[] plainText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
plainText = cipher.doFinal(plainText);
return plainText;
}
and in request add header like
request.addHeader("KeyVersion",String.valueOf(utils.getInt(Key.Key_Version)));
request.addHeader("EmpId",String.valueOf(utils.getInt(Key.Emp_Id)));
and when response come i check for new key like
Header[] headers = response.getHeaders("KeyVersion");
if(headers.length>0){
String keyVersion = headers[0].getValue();
if (keyVersion == null) {
System.out.println("Key 'Server' is not found!");
} else {
System.out.println("Key 'Server' found! -- with version "+keyVersion);
if(utils.getInt("KeyVersion")<Integer.parseInt(keyVersion)){
utils.saveInt("KeyVersion", Integer.parseInt(keyVersion));
utils.saveString("Key", response.getHeaders("KeyValue")[0].getValue());
String s = response.getHeaders("KeyValue")[0].getValue();
System.out.println("key is "+s);
}
}
Encryption isn't the answer.
If someone wants the URL, user and password, which are stored in the client, you cannot avoid it. Even if it's encrypted, you have to provide the decryption key to the client, which then could be decompiled itself.
You cannot prevent reverse-engineering of your service interface.
And therefore cannot prevent other clients to use your service interface. It's easy to sniff the network traffic with Fiddler. Even SSL is no problem, because we can manipulate the client itself, before the data becomes encrypted.
Let's see some other SO threads about reverse-engineering.
Following on from nKn's answer:
One way of doing what you want to do is use both asymmetric and symmetric encryption, what you do is this:
Client initiates a connection to the server
Server generates a pair of public and private keys for asymmetric encryption (RSA for example).
The Server sends the public key unecrypted in plaintext to the client
The client generates a new unrelated key for the symmetric encryption (AES for example).
Client uses the public key from before to encrypt the symmetric-algorithm key and send it to the server.
Server decrypts the message using the private key, and now both sides have a common symmetric key to use.
This approach forces the client to generate a new symmetric key every time, so you need your server to keep the correct key for every connection/session. You cannot use this approach if you want a static symmetric key, for this you can use another approach:
Client generates the asymmetric key pair and send the public key to the client.
The Server uses the public key to encrypt the symmetric key and send it to the client.
The Client decrypts the message using the private key, and destroys the private key as soon as possible. - Now both sides share the same symmetric key
With the second approach you can just store the symmetric key on your server and you don't have to store a different key for every connection/session. I would still advise you to periodically change the symmetric key, just to be sure.
Both approaches do not force you to hard code keys into your client code, or send symmetric keys in plaintext.
The only thing that is sent in plaintext is the public key, and that is not a problem at all, hence the name "public key".
String httpsURL = "https://www.abcd.com/auth/login/";
String query = "email="+URLEncoder.encode("abc#xyz.com","UTF-8");
query += "&";
query += "password="+URLEncoder.encode("abcd","UTF-8") ;
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(query.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(query);
output.close();
DataInputStream input = new DataInputStream( con.getInputStream() );
for( int c = input.read(); c != -1; c = input.read() )
System.out.print( (char)c );
input.close();
System.out.println("Resp Code:"+con .getResponseCode());
System.out.println("Resp Message:"+ con .getResponseMessage());
First, never work with password itself, work only with hash representation(sha1 function) of password. Second, you can use SSL (https)to establish secure connection.
To sum it up ,after user clicks on login button ,get password from edittext and create hash of it. On server side also use hash representation. Next, send data as body of https request to www.yoursite.com/login and in request body will be your data. Send it as json f.e...

Java Server not able to encrypt/decrypt data with Blackberry's AESkey

I am developing a BlackBerry application where the server is in Java. Whenever AES encrypted data is sent to server along with PKCS5 Formatting,The server gets bad padding exception while decrypting it.
Is that the Blackberry or the server code? Have you tried using the standard JCE classes? something like this:
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(yourKeyBytes, "AES");
aes.init(Cipher.DECRYPT_MODE, key);
byte[] cleartext = aes.update(ciphertext, 0, ciphertext.length);
Make sure you're doing the padding etc in the right order first: pad then encrypt, decrypt then unpad.
Check the transmitted data length and make sure it's a multiple of blocksize.
Make sure blocksize is consistent in all the calls.
Make sure your crypto provider settings are exactly matching.

Categories

Resources