I'm looking to encrypt my access token that is generated when the user inputs a username and password. The question I'm asking here is what are the different ways of doing this and what would the community think is the best method to do so. I've looked at Cryptography and Keystore but not sure if these are the right way to go? I'm a noob to encryption so any documentation would also be very helpful.
Thank you very much :D
Please try with android SecretKeySpec class
for encryption
public void setPassCode(String value) throws Exception {
try {
SecretKeySpec sks = null;
sks = getEncryptKey();
byte[] userLatENC=null;
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE,sks );
userLatENC = c.doFinal(value.getBytes());
passCode = Base64.encodeToString(userLatENC, Base64.DEFAULT);
} catch (Exception e) {
throw e;
}
}
for decryption
public String getPassCode() throws Exception {
SecretKeySpec sks = null;
try {
String encVal = "pass_code";
if (encVal.isEmpty()) {
return encVal;
}
sks = getDecryptKey();
byte[] latDEC=null;
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, sks);
latDEC = c.doFinal(Base64.decode(encVal, Base64.DEFAULT));
return new String(latDEC);
} catch (Exception e) {
throw e;
}
}
Get Encrypted Key
private SecretKeySpec getEncryptKey() throws Exception{
SecretKeySpec sks = null;
SecretKey key =null;
byte[] keyToSave;
try {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed("any data used as random seed".getBytes());
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, sr);
key= kg.generateKey();
keyToSave =key.getEncoded();
sks = new SecretKeySpec(keyToSave, "AES");
ks.load(null,null);
ks.setKeyEntry("aliasKey",key,null, null);
FileOutputStream ksout = context.openFileOutput("keystore_android", Context.MODE_PRIVATE);
ks.store(ksout, null);
ksout.close();
return sks;
} catch (Exception e) {
throw e;
}
}
For Decrypted Key
private SecretKeySpec getDecryptKey() throws Exception{
SecretKeySpec sks = null;
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream fis = null;
fis = context.openFileInput("keystore_android");
keyStore.load(fis,null);
sks=new SecretKeySpec((keyStore.getKey("aliasKey", null)).getEncoded(), "AES");
return sks;
} catch (Exception e) {
throw e;
}
}
Related
I think I am missing something, i believe the image(converted to bytes) is being encrypted but not decrypted when it arrives at the client side. The image seems to pass the RSA signature verification but somehow it can not be viewed.
Client Side Code:
public void aliceEncrypt(byte[] plaintext, byte[] sharedSecret) {
Cipher cipher;
byte[] encrypted = null;
try {
cipher = Cipher.getInstance("RC4");
Key sk = new SecretKeySpec(sharedSecret, "RC4");
cipher.init(Cipher.ENCRYPT_MODE, sk);
encrypted = cipher.doFinal(plaintext);
CipherOutputStream cos = new CipherOutputStream(socket.getOutputStream(), cipher);
ObjectOutputStream oos = new ObjectOutputStream(cos);
oos.writeObject(encrypted);
oos.flush();
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException | InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
Server Side Code:
public byte[] bobDecrypt( byte[] sharedSecret) {
Cipher cipher = null;
byte[] bytes = null;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("RC4");
Key sk = new SecretKeySpec(sharedSecret, "RC4");
cipher.init(Cipher.DECRYPT_MODE, sk);
CipherInputStream cis = new CipherInputStream(socket.getInputStream(), cipher);
ObjectInputStream ois = new ObjectInputStream(cis);
bytes = (byte[])ois.readObject();
decrypted = cipher.doFinal(bytes);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException | InvalidKeyException | ClassNotFoundException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return decrypted;
}
CipherInputStream and CipherOutputStream are meant to do all the heavy lifting, so you just supply them with an initialized Cipher instance and then use the write and read stream methods. For the most part you can layer these as with out input and output streams, but there is one subtlety: when a block cipher is used, there is no good way to signal the CipherOutputStream that it needs to call Cipher.doFinal(). The only supported way is to call the close() method. These close() calls propagate
to other wrapped streams, and in this case where a socket Outputstream is wrapped it ends up closing the socket as a side effect. This may be perfectly acceptable behavior, but you need to be aware of it. In this case, because you are using a byte-oriented stream cipher (RC4), there is no padding, so Cipher.doFinal()is basically a no-op anyway (well, it does reset the cipher state), so calling flush() is as good as calling close(). The code below is basically your code modified to correctly show how to layer and use the various streams.
public void aliceEncrypt(byte[] plaintext, byte[] sharedSecret, Socket socket) {
try {
Cipher cipher = Cipher.getInstance("RC4/ECB/NoPadding");
Key sk = new SecretKeySpec(sharedSecret, "RC4");
cipher.init(Cipher.ENCRYPT_MODE, sk);
CipherOutputStream cos = new CipherOutputStream(socket.getOutputStream(), cipher);
ObjectOutputStream oos = new ObjectOutputStream(cos);
oos.writeObject(plaintext);
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] bobDecrypt( byte[] sharedSecret, Socket socket) {
try {
Cipher cipher = Cipher.getInstance("RC4/ECB/NoPadding");
Key sk = new SecretKeySpec(sharedSecret, "RC4");
cipher.init(Cipher.DECRYPT_MODE, sk);
CipherInputStream cis = new CipherInputStream(socket.getInputStream(), cipher);
ObjectInputStream ois = new ObjectInputStream(cis);
byte[] bytes = (byte[]) ois.readObject();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I'm developing a native android app and hybrid IOS app. I'm encrypting the password before sending the request to BL. Below is my native code.
public String Encrypt (String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
try {
AssetManager assets = context.getAssets();
byte[] key = readFully(
assets.open("encryption.der", AssetManager.ACCESS_BUFFER));
KeySpec publicKeySpec = new X509EncodedKeySpec(key);
KeyFactory kf = KeyFactory.getInstance("RSA");
Key pk = kf.generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pk);
ByteArrayOutputStream out = new ByteArrayOutputStream();
CipherOutputStream cout = new CipherOutputStream(out, cipher);
try {
cout.write(plain.getBytes(UTF_8));
cout.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
cout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
encrypted = new String(encode(out.toByteArray(), DEFAULT), "UTF-8");
return encrypted;
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
static byte[] readFully(InputStream inputStream) throws IOException {
InputStream in = new BufferedInputStream(inputStream);
byte[] tmp = new byte[1024];
int readLen, size = 0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((readLen = in.read(tmp)) != -1) {
if (((long) size + readLen) > Integer.MAX_VALUE) {
// woah! did we just ship an app of 2GB?
throw new IllegalStateException("Invalid file. File size exceeds expected "
+ "maximum of 2GB");
}
size += readLen;
out.write(tmp, 0, readLen);
}
return out.toByteArray();
}
I have my key in encryption.der file. Everything works fine in android. Now coming to IOS which I'm using Ionic to develop. I'm not able to achieve the encryption part. I have used the "cryptico" : link : https://github.com/wwwtyro/cryptico/blob/master/README.md .
And finally converting to Base64 like these.
var EncryptionPassword = cryptico.encrypt($scope.userInfo.Password, publicKey);
$scope.encPass = base64.encode(EncryptionPassword.cipher);
But I'm getting ArrayIndexOutOfBound Exception from BL. Can you suggest exact same solution has android for angularjs too. So RSA encrytion works on both IOS and Android.
Create a Service and place your public Key inside that.
.service('Settings', function(){
this.publicKey = 'MIIBIjANBgdcssvsvsfvsfvsfvrefvfvfviuwoihijwfoiw278499080989i09M+KC8MYYOu/NRLmFg85LRrfRszyI/vZ/k8982789uiwbgchdbhU+3joQZoJ3Sxq/GbIIFf/3y4f9DuKI53y1qR2qD4xIskfa9rPVqvBtAu2KSNRd8V4J8RKI2gT2YEA+A3Z0mQq4GBRS8iYmGLqRQyPfNUSankylBrTpOIVFBZORdZehjJMmwl98UynyfnyMIHUIFuhefuibiufbeufbsoijn93fD7nxt+siZryfazn3EAgBaTKTV/U5xIepzDN6ZYJ4qnC93u6erdb1X4m1zU6RGapwzCOPOORTyzw/uWJ8twcODNt0cqVp+sYQIDAQAB';
})
Now in your JS encrypt using public key and JSEncrypt.
var encrypt = new JSEncrypt(); encrypt.setPublicKey(Settings.publicKey);
EncryptionPin = encrypt.encrypt($scope.customerInfo.Pin);
EncryptionPin is the final key.
Encryption is working fine. When I try to decrypt I receive error "pad block corrupted"(on c3des.doFinal). What am I doing wrong? I use web services (C#) and encryption and decryption is working fine.
public String encryptText(String plainText) throws Exception {
byte[] plaintext = plainText.getBytes("UTF-8");//input
byte[] tdesKeyData = "sdfsdgf3q453qdsg".getBytes("UTF-8");
Cipher c3des = Cipher.getInstance("DESede/ECB/PKCS7Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
c3des.init(Cipher.ENCRYPT_MODE, myKey);
byte[] cipherText = c3des.doFinal(plaintext);
String encryptedString = Base64.encodeToString(cipherText,
Base64.DEFAULT);
return encryptedString;
}
public String decrypt(String tekst) throws Exception {
byte[] tekst2 = tekst.getBytes("UTF-8");
byte[] tdesKeyData = "sdfsdgf3q453qdsg".getBytes("UTF-8");
Cipher c3des = Cipher.getInstance("DESede/ECB/PKCS7Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
String decryptedString="";
try {
c3des.init(Cipher.DECRYPT_MODE, myKey);
byte[] cipherText = c3des.doFinal(tekst2);
decryptedString = Base64.decode(cipherText, Base64.DEFAULT).toString();
}
catch(Exception e)
{
decryptedString=e.getMessage();
}
return decryptedString;
}
So I'm using the code below for encrypting/decrypting string values that can be stored in the device preferences but I know need to add a method for encrypting/decrypting an ArrayList that can also be stored in the preferences as well (so I'm guessing the encryption needs to convert the arraylist to a string and then the decryption needs to convert that string back to the arraylist). Since I'm pretty new to Android/Java I'm having a hard time figuring out how to do this so any help would be appreciated.
public String encrypt(String key, String data) {
if (key == null || data == null)
return null;
try {
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(charsetName));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
byte[] dataBytes = data.getBytes(charsetName);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.encodeToString(cipher.doFinal(dataBytes), base64Mode);
} catch (Exception e) {
return null;
}
}
public String decrypt(String key, String data) {
if (key == null || data == null)
return null;
try {
byte[] dataBytes = Base64.decode(data, base64Mode);
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(charsetName));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] dataBytesDecrypted = (cipher.doFinal(dataBytes));
return new String(dataBytesDecrypted);
} catch (Exception e) {
return null;
}
}
Serialize the ArrayList<LinkedHashMap> to Json before sending the input to encrypt()
public static String ArrayListToString(ArrayList<LinkedHashMap> list) {
Gson serializer = new Gson();
return serializer.toJson(list);
}
then do deserializing after decrypting.
You need to reference Google-Gson in your project.
I want to encrypt JSON string and then send it to web server. For encryption I am using AES algorithm.
my JSON string is like :
String pJSON = "{\"UserName\":\"abc\",\"Password\":\"123456789\"}";
any idea ??
If you want to protect the password and other personal details whilst they are in transit, it is MUCH better to use HTTPS (secure HTTP) than to do your own encryption because:
If you do your own encryption/decryption then your app contains everything a hacker needs to decrypt the password, they just need to reverse-engineer it (you can make this harder, but not impossible, using a tool like Proguard)
HTTPS is designed for this type of scenario, and is much easier to implement. You just buy a secure web server cert (usually less than $100) and install it on the web server.
So I am suggesting that rather than doing your own encryption which is time-consuming and prone to attack, use the existing web infrastructure to do it for you.
Actually this is a JSON object.
You can do something like this:
JSONObject JObject=new JSONObject();
JObject.put("UserName", "abc");
JObject.put("Password", "123456789");
This will create a similar string then you can send it to server using PUT or POST method.
Please check this out. I have gone of this encryption just few day before.
public class AES_ECB {
//final static String AES_V1_KEY = "D0QgiY8JYvx8qzKx0iaN8kwEJgwpEqAJ";
final static String AES_V1_KEY = "BH&625%$#kOhrtxx";
private static final String KEY_ALGORITHM = "AES";
private static final String CIPHER_ALGORITHM = "AES/ECB/NoPadding";
// private static final String CIPHER_ALGORITHM = "AES/CFB/NoPadding";
// private static SecretKeySpec secretKeySpec = new
// SecretKeySpec(AES_V1_KEY.getBytes(), "AES");
// private static byte[] iv = "Htw%$42u&8o*pqxzV#C!33Zq29&bSq2#".getBytes();
// private static byte[] iv = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5,
// 0x6,
// 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
// private static IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
private static final String PROVIDER = "BC";
static String nullPadString(String original) {
String output = original;
int remain = output.length() % 16;
if (remain != 0) {
remain = 16 - remain;
for (int i = 0; i < remain; i++)
output += (char) 0;
}
return output;
}
static String encryptString(final String RAWDATA, boolean ENCODE) {
String encrypted = null;
byte[] encryptedBytes = null;
byte[] key;
key = AES_V1_KEY.getBytes();
// SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
// Instantiate the cipher
Cipher cipher = null;
try {
String input = RAWDATA;
// KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
// SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
// sr.setSeed(key);
// kgen.init(128, sr); //192 and 256 bits may not be available
// SecretKey skey = kgen.generateKey();
// byte[] raw1 = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// cipher.init(Cipher.ENCRYPT_MODE,
// AES_ECB.secretKeySpec,AES_ECB.ivParameterSpec);
// encryptedBytes = cipher.doFinal(nullPadString(input).getBytes());
encryptedBytes = cipher.doFinal(nullPadString(input).getBytes());
} catch (NoSuchAlgorithmException e) {
Log.d("ERROR", e.toString());
} catch (NoSuchPaddingException e) {
Log.d("ERROR", e.toString());
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
Log.d("ERROR", e.toString());
} catch (IllegalBlockSizeException e) {
Log.d("ERROR", e.toString());
} catch (BadPaddingException e) {
Log.d("ERROR", e.toString());
}
encrypted = new String(encryptedBytes);
if (ENCODE)
encrypted = new String(Base64.encodeBytes(encryptedBytes));
else
encrypted = new String(encryptedBytes);
return encrypted;
// /return encrypted;
}// method end
static String decryptString(final String ENCRYPTEDDATA, final boolean DECODE) {
String raw = null;
byte[] rawBytes = null;
byte[] encryptedBytes = null;
if (DECODE)
try {
encryptedBytes = Base64.decode(ENCRYPTEDDATA.getBytes());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
else
encryptedBytes = ENCRYPTEDDATA.getBytes();
// encryptedBytes = ENCRYPTEDDATA.getBytes();
byte[] key;
key = AES_V1_KEY.getBytes();
// SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = null;
try {
// KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
// SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
// sr.setSeed(key);
// kgen.init(128, sr); // 192 and 256 bits may not be available
// SecretKey skey = kgen.generateKey();
// byte[] raw1 = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
rawBytes = cipher.doFinal(encryptedBytes);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(rawBytes==null)
return "";
else{
return raw = new String(rawBytes);
}
// raw = new String(rawBytes);
// int delimiter = raw.indexOf('|');
// int length = Integer.valueOf(raw.substring(0, delimiter));
// raw = raw.substring(delimiter + 1, length + delimiter + 1);
// return raw;
}
}