mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 00:37:47 +00:00
parent
b7badec752
commit
0b62cf372b
@ -25,11 +25,11 @@ package org.thoughtcrime.securesms.contacts;
|
||||
public class NameAndNumber {
|
||||
public String name;
|
||||
public String number;
|
||||
|
||||
|
||||
public NameAndNumber(String name, String number) {
|
||||
this.name = name;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
|
||||
public NameAndNumber() {}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public class AsymmetricMasterCipher {
|
||||
public AsymmetricMasterCipher(AsymmetricMasterSecret asymmetricMasterSecret) {
|
||||
this.asymmetricMasterSecret = asymmetricMasterSecret;
|
||||
}
|
||||
|
||||
|
||||
public String decryptBody(String body) throws IOException, InvalidMessageException {
|
||||
try {
|
||||
byte[] combined = Base64.decode(body);
|
||||
@ -77,7 +77,7 @@ public class AsymmetricMasterCipher {
|
||||
throw new InvalidMessageException(ike);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String encryptBody(String body) {
|
||||
try {
|
||||
ECPublicKey theirPublic = asymmetricMasterSecret.getDjbPublicKey();
|
||||
@ -95,31 +95,31 @@ public class AsymmetricMasterCipher {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private MasterCipher getMasterCipherForSecret(byte[] secretBytes) {
|
||||
SecretKeySpec cipherKey = deriveCipherKey(secretBytes);
|
||||
SecretKeySpec macKey = deriveMacKey(secretBytes);
|
||||
MasterSecret masterSecret = new MasterSecret(cipherKey, macKey);
|
||||
|
||||
return new MasterCipher(masterSecret);
|
||||
return new MasterCipher(masterSecret);
|
||||
}
|
||||
|
||||
|
||||
private SecretKeySpec deriveMacKey(byte[] secretBytes) {
|
||||
byte[] digestedBytes = getDigestedBytes(secretBytes, 1);
|
||||
byte[] macKeyBytes = new byte[20];
|
||||
|
||||
|
||||
System.arraycopy(digestedBytes, 0, macKeyBytes, 0, macKeyBytes.length);
|
||||
return new SecretKeySpec(macKeyBytes, "HmacSHA1");
|
||||
}
|
||||
|
||||
|
||||
private SecretKeySpec deriveCipherKey(byte[] secretBytes) {
|
||||
byte[] digestedBytes = getDigestedBytes(secretBytes, 0);
|
||||
byte[] cipherKeyBytes = new byte[16];
|
||||
|
||||
System.arraycopy(digestedBytes, 0, cipherKeyBytes, 0, cipherKeyBytes.length);
|
||||
|
||||
System.arraycopy(digestedBytes, 0, cipherKeyBytes, 0, cipherKeyBytes.length);
|
||||
return new SecretKeySpec(cipherKeyBytes, "AES");
|
||||
}
|
||||
|
||||
|
||||
private byte[] getDigestedBytes(byte[] secretBytes, int iteration) {
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
|
@ -44,24 +44,24 @@ import android.util.Log;
|
||||
*/
|
||||
|
||||
public class DecryptingPartInputStream extends FileInputStream {
|
||||
|
||||
|
||||
private static final int IV_LENGTH = 16;
|
||||
private static final int MAC_LENGTH = 20;
|
||||
|
||||
|
||||
private Cipher cipher;
|
||||
private Mac mac;
|
||||
|
||||
|
||||
private boolean done;
|
||||
private long totalDataSize;
|
||||
private long totalRead;
|
||||
private byte[] overflowBuffer;
|
||||
|
||||
|
||||
public DecryptingPartInputStream(File file, MasterSecret masterSecret) throws FileNotFoundException {
|
||||
super(file);
|
||||
try {
|
||||
if (file.length() <= IV_LENGTH + MAC_LENGTH)
|
||||
throw new FileNotFoundException("Part shorter than crypto overhead!");
|
||||
|
||||
|
||||
done = false;
|
||||
mac = initializeMac(masterSecret.getMacKey());
|
||||
cipher = initializeCipher(masterSecret.getEncryptionKey());
|
||||
@ -81,12 +81,12 @@ public class DecryptingPartInputStream extends FileInputStream {
|
||||
throw new FileNotFoundException("IOException while reading IV!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int length) throws IOException {
|
||||
if (totalRead != totalDataSize)
|
||||
@ -96,11 +96,11 @@ public class DecryptingPartInputStream extends FileInputStream {
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private int readFinal(byte[] buffer, int offset, int length) throws IOException {
|
||||
try {
|
||||
try {
|
||||
int flourish = cipher.doFinal(buffer, offset);
|
||||
// mac.update(buffer, offset, flourish);
|
||||
//mac.update(buffer, offset, flourish);
|
||||
|
||||
byte[] ourMac = mac.doFinal();
|
||||
byte[] theirMac = new byte[mac.getMacLength()];
|
||||
@ -108,7 +108,7 @@ public class DecryptingPartInputStream extends FileInputStream {
|
||||
|
||||
if (!Arrays.equals(ourMac, theirMac))
|
||||
throw new IOException("MAC doesn't match! Potential tampering?");
|
||||
|
||||
|
||||
done = true;
|
||||
return flourish;
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
@ -122,7 +122,7 @@ public class DecryptingPartInputStream extends FileInputStream {
|
||||
throw new IOException("Bad padding exception!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int readIncremental(byte[] buffer, int offset, int length) throws IOException {
|
||||
int readLength = 0;
|
||||
if (null != overflowBuffer) {
|
||||
@ -145,11 +145,11 @@ public class DecryptingPartInputStream extends FileInputStream {
|
||||
|
||||
if (length + totalRead > totalDataSize)
|
||||
length = (int)(totalDataSize - totalRead);
|
||||
|
||||
|
||||
byte[] internalBuffer = new byte[length];
|
||||
int read = super.read(internalBuffer, 0, internalBuffer.length <= cipher.getBlockSize() ? internalBuffer.length : internalBuffer.length - cipher.getBlockSize());
|
||||
totalRead += read;
|
||||
|
||||
|
||||
try {
|
||||
mac.update(internalBuffer, 0, read);
|
||||
|
||||
@ -175,41 +175,41 @@ public class DecryptingPartInputStream extends FileInputStream {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Mac initializeMac(SecretKeySpec key) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
Mac hmac = Mac.getInstance("HmacSHA1");
|
||||
hmac.init(key);
|
||||
|
||||
return hmac;
|
||||
}
|
||||
|
||||
|
||||
private Cipher initializeCipher(SecretKeySpec key)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException,
|
||||
NoSuchAlgorithmException, NoSuchPaddingException, IOException
|
||||
NoSuchAlgorithmException, NoSuchPaddingException, IOException
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
IvParameterSpec iv = readIv(cipher.getBlockSize());
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, iv);
|
||||
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
|
||||
private IvParameterSpec readIv(int size) throws IOException {
|
||||
byte[] iv = new byte[size];
|
||||
readFully(iv);
|
||||
|
||||
|
||||
mac.update(iv);
|
||||
return new IvParameterSpec(iv);
|
||||
}
|
||||
|
||||
|
||||
private void readFully(byte[] buffer) throws IOException {
|
||||
int offset = 0;
|
||||
|
||||
|
||||
for (;;) {
|
||||
int read = super.read(buffer, offset, buffer.length-offset);
|
||||
|
||||
|
||||
if (read + offset < buffer.length) offset += read;
|
||||
else return;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public class EncryptingPartOutputStream extends FileOutputStream {
|
||||
private Cipher cipher;
|
||||
private Mac mac;
|
||||
private boolean closed;
|
||||
|
||||
|
||||
public EncryptingPartOutputStream(File file, MasterSecret masterSecret) throws FileNotFoundException {
|
||||
super(file);
|
||||
|
||||
@ -62,37 +62,37 @@ public class EncryptingPartOutputStream extends FileOutputStream {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) throws IOException {
|
||||
this.write(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int length) throws IOException {
|
||||
byte[] encryptedBuffer = cipher.update(buffer, offset, length);
|
||||
|
||||
|
||||
if (encryptedBuffer != null) {
|
||||
mac.update(encryptedBuffer);
|
||||
super.write(encryptedBuffer, 0, encryptedBuffer.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
if (!closed) {
|
||||
byte[] encryptedRemainder = cipher.doFinal();
|
||||
mac.update(encryptedRemainder);
|
||||
|
||||
|
||||
byte[] macBytes = mac.doFinal();
|
||||
|
||||
|
||||
super.write(encryptedRemainder, 0, encryptedRemainder.length);
|
||||
super.write(macBytes, 0, macBytes.length);
|
||||
super.write(macBytes, 0, macBytes.length);
|
||||
|
||||
closed = true;
|
||||
}
|
||||
|
||||
|
||||
super.close();
|
||||
} catch (BadPaddingException bpe) {
|
||||
throw new AssertionError(bpe);
|
||||
@ -100,22 +100,22 @@ public class EncryptingPartOutputStream extends FileOutputStream {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Mac initializeMac(SecretKeySpec key) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
Mac hmac = Mac.getInstance("HmacSHA1");
|
||||
hmac.init(key);
|
||||
|
||||
return hmac;
|
||||
}
|
||||
|
||||
|
||||
private Cipher initializeCipher(Mac mac, SecretKeySpec key) throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
|
||||
byte[] ivBytes = cipher.getIV();
|
||||
byte[] ivBytes = cipher.getIV();
|
||||
mac.update(ivBytes);
|
||||
super.write(ivBytes, 0, ivBytes.length);
|
||||
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class IdentityKeyUtil {
|
||||
|
||||
private static final String IDENTITY_PUBLIC_KEY_DJB_PREF = "pref_identity_public_curve25519";
|
||||
private static final String IDENTITY_PRIVATE_KEY_DJB_PREF = "pref_identity_private_curve25519";
|
||||
|
||||
|
||||
public static boolean hasIdentityKey(Context context) {
|
||||
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
|
||||
|
||||
@ -50,10 +50,10 @@ public class IdentityKeyUtil {
|
||||
preferences.contains(IDENTITY_PUBLIC_KEY_DJB_PREF) &&
|
||||
preferences.contains(IDENTITY_PRIVATE_KEY_DJB_PREF);
|
||||
}
|
||||
|
||||
|
||||
public static IdentityKey getIdentityKey(Context context) {
|
||||
if (!hasIdentityKey(context)) return null;
|
||||
|
||||
|
||||
try {
|
||||
byte[] publicKeyBytes = Base64.decode(retrieve(context, IDENTITY_PUBLIC_KEY_DJB_PREF));
|
||||
return new IdentityKey(publicKeyBytes, 0);
|
||||
@ -114,11 +114,11 @@ public class IdentityKeyUtil {
|
||||
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
|
||||
return preferences.getString(key, null);
|
||||
}
|
||||
|
||||
|
||||
public static void save(Context context, String key, String value) {
|
||||
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
|
||||
Editor preferencesEditor = preferences.edit();
|
||||
|
||||
|
||||
preferencesEditor.putString(key, value);
|
||||
if (!preferencesEditor.commit()) throw new AssertionError("failed to save identity key/value to shared preferences");
|
||||
}
|
||||
|
@ -41,12 +41,12 @@ public class AudioSlide extends Slide {
|
||||
public AudioSlide(Context context, Uri uri) throws IOException, MediaTooLargeException {
|
||||
super(context, constructPartFromUri(context, uri));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasImage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasAudio() {
|
||||
return true;
|
||||
@ -69,15 +69,15 @@ public class AudioSlide extends Slide {
|
||||
|
||||
public static PduPart constructPartFromUri(Context context, Uri uri) throws IOException, MediaTooLargeException {
|
||||
PduPart part = new PduPart();
|
||||
|
||||
|
||||
if (getMediaSize(context, uri) > MAX_MESSAGE_SIZE)
|
||||
throw new MediaTooLargeException("Audio track larger than size maximum.");
|
||||
|
||||
|
||||
Cursor cursor = null;
|
||||
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, new String[]{Audio.Media.MIME_TYPE}, null, null, null);
|
||||
|
||||
|
||||
if (cursor != null && cursor.moveToFirst())
|
||||
part.setContentType(cursor.getString(0).getBytes());
|
||||
else
|
||||
@ -90,7 +90,7 @@ public class AudioSlide extends Slide {
|
||||
part.setDataUri(uri);
|
||||
part.setContentId((System.currentTimeMillis()+"").getBytes());
|
||||
part.setName(("Audio" + System.currentTimeMillis()).getBytes());
|
||||
|
||||
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ public class SlideDeck {
|
||||
public void clear() {
|
||||
slides.clear();
|
||||
}
|
||||
|
||||
|
||||
public PduBody toPduBody() {
|
||||
PduBody body = new PduBody();
|
||||
|
||||
@ -87,7 +87,7 @@ public class SlideDeck {
|
||||
public void addSlide(Slide slide) {
|
||||
slides.add(slide);
|
||||
}
|
||||
|
||||
|
||||
public List<Slide> getSlides() {
|
||||
return slides;
|
||||
}
|
||||
@ -101,5 +101,5 @@ public class SlideDeck {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import ws.com.google.android.mms.pdu.CharacterSets;
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public class TextSlide extends Slide {
|
||||
|
||||
|
||||
private static final int MAX_CACHE_SIZE = 10;
|
||||
private static final Map<Uri, SoftReference<String>> textCache =
|
||||
Collections.synchronizedMap(new LRUCache<Uri, SoftReference<String>>(MAX_CACHE_SIZE));
|
||||
@ -54,7 +54,7 @@ public class TextSlide extends Slide {
|
||||
public boolean hasText() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
try {
|
||||
@ -69,9 +69,9 @@ public class TextSlide extends Slide {
|
||||
}
|
||||
|
||||
|
||||
String text = new String(getPartData(), CharacterSets.getMimeName(part.getCharset()));
|
||||
String text = new String(getPartData(), CharacterSets.getMimeName(part.getCharset()));
|
||||
textCache.put(part.getDataUri(), new SoftReference<String>(text));
|
||||
|
||||
|
||||
return text;
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
Log.w("TextSlide", uee);
|
||||
|
@ -79,7 +79,7 @@ public class VideoSlide extends Slide {
|
||||
PduPart part = new PduPart();
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor cursor = null;
|
||||
|
||||
|
||||
try {
|
||||
cursor = resolver.query(uri, new String[] {MediaStore.Video.Media.MIME_TYPE}, null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
@ -90,14 +90,14 @@ public class VideoSlide extends Slide {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
|
||||
if (getMediaSize(context, uri) > MAX_MESSAGE_SIZE)
|
||||
throw new MediaTooLargeException("Video exceeds maximum message size.");
|
||||
|
||||
|
||||
part.setDataUri(uri);
|
||||
part.setContentId((System.currentTimeMillis()+"").getBytes());
|
||||
part.setName(("Video" + System.currentTimeMillis()).getBytes());
|
||||
|
||||
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
@ -26,7 +26,7 @@ import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SmsTransportDetails {
|
||||
|
||||
|
||||
public static final int SMS_SIZE = 160;
|
||||
public static final int MULTIPART_SMS_SIZE = 153;
|
||||
|
||||
|
@ -37,7 +37,7 @@ public class MemoryCleaner {
|
||||
public static void clean(MasterSecret masterSecret) {
|
||||
// if (masterSecret == null)
|
||||
// return;
|
||||
//
|
||||
//
|
||||
// try {
|
||||
// SecretKeySpec cipherKey = masterSecret.getEncryptionKey();
|
||||
// SecretKeySpec macKey = masterSecret.getMacKey();
|
||||
|
Loading…
x
Reference in New Issue
Block a user