-
Notifications
You must be signed in to change notification settings - Fork 431
Encrypt message on one device and decrypt on another #49
Comments
Entity does not actually wrap the key. Entity is meant to be a publicly visible filename to prevent against substitution attacks. The key comes from the KeyChain you supply while initializing the Crypto object. The default SharedPreferencesKeyChain generates a key per device. You can make the KeyChain return the same key on both devices by creating a custom KeyChain. The key needs to be NativeGCMCipher.KEY_LENGTH length. You can look at the SharedPreferencesKeyChain as a sample https://github.com/facebook/conceal/blob/master/java/com/facebook/crypto/keychain/SharedPrefsBackedKeyChain.java |
I hope that answers your question. I'm closing out the task. Feel free to reopen if you have follow up questions. |
Hi Siyengar, thanks for your answer. I have two question. I made a class like you sad. CustomSharedPrefsBackedKeyChain.java Here is a code: http://ideone.com/3Zlgos. crypto = new Crypto( So, my question is,
|
You can initialize Crypto as many times as you want, just call new Crypto() For the 2 device problem, you'll need a way to share a key between the 2 devices. It sounds like you want an encrypted communication protocol between devices and not a pure file encryption solution. You might want to consider using a secure communication protocol instead like SSL. This completely depends on the communication medium and the nature of your app. |
Okey, I made this class CustomSharedPrefsBackedKeyChain and it's work. package XXX;
import com.facebook.crypto.exception.KeyChainException;
import com.facebook.crypto.keychain.KeyChain;
import com.facebook.crypto.keychain.SecureRandomFix;
import java.security.SecureRandom;
import java.util.Arrays;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import android.util.Log;
import com.facebook.crypto.cipher.NativeGCMCipher;
import com.facebook.crypto.mac.NativeMac;
/**
* Created by TheKing on 2014-12-29.
*/
public class CustomSharedPrefsBackedKeyChain implements KeyChain {
// Visible for testing.
/* package */ static final String SHARED_PREF_NAME = "crypto";
/* package */ static final String CIPHER_KEY_PREF = "cipher_key";
/* package */ static final String MAC_KEY_PREF = "mac_key";
private final SharedPreferences mSharedPreferences;
private final SecureRandom mSecureRandom;
private String key = null;
protected byte[] mCipherKey;
protected boolean mSetCipherKey;
protected byte[] mMacKey;
protected boolean mSetMacKey;
private static final SecureRandomFix sSecureRandomFix = new SecureRandomFix();
private String log = "KeyChain";
public CustomSharedPrefsBackedKeyChain(Context context, String key) {
Log.d(log, "CustomSharedPrefsBackedKeyChain");
mSharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
mSecureRandom = new SecureRandom();
this.key = key;
}
@Override
public synchronized byte[] getCipherKey() throws KeyChainException {
if (!mSetCipherKey) {
mCipherKey = maybeGenerateKey(CIPHER_KEY_PREF, NativeGCMCipher.KEY_LENGTH);
}
mSetCipherKey = true;
return mCipherKey;
}
@Override
public byte[] getMacKey() throws KeyChainException {
if (!mSetMacKey) {
mMacKey = maybeGenerateKey(MAC_KEY_PREF, NativeMac.KEY_LENGTH);
}
mSetMacKey = true;
return mMacKey;
}
@Override
public byte[] getNewIV() throws KeyChainException {
sSecureRandomFix.tryApplyFixes();
byte[] iv = new byte[NativeGCMCipher.IV_LENGTH];
mSecureRandom.nextBytes(iv);
return iv;
}
@Override
public synchronized void destroyKeys() {
mSetCipherKey = false;
mSetMacKey = false;
Arrays.fill(mCipherKey, (byte) 0);
Arrays.fill(mMacKey, (byte) 0);
mCipherKey = null;
mMacKey = null;
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.remove(CIPHER_KEY_PREF);
editor.remove(MAC_KEY_PREF);
//editor.commit();
}
/**
* Generates a key associated with a preference.
*/
private byte[] maybeGenerateKey(String pref, int length) throws KeyChainException {
String base64Key = mSharedPreferences.getString(pref, null);
String key;
if(length == NativeGCMCipher.KEY_LENGTH)
key = this.key;
else if(length == NativeMac.KEY_LENGTH)
key = (this.key + this.key + this.key +this.key);
else
key = this.key;
base64Key = key.toString();
if (base64Key == null) {
// Generate key if it doesn't exist.
return generateAndSaveKey(pref, length);
} else {
return base64Key.getBytes();
}
}
private byte[] generateAndSaveKey(String pref, int length) throws KeyChainException {
sSecureRandomFix.tryApplyFixes();
byte[] key = new byte[length];
if(length == NativeGCMCipher.KEY_LENGTH)
key = this.key.getBytes();
else if(length == NativeMac.KEY_LENGTH)
key = (this.key + this.key + this.key +this.key).getBytes();
else
key = this.key.getBytes();
mSecureRandom.nextBytes(key);
// Store the session key.
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(
pref,
encodeForPrefs(key));
//editor.commit();
Log.d(log, key.toString());
return key;
}
/**
* Visible for testing.
*/
byte[] decodeFromPrefs(String keyString) {
if (keyString == null) {
return null;
}
Log.d(log, keyString.toString());
return Base64.decode(keyString, Base64.DEFAULT);
}
/**
* Visible for testing.
*/
String encodeForPrefs(byte[] key) {
if (key == null ) {
return null;
}
return Base64.encodeToString(key, Base64.DEFAULT);
}
} To initialize use this Crypto crypto = new Crypto(new CustomSharedPrefsBackedKeyChain(c, key), new SystemNativeCryptoLibrary()); Thanks very much for your time. |
@eliaszkubala thank you for sharing this implementation! I had a very similar need. |
Hi,
I have a strange problem with sharing cipher message between two devices. I make a chat which is using this cipher to encode share message, image, video and voice. Everything works well when i type to myself, that's mean encode and decode on same device.
When I write message to someone else e.g.
message = "Hi buddy!";
key = "3oqpnnnrhip5gdh02mt6bnslke";
message = String.valueOf(Base64.encodeToString(crypto.encrypt(Base64.encode(message[0].getBytes(), Base64.DEFAULT), new Entity(key)), Base64.DEFAULT));
after encode: "AQEt6KNevPCjsgllKD985iX1lqpwYyzObkYclEK4i/fxxp0bjwLJzIcNAg=="
on another device i get the same encode message and key. But when i try decode i always get IOException.
"com.facebook.crypto.cipher.NativeGCMCipherException: decryptFinal
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.facebook.crypto.cipher.NativeGCMCipher.decryptFinal(NativeGCMCipher.java:108)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.facebook.crypto.streams.NativeGCMCipherInputStream.ensureTagValid(NativeGCMCipherInputStream.java:126)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.facebook.crypto.streams.NativeGCMCipherInputStream.read(NativeGCMCipherInputStream.java:91)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.facebook.crypto.streams.NativeGCMCipherInputStream.read(NativeGCMCipherInputStream.java:76)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.facebook.crypto.Crypto.decrypt(Crypto.java:131)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.incotalk.activity_talk.decode(activity_talk.java:1121)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.incotalk.activity_talk$6.onItemClick(activity_talk.java:446)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.widget.AdapterView.performItemClick(AdapterView.java:298)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.widget.AbsListView.performItemClick(AbsListView.java:1086)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.widget.AbsListView$PerformClick.run(AbsListView.java:2855)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.widget.AbsListView$1.run(AbsListView.java:3529)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.os.Handler.handleCallback(Handler.java:615)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:92)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.os.Looper.loop(Looper.java:137)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:4745)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at java.lang.reflect.Method.invokeNative(Native Method)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:511)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
12-26 09:37:16.399 2327-2327/com.incotalk W/System.err﹕ at dalvik.system.NativeStart.main(Native Method)"
I decode with this line of code:
byte[] messageB = Base64.decode(message, Base64.DEFAULT);
return new String(
Base64.decode(crypto.decrypt(messageB, new Entity(attachmentKeyDecoded)),Base64.DEFAULT), "UTF-8");
return new String(
Base64.decode(crypto.decrypt(messageB, new Entity(attachmentKeyDecoded)), Base64.DEFAULT),
"UTF-8"
)
Please explain why it doesn't work.
The text was updated successfully, but these errors were encountered: