Error: RSA routines:decrypt:DATA_LEN_NOT_EQUAL_TO_MOD_LEN - android

I need to encrypt the ACCESS_TOKEN. While decrypting, getting error:
** error:0407806d:RSA routines:decrypt:DATA_LEN_NOT_EQUAL_TO_MOD_LEN**
private String ACCESS_TOKEN = "bearer
nG25Uokr3eF0WAisEcoS4hb1isLwR2qbOGu3UnwARGfeBNlP7RToSf3DCmowl99-TX0nrwL1qElIRZALFNbBXQPL6weVhJk9LRjJAoD9oBlTPtfDNMAZXlLqBqWnYZoxNyfQoPUE_Y0iMBcj_j6RqOfJc4Npid7Wo1AoipXOPYt1JLMfdHN9TZvtn6SxNP9UFipDANkcnHsurDwjPV_X0PdzyqsgXuoIjfAQLd7IonVYGZYmB_SYO68q5CorhH7hA01iIm7TDeUrOAM1p2C9W84rV6nMzMZS-7LPoweMWPxaLHcj15ex3TR16PGNGwbfiRPMLxNjmpqQEi3Mfqax2mk9qHL6LNb-OQK_5y9Zo9w1nC55iQhM-PbF96kgYa5zM2o94yI1IhcWAs-fJEe5tPsT3Dj_QfLWeNVblzDysfNwNajCGnauuPLzG-5qrGgNRtw0Dou8eNhk1lplDXxqu-G9kRyK1KKnPtuyCawzEJ_-4aEHdeA3-QSEqWCphu6w";
Please refer the code:
import android.util.Base64;
import com.itc.classmate.application.MyApplication;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
*/
public enum EncryptMoreThn256Byte {
INSTANCE;
private SecretKey secKey;
// private String ACCESS_TOKEN = "bearer nG25Uokr3eF0WAisEcoS4hb1isLwR2qbOGu3UnwARGfeBNlP7RToSf3DCmowl99-TX0nrwL1qElIRZALFNbBXQPL6weVhJk9LRjJAoD9oBlTPtfDNMAZXlLqBqWnYZoxNyfQoPUE_Y0iMBcj_j6RqOfJc4Npid7Wo1AoipXOPYt1JLMfdHN9TZvtn6SxNP9UFipDANkcnHsurDwjPV_X0PdzyqsgXuoIjfAQLd7IonVYGZYmB_SYO68q5CorhH7hA01iIm7TDeUrOAM1p2C9W84rV6nMzMZS-7LPoweMWPxaLHcj15ex3TR16PGNGwbfiRPMLxNjmpqQEi3Mfqax2mk9qHL6LNb-OQK_5y9Zo9w1nC55iQhM-PbF96kgYa5zM2o94yI1IhcWAs-fJEe5tPsT3Dj_QfLWeNVblzDysfNwNajCGnauuPLzG-5qrGgNRtw0Dou8eNhk1lplDXxqu-G9kRyK1KKnPtuyCawzEJ_-4aEHdeA3-QSEqWCphu6w";
// private String initialText = "this is working";
private EncryptMoreThn256Byte() {
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "called constructor of EncryptMoreThn256Byte");
KeyGenerator generator = null;
try {
generator = KeyGenerator.getInstance("AES");
generator.init(128); // The AES key size in number of bits
secKey = generator.generateKey();
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "EncryptMoreThn256Byte: secKey+++ " + secKey.getEncoded());
// SecureRandom random = new SecureRandom();
// byte[] salt = new byte[(256/8)];
// random.nextBytes(salt);
// KeySpec keySpec = new PBEKeySpec(initialText.toCharArray(), salt, 1000, 256);
// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
// byte[] decrptedSecrateKey = keyFactory.generateSecret(keySpec).getEncoded();
// // secKey = new SecretKeySpec(decrptedSecrateKey, "AES");
// secKey = new SecretKeySpec(decrptedSecrateKey, 0, decrptedSecrateKey.length, "AES");
} catch (Exception e) {
AppLog.errLog(EncryptMoreThn256Byte.class.getSimpleName(), e.getMessage());
}
}
public String encryptAccessTokenUsingAES(String plainText) {
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptAccessTokenUsingAES: plainText " + plainText);
if (plainText != null || !plainText.isEmpty()) {
String encrytedSecretKey = SharedPreferences.getInstance(MyApplication.getInstance().getApplicationContext()).getEncrytedSecretKey();
if (encrytedSecretKey != null) {
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptAccessTokenUsingAES: encrytedSecretKey >+++ " + encrytedSecretKey);
byte[] decrptedSecrateKey = decryptSecretKeyUsingRSA(encrytedSecretKey);
if (decrptedSecrateKey != null) {
secKey = new SecretKeySpec(decrptedSecrateKey, 0, decrptedSecrateKey.length, "AES");
}
} else {
encryptSecretKeyUsingRSA(secKey);
}
String str = new String(encryptText(secKey, plainText));
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "final encryptAccessTokenUsingAES is: " + str);
return str;
}
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptAccessTokenUsingAES: value " + null);
return null;
}
public String decryptAccessTokenUsingAES(String encrptedAssessToken) {
String encrpted_secretkey = SharedPreferences.getInstance(MyApplication.getInstance().getApplicationContext()).getEncrytedSecretKey();
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptAccessTokenUsingAES encrpted_secretkey:: " + encrpted_secretkey);
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptAccessTokenUsingAES accesstoken:: " + encrptedAssessToken);
if (encrpted_secretkey != null) {
byte[] decrptedSecrateKey = decryptSecretKeyUsingRSA(encrpted_secretkey);
if (decrptedSecrateKey != null) {
SecretKey secKey = new SecretKeySpec(decrptedSecrateKey, 0, decrptedSecrateKey.length, "AES");
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptAccessTokenUsingAES secKey.getEncoded():: " + secKey.getEncoded());
String str = decryptText(secKey, encrptedAssessToken);
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "final decryptAccessTokenUsingAES is: " + str);
return str;
}
}
return null;
}
private byte[] encryptSecretKeyUsingRSA(SecretKey secKey) {
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA SecretKey:: " + secKey);
KeyPairGenerator kpg = null;
byte[] encryptedSecrteKey = null;
try {
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PublicKey puKey = keyPair.getPublic();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.PUBLIC_KEY, puKey);
//AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA secKey.getEncoded():: " + secKey.getEncoded());
//AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA secKey.getEncoded().length:: " + secKey.getEncoded().length);
//byte[] encryptedSecrteKey = cipher.doFinal(secKey.getEncoded());
//byte[] encryptedSecrteKey=cipher.doFinal(initialText.getBytes("UTF-8"));
encryptedSecrteKey = cipher.doFinal(secKey.getEncoded());
// String str = Base64.encodeToString(encryptedSecrteKey, Base64.DEFAULT);
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA encryptedSecrteKey[]:: " + encryptedSecrteKey.length);
//AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA encrytionSecretKey:: " + str);
//AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA encrytionSecretKey length:: " + str.length());
SharedPreferences.getInstance(MyApplication.getInstance().getApplicationContext()).setEncrytedSecretKey(encryptedSecrteKey.toString());
} catch (Exception e) {
AppLog.errLog(EncryptMoreThn256Byte.class.getSimpleName(), "encryptSecretKeyUsingRSA::+" + e.getMessage());
} finally {
return encryptedSecrteKey;
}
}
private byte[] decryptSecretKeyUsingRSA(String encryptSecretKey) {
KeyPairGenerator kpg = null;
byte[] bytes = null;
try {
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey prKey = keyPair.getPrivate();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.PRIVATE_KEY, prKey);
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptSecretKeyUsingRSA encryptSecretKey.getBytes():: " + encryptSecretKey.getBytes());
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptSecretKeyUsingRSA encryptSecretKey.getBytes().length:: " + encryptSecretKey.getBytes().length);
// bytes = cipher.doFinal(Base64.decode(encryptSecretKey, Base64.DEFAULT));
bytes = cipher.doFinal(encryptSecretKey.getBytes());
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptSecretKeyUsingRSA cipher.doFinal(encryptSecretKey.getBytes():: " + bytes.toString());
} catch (Exception e) {
AppLog.errLog(EncryptMoreThn256Byte.class.getSimpleName(), "decryptSecretKeyUsingRSA++++ " + e.getMessage());
}
return bytes;
}
private byte[] encryptText(SecretKey pSecKey, String plainText) {
byte[] encryptAccessToken = null;
try {
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptText::secKey: " + pSecKey.getEncoded());
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, pSecKey);
encryptAccessToken = aesCipher.doFinal(plainText.getBytes());
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptText:::: " + encryptAccessToken.toString());
} catch (Exception e) {
AppLog.errLog(EncryptMoreThn256Byte.class.getSimpleName(), "encryptTextUsingAES " + e.getMessage());
}
return encryptAccessToken;
}
/**
* Convert bytes to AES SecertKey so we can decrypt access token
*
* #return
*/
private String decryptText(SecretKey originalKey, String decryptedAccessToken) {
byte[] bytePlainText = null;
try {
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "encryptText::originalKey: " + originalKey.getEncoded());
//SecretKey originalKey = new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");
Cipher aesCipher = null;
aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, originalKey);
bytePlainText = aesCipher.doFinal(decryptedAccessToken.getBytes());
AppLog.log(EncryptMoreThn256Byte.class.getSimpleName(), "decryptText bytePlainText:: " + bytePlainText.toString());
} catch (Exception e) {
AppLog.errLog(EncryptMoreThn256Byte.class.getSimpleName(), "encryptTextUsingAES " + e.getMessage());
}
return new String(bytePlainText);
}
private byte[] encrytAT(String plaintext, String password) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[(256 / 8)];
random.nextBytes(salt);
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 1000, 256);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
SecretKey key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
random.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
return cipher.doFinal(plaintext.getBytes("UTF-8"));
}
}
Also find the log for the same code:
03-28 11:47:59.536 12795-12795/? D/debug_log: EncryptMoreThn256Byte :encryptAccessTokenUsingAES: encrytedSecretKey >+++ [B#b56ec6b 03-2811:48:00.803 12795-12795/? D/debug_log: EncryptMoreThn256Byte :decryptSecretKeyUsingRSA encryptSecretKey.getBytes():: [B#43f8244
03-28 11:48:00.804 12795-12795/? D/debug_log: EncryptMoreThn256Byte :decryptSecretKeyUsingRSA encryptSecretKey.getBytes().length:: 10 03-2811:48:00.804 12795-12795/? E/error_log: Exception from:EncryptMoreThn256Byte : decryptSecretKeyUsingRSA++++error:0407806d:RSA routines:decrypt:DATA_LEN_NOT_EQUAL_TO_MOD_LEN
03-28 11:48:00.805 12795-12795/? D/debug_log: EncryptMoreThn256Byte :encryptText::secKey: [B#d535f2d
03-28 11:48:00.808 12795-12795/? D/debug_log: EncryptMoreThn256Byte : encryptText:::: [B#d4d6c62 03-2811:48:00.808 12795-12795/? D/debug_log: EncryptMoreThn256Byte : finalencryptAccessTokenUsingAES is: (���(z��RW�D
03-28 11:48:00.808 12795-12795/? D/debug_log: MyApplication : EncryptMoreThn256Byte +++str (���(z��RW�D
03-28 11:48:00.808 12795-12795/? D/debug_log:EncryptMoreThn256Byte : decryptAccessTokenUsingAESencrpted_secretkey:: [B#b56ec6b
03-28 11:48:00.808 12795-12795/? D/debug_log: EncryptMoreThn256Byte : decryptAccessTokenUsingAESaccesstoken:: (���(z��RW�D
03-28 11:48:03.539 12795-12795/? D/debug_log: EncryptMoreThn256Byte : decryptSecretKeyUsingRSAencryptSecretKey.getBytes():: [B#6c931f3
03-28 11:48:03.540 12795-12795/? D/debug_log: EncryptMoreThn256Byte :decryptSecretKeyUsingRSA encryptSecretKey.getBytes().length:: 10 03-2811:48:03.540 12795-12795/? E/error_log: Exception from:EncryptMoreThn256Byte : decryptSecretKeyUsingRSA++++error:0407806d:RSA routines:decrypt:DATA_LEN_NOT_EQUAL_TO_MOD_LEN
03-28 11:48:03.540 12795-12795/? D/debug_log: MyApplication :EncryptMoreThn256Byte +++ dep null

Plase, review this.
public class AESEncryptor {
private static final String CIPHER_TYPE = "RSA/ECB/PKCS1Padding";//AES/GCM/NoPadding
public final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static AESEncryptor instance;
private String alias_ = "classmate123";
private KeyStore keyStore;
private AESEncryptor() {
}
public static AESEncryptor getInstance() {
if (instance == null) {
instance = new AESEncryptor();
}
return instance;
}
public KeyStore initAndroidKeyStore(Context pContext) {
try {
if (keyStore == null) {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
keyStore.load(null);
createNewKeys(pContext);
}
} catch (Exception e) {
AppLog.errLog("AESEncrytion", "initAndroidKeyStore : " + e.getMessage());
}
return keyStore;
}
public String encrypt(String key, String cleartext) throws Exception {
//AppLog.log("AESEncrytion", "encrypt+++ " + cleartext);
if (cleartext == null || cleartext.trim().length()==0||cleartext.isEmpty()) {
return "";
}
return encryptString(alias_, cleartext);
}
public String decrypt(String key, String encryptedValue) throws Exception {
//AppLog.log("AESEncrytion", "encryptedValue+++ " + encryptedValue);
if (encryptedValue == null || encryptedValue.trim().length()==0||encryptedValue.isEmpty()) {
return "";
}
return decryptString(alias_, encryptedValue);
}
public void createNewKeys(Context pContext) {
String alias = alias_;
try {
// Create new key if needed
if (!keyStore.containsAlias(alias)) {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 1);
AlgorithmParameterSpec spec = null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
spec = new KeyPairGeneratorSpec.Builder(pContext)
// You'll use the alias later to retrieve the key. It's a key for the key!
.setAlias(alias)
// The subject used for the self-signed certificate of the generated pair
.setSubject(new X500Principal("CN=" + alias))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
}else {
// On Android M or above, use the KeyGenparameterSpec.Builder and specify permitted
// properties and restrictions of the key.
spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_SIGN)
.setCertificateSubject(new X500Principal("CN=" + alias))
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.setCertificateSerialNumber(BigInteger.ONE)
.setCertificateNotBefore(start.getTime())
.setCertificateNotAfter(end.getTime())
.build();
}
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", ANDROID_KEY_STORE);
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
// AppLog.log("AESEncrytion", "createNewKeys keyPair.getPrivate(): " + keyPair.getPrivate());
// AppLog.log("AESEncrytion", "createNewKeys keyPair.getPublic(): " + keyPair.getPublic());
} else {
AppLog.log("AESEncrytion", "KeyStore already containsAlias alias: " + keyStore.containsAlias(alias));
}
} catch (Exception e) {
AppLog.errLog("AESEncrytion", "createNewKeys: " + e.getMessage());
}
//refreshKeys();
}
public String encryptString(String alias, String initialText) {
try {
//AppLog.log("AESEncrytion", "initialText+++ " + initialText);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, null);
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey();
//AppLog.log("AESEncrytion", "encryptString keyPair.getPublic(): " + publicKey.getEncoded());
// RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
Cipher input = Cipher.getInstance(CIPHER_TYPE);
input.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted=input.doFinal(initialText.getBytes("UTF-8"));
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, input);
// cipherOutputStream.write(initialText.getBytes("UTF-8"));
// cipherOutputStream.close();
// byte[] vals = outputStream.toByteArray();
// AppLog.log("AESEncrytion", "decryptString+++ " + Base64.encodeToString(vals, Base64.DEFAULT));
return Base64.encodeToString(encrypted, Base64.DEFAULT);
} catch (Exception e) {
AppLog.errLog("AESEncrytion", "encryptString " + e.getMessage() + " occured");
}
return "";
}
public String decryptString(String alias, String cipherText) {
try {
//AppLog.log("AESEncrytion", "cipherText : " + cipherText);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, null);
// RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
//AppLog.log("AESEncrytion", "decryptString keyPair.getPrivate(): " + privateKey.getEncoded());
Cipher output = Cipher.getInstance(CIPHER_TYPE);
output.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted=output.doFinal(Base64.decode(cipherText, Base64.DEFAULT));
// CipherInputStream cipherInputStream = new CipherInputStream(
// new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), output);
// ArrayList<Byte> values = new ArrayList<>();
// int nextByte;
// while ((nextByte = cipherInputStream.read()) != -1) {
// values.add((byte) nextByte);
// }
// byte[] bytes = new byte[values.size()];
// for (int i = 0; i < bytes.length; i++) {
// bytes[i] = values.get(i).byteValue();
// }
String finalText = new String(decrypted, 0, decrypted.length, "UTF-8");
// AppLog.log("AESEncrytion", "decryptString : " + finalText);
return finalText;
} catch (Exception e) {
AppLog.errLog("AESEncrytion", "decryptString:: " + e.getMessage() + " occured");
}
return "";
}
public boolean isKeysAvail() throws KeyStoreException {
return keyStore.containsAlias(alias_);
}
public void deleteKey() throws KeyStoreException {
keyStore.deleteEntry(alias_);
}
}
It has solved my problem. I have changed my approach to encrypt and decrypt.

Related

Triple DES Algorithm in Android JAVA

I am new to Android-Java. I have below function in C# for Encryption (Triple DES)
public string Encrypt(string data)
{
try
{
if (!string.IsNullOrEmpty(data))
{
//byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(data);
//System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider CryptDesECB = new TripleDESCryptoServiceProvider();
CryptDesECB.Key = keyArray;
CryptDesECB.Mode = CipherMode.ECB;
CryptDesECB.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = CryptDesECB.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
CryptDesECB.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
return string.Empty;
}
catch (Exception)
{
return string.Empty;
}
}
I have tried below code for having same Encryption function in Android platform:
public static String EncryptText(String message) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte [] base64Bytes = Base64.encode(buf,Base64.DEFAULT);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
But, the encryption result is different on both platforms? If anyone can help me in pointing the issue in Android function.
Thanks in advance.
I wrote below class for Triple DES ECB mode PKCS5/7 padding mode encryption-decryption and it worked for me:
public class DESedeEncryption {
private static final String UNICODE_FORMAT = "UTF8";
public static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
private KeySpec myKeySpec;
private SecretKeyFactory mySecretKeyFactory;
private Cipher cipher;
byte[] keyAsBytes;
private String myEncryptionKey;
private String myEncryptionScheme;
SecretKey key;
public DESedeEncryption() throws Exception
{
myEncryptionKey = "YOURPRIVATEKEY";
myEncryptionScheme = DESEDE_ENCRYPTION_SCHEME;
keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
myKeySpec = new DESedeKeySpec(keyAsBytes);
mySecretKeyFactory = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = mySecretKeyFactory.generateSecret(myKeySpec);
}
/**
* Method To Encrypt The String
*/
public String encrypt(String unencryptedString) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
encryptedString = Base64.encodeToString(encryptedText, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString.endsWith("\n") ? encryptedString.replace("\n","") : encryptedString;
}
/**
* Method To Decrypt An Ecrypted String
*/
public String decrypt(String encryptedString) {
String decryptedText=null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedText = Base64.decode(encryptedString, Base64.DEFAULT);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText= bytes2String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
/**
* Returns String From An Array Of Bytes
*/
private static String bytes2String(byte[] bytes) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i > bytes.length; i++) {
stringBuffer.append((char) bytes[i]);
}
return stringBuffer.toString();
}
}

Cipher functions:EVP_DecryptFinal_ex:DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH

Im trying to implement AES in an Android application. The server is a PHP server.
This is the AES code :
public class AES{
private String SecretKey = "89432hjfsd891787";
private String iv = "fedcba9876543210";
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
public AES()
{
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] data)
{
if (data==null)
{
return null;
}
int len = data.length;
String str = "";
for (int i=0; i<len; i++) {
if ((data[i]&0xFF)<16)
str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
else
str = str + java.lang.Integer.toHexString(data[i]&0xFF);
}
return str;
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private static String padString(String source)
{
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++) {
source += paddingChar;
}
return source;
}
}
I get an error while decrypting the incoming string : Cipher functions:EVP_DecryptFinal_ex:DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
How do i go about this?
Manually padding the String representation of the plaintext with spaces is not a good padding mechanism. Instead, you should use AES/CBC/PKCS5Padding which will handle the padding as prescribed in PKCS #5/#7.
You should also:
generate a unique IV per encryption operation rather than re-using the same value for all messages
Use an authenticated mode of operation (GCM, HMAC/SHA-256 MAC over cipher text, etc.)
Store the key in hexadecimal representation of the raw bytes rather than an ASCII/UTF-8 String encoding (not specified in your code)
Encode the cipher text in Base64 or Hex before serializing/transmitting. Encoding errors can contribute to padding exceptions during decryption.

Android KeyStore to store the SecretKey for encryption/decryption

I am trying to have secret (String) in the app, anywhere, save to be! So I came up with this idea to use the keyStore to store the key and only use it for encryption and decryption of my secret. Here is how I save (encrypt) my secret:
public static boolean setKeyStoreString(String strToStore, Context context) {
if (strToStore == null) return false;
if (strToStore.length() == 0) return false;
Log.e(TAG, strToStore);
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
int nBefore = keyStore.size();
// Create the keys if necessary
if (!keyStore.containsAlias("phrase")) {
KeyGenerator generator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder("phrase", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setKeySize(256)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationValidityDurationSeconds(-1)
.setRandomizedEncryptionRequired(false)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(false)
.build();
generator.init(spec);
generator.generateKey();
}
int nAfter = keyStore.size();
Log.v(TAG, "Before = " + nBefore + " After = " + nAfter);
String filesDirectory = context.getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + "my_phrase";
// Log.v(TAG, "strPhrase = " + strToStore);
// Log.v(TAG, "dataDirectory = " + dataDirectory);
// Log.v(TAG, "filesDirectory = " + filesDirectory);
// Log.v(TAG, "encryptedDataFilePath = " + encryptedDataFilePath);
SecretKey secret = (SecretKey) keyStore.getKey("phrase", null);
Cipher inCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
inCipher.init(Cipher.ENCRYPT_MODE, secret);
CipherOutputStream cipherOutputStream = new CipherOutputStream(
new FileOutputStream(encryptedDataFilePath), inCipher);
byte[] bytesToStore = strToStore.getBytes("UTF-8");
cipherOutputStream.write(bytesToStore);
try {
cipherOutputStream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
return false;
}
and here is how I try to retrieve it:
public static String getKeyStoreString(final Context context) {
KeyStore keyStore;
String recoveredSecret = "";
String filesDirectory = context.getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + "my_phrase";
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
SecretKey secretKey = (SecretKey)
keyStore.getKey("phrase", null);
if (secretKey == null) throw new RuntimeException("secretKey is null");
Cipher outCipher;
outCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
outCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(
new byte[outCipher.getBlockSize()]));
CipherInputStream cipherInputStream = new CipherInputStream(
new FileInputStream(encryptedDataFilePath), outCipher);
byte[] roundTrippedBytes = new byte[1000]; //TODO: dynamically resize as we get more data
int index = 0;
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
roundTrippedBytes[index] = (byte) nextByte;
index++;
}
recoveredSecret = new String(roundTrippedBytes, 0, index, "UTF-8");
Log.e(TAG, "round tripped string = " + recoveredSecret);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, "recovered: " + recoveredSecret);
return recoveredSecret;
}
the problem is - the result comes a little damaged in the beginning,
i.e: some cool text for extraction >>>>> �k��X�&�ALqM,A� text for
extraction
i have the same problem i used Base64.encode(your byte[], Base64.DEFAULT);to encode and Base64.decode(your byte[], Base64.DEFAULT) to decode
try to put byte[] encode = Base64.encode(bytesToStore, Base64.DEFAULT)
after byte[] bytesToStore = strToStore.getBytes("UTF-8");
in the public static boolean setKeyStoreString() and check in the "encode" log

How Can I Use the Android KeyStore to securely store arbitrary strings?

I would like to be able securely store some sensitive strings in the Android KeyStore. I get the strings from the server but I have a use case which requires me to persist them. KeyStore will only allow access from the same UID as that assigned to my app, and it will encrypt the data with the device master password, so it's my understanding that I don't have to do any additional encryption to protect my data. My trouble is, I'm missing something about how to write the data. The code I have below works perfectly, as long as the call to KeyStore.store(null) is omitted. That code fails, and as long as I can't store the data after putting it to the KeyStore, then I can't persist it.
I think I'm missing something about the KeyStore API, but I don't know what. Any help appreciated!
String metaKey = "ourSecretKey";
String encodedKey = "this is supposed to be a secret";
byte[] encodedKeyBytes = new byte[(int)encodedKey.length()];
encodedKeyBytes = encodedKey.getBytes("UTF-8");
KeyStoreParameter ksp = null;
//String algorithm = "DES";
String algorithm = "DESede";
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm);
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKeyBytes, algorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(secretKeySpec);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore.setEntry(metaKey, secretKeyEntry, ksp);
keyStore.store(null);
String recoveredSecret = "";
if (keyStore.containsAlias(metaKey)) {
KeyStore.SecretKeyEntry recoveredEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry(metaKey, ksp);
byte[] bytes = recoveredEntry.getSecretKey().getEncoded();
for (byte b : bytes) {
recoveredSecret += (char)b;
}
}
Log.v(TAG, "recovered " + recoveredSecret);
I started with the premise that I could use AndroidKeyStore to secure arbitrary blobs of data, and call them "keys". However, the deeper I delved into this, the clearer it became that the KeyStore API is deeply entangled with Security-related objects: Certificates, KeySpecs, Providers, etc. It's not designed to store arbitrary data, and I don't see a straightforward path to bending it to that purpose.
However, the AndroidKeyStore can be used to help me to secure my sensitive data. I can use it to manage the cryptographic keys which I will use to encrypt data local to the app. By using a combination of AndroidKeyStore, CipherOutputStream, and CipherInputStream, we can:
Generate, securely store, and retrieve encryption keys on the device
Encrypt arbitrary data and save it on the device (in the app's directory, where it will be further protected by the file system permissions)
Access and decrypt the data for subsequent use.
Here is some example code which demonstrates how this is achieved.
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
String alias = "key3";
int nBefore = keyStore.size();
// Create the keys if necessary
if (!keyStore.containsAlias(alias)) {
Calendar notBefore = Calendar.getInstance();
Calendar notAfter = Calendar.getInstance();
notAfter.add(Calendar.YEAR, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(alias)
.setKeyType("RSA")
.setKeySize(2048)
.setSubject(new X500Principal("CN=test"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(notBefore.getTime())
.setEndDate(notAfter.getTime())
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
}
int nAfter = keyStore.size();
Log.v(TAG, "Before = " + nBefore + " After = " + nAfter);
// Retrieve the keys
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
Log.v(TAG, "private key = " + privateKey.toString());
Log.v(TAG, "public key = " + publicKey.toString());
// Encrypt the text
String plainText = "This text is supposed to be a secret!";
String dataDirectory = getApplicationInfo().dataDir;
String filesDirectory = getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + "keep_yer_secrets_here";
Log.v(TAG, "plainText = " + plainText);
Log.v(TAG, "dataDirectory = " + dataDirectory);
Log.v(TAG, "filesDirectory = " + filesDirectory);
Log.v(TAG, "encryptedDataFilePath = " + encryptedDataFilePath);
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
inCipher.init(Cipher.ENCRYPT_MODE, publicKey);
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
outCipher.init(Cipher.DECRYPT_MODE, privateKey);
CipherOutputStream cipherOutputStream =
new CipherOutputStream(
new FileOutputStream(encryptedDataFilePath), inCipher);
cipherOutputStream.write(plainText.getBytes("UTF-8"));
cipherOutputStream.close();
CipherInputStream cipherInputStream =
new CipherInputStream(new FileInputStream(encryptedDataFilePath),
outCipher);
byte [] roundTrippedBytes = new byte[1000]; // TODO: dynamically resize as we get more data
int index = 0;
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
roundTrippedBytes[index] = (byte)nextByte;
index++;
}
String roundTrippedString = new String(roundTrippedBytes, 0, index, "UTF-8");
Log.v(TAG, "round tripped string = " + roundTrippedString);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (NoSuchProviderException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (KeyStoreException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (CertificateException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (UnrecoverableEntryException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (NoSuchPaddingException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (InvalidKeyException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (BadPaddingException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (IllegalBlockSizeException e) {
Log.e(TAG, Log.getStackTraceString(e));
} catch (UnsupportedOperationException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
You may have noticed that there are problems handling different API levels with the Android Keystore.
Scytale is an open source library that provides a convenient wrapper around the Android Keystore so that you don't have write boiler plate and can dive straight into enryption/decryption.
Sample code:
// Create and save key
Store store = new Store(getApplicationContext());
if (!store.hasKey("test")) {
SecretKey key = store.generateSymmetricKey("test", null);
}
...
// Get key
SecretKey key = store.getSymmetricKey("test", null);
// Encrypt/Decrypt data
Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
String text = "Sample text";
String encryptedData = crypto.encrypt(text, key);
Log.i("Scytale", "Encrypted data: " + encryptedData);
String decryptedData = crypto.decrypt(encryptedData, key);
Log.i("Scytale", "Decrypted data: " + decryptedData);
I have reworked the accepted answer by Patrick Brennan. on Android 9, it was yielding a NoSuchAlgorithmException. The deprecated KeyPairGeneratorSpec has been replaced with KeyPairGenerator. There was also some work required to address an exception regarding the padding.
The code is annotated with the changes made: "***"
#RequiresApi(api = Build.VERSION_CODES.M)
public static void storeExistingKey(Context context) {
final String TAG = "KEY-UTIL";
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
String alias = "key11";
int nBefore = keyStore.size();
// Create the keys if necessary
if (!keyStore.containsAlias(alias)) {
Calendar notBefore = Calendar.getInstance();
Calendar notAfter = Calendar.getInstance();
notAfter.add(Calendar.YEAR, 1);
// *** Replaced deprecated KeyPairGeneratorSpec with KeyPairGenerator
KeyPairGenerator spec = KeyPairGenerator.getInstance(
// *** Specified algorithm here
// *** Specified: Purpose of key here
KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
spec.initialize(new KeyGenParameterSpec.Builder(
alias, KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) // RSA/ECB/PKCS1Padding
.setKeySize(2048)
// *** Replaced: setStartDate
.setKeyValidityStart(notBefore.getTime())
// *** Replaced: setEndDate
.setKeyValidityEnd(notAfter.getTime())
// *** Replaced: setSubject
.setCertificateSubject(new X500Principal("CN=test"))
// *** Replaced: setSerialNumber
.setCertificateSerialNumber(BigInteger.ONE)
.build());
KeyPair keyPair = spec.generateKeyPair();
Log.i(TAG, keyPair.toString());
}
int nAfter = keyStore.size();
Log.v(TAG, "Before = " + nBefore + " After = " + nAfter);
// Retrieve the keys
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, null);
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey();
Log.v(TAG, "private key = " + privateKey.toString());
Log.v(TAG, "public key = " + publicKey.toString());
// Encrypt the text
String plainText = "This text is supposed to be a secret!";
String dataDirectory = context.getApplicationInfo().dataDir;
String filesDirectory = context.getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + "keep_yer_secrets_here";
Log.v(TAG, "plainText = " + plainText);
Log.v(TAG, "dataDirectory = " + dataDirectory);
Log.v(TAG, "filesDirectory = " + filesDirectory);
Log.v(TAG, "encryptedDataFilePath = " + encryptedDataFilePath);
// *** Changed the padding type here and changed to AndroidKeyStoreBCWorkaround
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
inCipher.init(Cipher.ENCRYPT_MODE, publicKey);
// *** Changed the padding type here and changed to AndroidKeyStoreBCWorkaround
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
outCipher.init(Cipher.DECRYPT_MODE, privateKey);
CipherOutputStream cipherOutputStream =
new CipherOutputStream(
new FileOutputStream(encryptedDataFilePath), inCipher);
// *** Replaced string literal with StandardCharsets.UTF_8
cipherOutputStream.write(plainText.getBytes(StandardCharsets.UTF_8));
cipherOutputStream.close();
CipherInputStream cipherInputStream =
new CipherInputStream(new FileInputStream(encryptedDataFilePath),
outCipher);
byte[] roundTrippedBytes = new byte[1000]; // TODO: dynamically resize as we get more data
int index = 0;
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
roundTrippedBytes[index] = (byte) nextByte;
index++;
}
// *** Replaced string literal with StandardCharsets.UTF_8
String roundTrippedString = new String(roundTrippedBytes, 0, index, StandardCharsets.UTF_8);
Log.v(TAG, "round tripped string = " + roundTrippedString);
} catch (NoSuchAlgorithmException | UnsupportedOperationException | InvalidKeyException | NoSuchPaddingException | UnrecoverableEntryException | NoSuchProviderException | KeyStoreException | CertificateException | IOException e | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
Note: “AndroidKeyStoreBCWorkaround” allows the code to work across different APIs.
I would be grateful if anyone can comment on any shortcomings in this updated solution. Else if anyone with more Crypto knowledge feels confident to update Patrick's answer then I will remove this one.

Can't log in Facebook Chat via XMPP on Android

I've wrote a Android in App in which I want to Integrate a Chat via XMPP.
I've logged in Facebook with permission for XMPPLogin. But when I want to login in Facebook from XMPP I receive this XML Response:
RCV (1095775528): <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure></stream:stream>
causing this Error:
SASL authentication failed using mechanism X-FACEBOOK-PLATFORM:
at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:341)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:242)
at org.jivesoftware.smack.Connection.login(Connection.java:371)
at com.example.messenger.ChatActivity.testLogin(ChatActivity.java:240)
at com.example.messenger.ChatActivity.access$0(ChatActivity.java:189)
at com.example.messenger.ChatActivity$1$1.run(ChatActivity.java:70)
at java.lang.Thread.run(Thread.java:856)
This is how I use the Login
private void testLogin(){
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222, "chat.facebook.com");
Log.i("XMPP Client", "ConnectionConfig");
config.setSASLAuthenticationEnabled(true);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
config.setDebuggerEnabled(true);
Log.i("XMPP Client", "config Complete");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
config.setTruststoreType("AndroidCAStore");
config.setTruststorePassword(null);
config.setTruststorePath(null);
} else {
config.setTruststoreType("BKS");
String path = System.getProperty("javax.net.ssl.trustStore");
if (path == null)
path = System.getProperty("java.home") + File.separator + "etc"
+ File.separator + "security" + File.separator
+ "cacerts.bks";
config.setTruststorePath(path);
}
Log.i("XMPP Client", "config if else complete");
xmpp = new XMPPConnection(config);
SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM",SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
Log.i("XMPP Client", "new Connection and sasl auth done");
try {
xmpp.connect();
Log.i("XMPPClient","Connected to " + xmpp.getHost());
} catch (XMPPException e1) {
Log.i("XMPPClient","Unable to " + xmpp.getHost());
e1.printStackTrace();
}
Log.i("XMPP Client", "xmpp connect done");
try {
String apiKey = Session.getActiveSession().getApplicationId();
String sessionKey = Session.getActiveSession().getAccessToken();
String sessionSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
Log.i("XMPP Client", Session.getActiveSession().getApplicationId());
xmpp.login(apiKey + "|" + sessionKey, sessionSecret , "Messenger");
Log.i("XMPPClient"," its logined ");
Log.i("Connected",""+xmpp.isConnected());
if ( xmpp.isConnected()){
Presence presence = new Presence(Presence.Type.available);
xmpp.sendPacket(presence);
}
} catch (XMPPException e) {
e.printStackTrace();
}
}
and this is my SASLXFacebookPlatformMechanism Class
package com.example.messenger;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
import org.apache.harmony.javax.security.sasl.Sasl;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;
public class SASLXFacebookPlatformMechanism extends SASLMechanism
{
private static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String applicationSecret = "";
private String sessionKey = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication)
{
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException
{
getSASLAuthentication().send(new AuthMechanism(NAME, ""));
}
#Override
public void authenticate(String apiKeyAndSessionKey, String host,
String applicationSecret) throws IOException, XMPPException
{
if (apiKeyAndSessionKey == null || applicationSecret == null)
{
throw new IllegalArgumentException("Invalid parameters");
}
String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
if (keyArray.length < 2)
{
throw new IllegalArgumentException(
"API key or session key is not present");
}
this.apiKey = keyArray[0];
this.applicationSecret = applicationSecret;
this.sessionKey = keyArray[1];
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
this);
authenticate();
}
#Override
public void authenticate(String username, String host, CallbackHandler cbh)
throws IOException, XMPPException
{
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
cbh);
authenticate();
}
#Override
protected String getName()
{
return NAME;
}
#Override
public void challengeReceived(String challenge) throws IOException
{
byte[] response = null;
if (challenge != null)
{
String decodedChallenge = new String(Base64.decode(challenge));
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis();
String sig =
"api_key=" + apiKey + "call_id=" + callId + "method="
+ method + "nonce=" + nonce + "session_key="
+ sessionKey + "v=" + version + applicationSecret;
try
{
sig = md5(sig);
} catch (NoSuchAlgorithmException e)
{
throw new IllegalStateException(e);
}
String composedResponse =
"api_key=" + URLEncoder.encode(apiKey, "utf-8")
+ "&call_id=" + callId + "&method="
+ URLEncoder.encode(method, "utf-8") + "&nonce="
+ URLEncoder.encode(nonce, "utf-8")
+ "&session_key="
+ URLEncoder.encode(sessionKey, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8") + "&sig="
+ URLEncoder.encode(sig, "utf-8");
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null)
{
authenticationText =
Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
private Map<String, String> getQueryMap(String query)
{
Map<String, String> map = new HashMap<String, String>();
String[] params = query.split("\\&");
for (String param : params)
{
String[] fields = param.split("=", 2);
map.put(fields[0], (fields.length > 1 ? fields[1] : null));
}
return map;
}
private String md5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(text.getBytes("utf-8"), 0, text.length());
return convertToHex(md.digest());
}
private String convertToHex(byte[] data)
{
StringBuilder buf = new StringBuilder();
int len = data.length;
for (int i = 0; i < len; i++)
{
int halfByte = (data[i] >>> 4) & 0xF;
int twoHalfs = 0;
do
{
if (0 <= halfByte && halfByte <= 9)
{
buf.append((char) ('0' + halfByte));
}
else
{
buf.append((char) ('a' + halfByte - 10));
}
halfByte = data[i] & 0xF;
} while (twoHalfs++ < 1);
}
return buf.toString();
}
}
Thank you for you Help :)

Categories

Resources