use of org.thoughtcrime.securesms.crypto.MasterCipher in project Signal-Android by WhisperSystems.
the class TextSecurePreKeyStore method loadSerializedRecord.
private byte[] loadSerializedRecord(File recordFile) throws IOException, InvalidMessageException {
FileInputStream fin = new FileInputStream(recordFile);
int recordVersion = readInteger(fin);
if (recordVersion > CURRENT_VERSION_MARKER) {
throw new AssertionError("Invalid version: " + recordVersion);
}
byte[] serializedRecord = readBlob(fin);
if (recordVersion < PLAINTEXT_VERSION && masterSecret != null) {
MasterCipher masterCipher = new MasterCipher(masterSecret);
serializedRecord = masterCipher.decryptBytes(serializedRecord);
} else if (recordVersion < PLAINTEXT_VERSION) {
throw new AssertionError("Migration didn't happen!");
}
fin.close();
return serializedRecord;
}
use of org.thoughtcrime.securesms.crypto.MasterCipher in project Signal-Android by WhisperSystems.
the class TextSecureSessionStore method loadSession.
@Override
public SessionRecord loadSession(@NonNull SignalProtocolAddress address) {
synchronized (FILE_LOCK) {
try {
FileInputStream in = new FileInputStream(getSessionFile(address));
int versionMarker = readInteger(in);
if (versionMarker > CURRENT_VERSION) {
throw new AssertionError("Unknown version: " + versionMarker);
}
byte[] serialized = readBlob(in);
in.close();
if (versionMarker < PLAINTEXT_VERSION && masterSecret != null) {
serialized = new MasterCipher(masterSecret).decryptBytes(serialized);
} else if (versionMarker < PLAINTEXT_VERSION) {
throw new AssertionError("Session didn't get migrated: (" + versionMarker + "," + address + ")");
}
if (versionMarker == SINGLE_STATE_VERSION) {
SessionStructure sessionStructure = SessionStructure.parseFrom(serialized);
SessionState sessionState = new SessionState(sessionStructure);
return new SessionRecord(sessionState);
} else if (versionMarker >= ARCHIVE_STATES_VERSION) {
return new SessionRecord(serialized);
} else {
throw new AssertionError("Unknown version: " + versionMarker);
}
} catch (InvalidMessageException | IOException e) {
Log.w(TAG, "No existing session information found.");
return new SessionRecord();
}
}
}
use of org.thoughtcrime.securesms.crypto.MasterCipher in project Signal-Android by WhisperSystems.
the class DatabaseFactory method onApplicationLevelUpgrade.
public void onApplicationLevelUpgrade(Context context, MasterSecret masterSecret, int fromVersion, DatabaseUpgradeActivity.DatabaseUpgradeListener listener) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.beginTransaction();
if (fromVersion < DatabaseUpgradeActivity.NO_MORE_KEY_EXCHANGE_PREFIX_VERSION) {
String KEY_EXCHANGE = "?TextSecureKeyExchange";
String PROCESSED_KEY_EXCHANGE = "?TextSecureKeyExchangd";
String STALE_KEY_EXCHANGE = "?TextSecureKeyExchangs";
int ROW_LIMIT = 500;
MasterCipher masterCipher = new MasterCipher(masterSecret);
int smsCount = 0;
int threadCount = 0;
int skip = 0;
Cursor cursor = db.query("sms", new String[] { "COUNT(*)" }, "type & " + 0x80000000 + " != 0", null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
smsCount = cursor.getInt(0);
cursor.close();
}
cursor = db.query("thread", new String[] { "COUNT(*)" }, "snippet_type & " + 0x80000000 + " != 0", null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
threadCount = cursor.getInt(0);
cursor.close();
}
Cursor smsCursor = null;
Log.w("DatabaseFactory", "Upgrade count: " + (smsCount + threadCount));
do {
Log.w("DatabaseFactory", "Looping SMS cursor...");
if (smsCursor != null)
smsCursor.close();
smsCursor = db.query("sms", new String[] { "_id", "type", "body" }, "type & " + 0x80000000 + " != 0", null, null, null, "_id", skip + "," + ROW_LIMIT);
while (smsCursor != null && smsCursor.moveToNext()) {
listener.setProgress(smsCursor.getPosition() + skip, smsCount + threadCount);
try {
String body = masterCipher.decryptBody(smsCursor.getString(smsCursor.getColumnIndexOrThrow("body")));
long type = smsCursor.getLong(smsCursor.getColumnIndexOrThrow("type"));
long id = smsCursor.getLong(smsCursor.getColumnIndexOrThrow("_id"));
if (body.startsWith(KEY_EXCHANGE)) {
body = body.substring(KEY_EXCHANGE.length());
body = masterCipher.encryptBody(body);
type |= 0x8000;
db.execSQL("UPDATE sms SET body = ?, type = ? WHERE _id = ?", new String[] { body, type + "", id + "" });
} else if (body.startsWith(PROCESSED_KEY_EXCHANGE)) {
body = body.substring(PROCESSED_KEY_EXCHANGE.length());
body = masterCipher.encryptBody(body);
type |= (0x8000 | 0x2000);
db.execSQL("UPDATE sms SET body = ?, type = ? WHERE _id = ?", new String[] { body, type + "", id + "" });
} else if (body.startsWith(STALE_KEY_EXCHANGE)) {
body = body.substring(STALE_KEY_EXCHANGE.length());
body = masterCipher.encryptBody(body);
type |= (0x8000 | 0x4000);
db.execSQL("UPDATE sms SET body = ?, type = ? WHERE _id = ?", new String[] { body, type + "", id + "" });
}
} catch (InvalidMessageException e) {
Log.w("DatabaseFactory", e);
}
}
skip += ROW_LIMIT;
} while (smsCursor != null && smsCursor.getCount() > 0);
Cursor threadCursor = null;
skip = 0;
do {
Log.w("DatabaseFactory", "Looping thread cursor...");
if (threadCursor != null)
threadCursor.close();
threadCursor = db.query("thread", new String[] { "_id", "snippet_type", "snippet" }, "snippet_type & " + 0x80000000 + " != 0", null, null, null, "_id", skip + "," + ROW_LIMIT);
while (threadCursor != null && threadCursor.moveToNext()) {
listener.setProgress(smsCount + threadCursor.getPosition(), smsCount + threadCount);
try {
String snippet = threadCursor.getString(threadCursor.getColumnIndexOrThrow("snippet"));
long snippetType = threadCursor.getLong(threadCursor.getColumnIndexOrThrow("snippet_type"));
long id = threadCursor.getLong(threadCursor.getColumnIndexOrThrow("_id"));
if (!TextUtils.isEmpty(snippet)) {
snippet = masterCipher.decryptBody(snippet);
}
if (snippet.startsWith(KEY_EXCHANGE)) {
snippet = snippet.substring(KEY_EXCHANGE.length());
snippet = masterCipher.encryptBody(snippet);
snippetType |= 0x8000;
db.execSQL("UPDATE thread SET snippet = ?, snippet_type = ? WHERE _id = ?", new String[] { snippet, snippetType + "", id + "" });
} else if (snippet.startsWith(PROCESSED_KEY_EXCHANGE)) {
snippet = snippet.substring(PROCESSED_KEY_EXCHANGE.length());
snippet = masterCipher.encryptBody(snippet);
snippetType |= (0x8000 | 0x2000);
db.execSQL("UPDATE thread SET snippet = ?, snippet_type = ? WHERE _id = ?", new String[] { snippet, snippetType + "", id + "" });
} else if (snippet.startsWith(STALE_KEY_EXCHANGE)) {
snippet = snippet.substring(STALE_KEY_EXCHANGE.length());
snippet = masterCipher.encryptBody(snippet);
snippetType |= (0x8000 | 0x4000);
db.execSQL("UPDATE thread SET snippet = ?, snippet_type = ? WHERE _id = ?", new String[] { snippet, snippetType + "", id + "" });
}
} catch (InvalidMessageException e) {
Log.w("DatabaseFactory", e);
}
}
skip += ROW_LIMIT;
} while (threadCursor != null && threadCursor.getCount() > 0);
if (smsCursor != null)
smsCursor.close();
if (threadCursor != null)
threadCursor.close();
}
if (fromVersion < DatabaseUpgradeActivity.MMS_BODY_VERSION) {
Log.w("DatabaseFactory", "Update MMS bodies...");
MasterCipher masterCipher = new MasterCipher(masterSecret);
Cursor mmsCursor = db.query("mms", new String[] { "_id" }, "msg_box & " + 0x80000000L + " != 0", null, null, null, null);
Log.w("DatabaseFactory", "Got MMS rows: " + (mmsCursor == null ? "null" : mmsCursor.getCount()));
while (mmsCursor != null && mmsCursor.moveToNext()) {
listener.setProgress(mmsCursor.getPosition(), mmsCursor.getCount());
long mmsId = mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow("_id"));
String body = null;
int partCount = 0;
Cursor partCursor = db.query("part", new String[] { "_id", "ct", "_data", "encrypted" }, "mid = ?", new String[] { mmsId + "" }, null, null, null);
while (partCursor != null && partCursor.moveToNext()) {
String contentType = partCursor.getString(partCursor.getColumnIndexOrThrow("ct"));
if (ContentType.isTextType(contentType)) {
try {
long partId = partCursor.getLong(partCursor.getColumnIndexOrThrow("_id"));
String dataLocation = partCursor.getString(partCursor.getColumnIndexOrThrow("_data"));
boolean encrypted = partCursor.getInt(partCursor.getColumnIndexOrThrow("encrypted")) == 1;
File dataFile = new File(dataLocation);
InputStream is;
if (encrypted)
is = new DecryptingPartInputStream(dataFile, masterSecret);
else
is = new FileInputStream(dataFile);
body = (body == null) ? Util.readFullyAsString(is) : body + " " + Util.readFullyAsString(is);
//noinspection ResultOfMethodCallIgnored
dataFile.delete();
db.delete("part", "_id = ?", new String[] { partId + "" });
} catch (IOException e) {
Log.w("DatabaseFactory", e);
}
} else if (ContentType.isAudioType(contentType) || ContentType.isImageType(contentType) || ContentType.isVideoType(contentType)) {
partCount++;
}
}
if (!TextUtils.isEmpty(body)) {
body = masterCipher.encryptBody(body);
db.execSQL("UPDATE mms SET body = ?, part_count = ? WHERE _id = ?", new String[] { body, partCount + "", mmsId + "" });
} else {
db.execSQL("UPDATE mms SET part_count = ? WHERE _id = ?", new String[] { partCount + "", mmsId + "" });
}
Log.w("DatabaseFactory", "Updated body: " + body + " and part_count: " + partCount);
}
}
if (fromVersion < DatabaseUpgradeActivity.TOFU_IDENTITIES_VERSION) {
File sessionDirectory = new File(context.getFilesDir() + File.separator + "sessions");
if (sessionDirectory.exists() && sessionDirectory.isDirectory()) {
File[] sessions = sessionDirectory.listFiles();
if (sessions != null) {
for (File session : sessions) {
String name = session.getName();
if (name.matches("[0-9]+")) {
long recipientId = Long.parseLong(name);
IdentityKey identityKey = null;
if (identityKey != null) {
MasterCipher masterCipher = new MasterCipher(masterSecret);
String identityKeyString = Base64.encodeBytes(identityKey.serialize());
String macString = Base64.encodeBytes(masterCipher.getMacFor(recipientId + identityKeyString));
db.execSQL("REPLACE INTO identities (recipient, key, mac) VALUES (?, ?, ?)", new String[] { recipientId + "", identityKeyString, macString });
}
}
}
}
}
}
if (fromVersion < DatabaseUpgradeActivity.ASYMMETRIC_MASTER_SECRET_FIX_VERSION) {
if (!MasterSecretUtil.hasAsymmericMasterSecret(context)) {
MasterSecretUtil.generateAsymmetricMasterSecret(context, masterSecret);
MasterCipher masterCipher = new MasterCipher(masterSecret);
Cursor cursor = null;
try {
cursor = db.query(SmsDatabase.TABLE_NAME, new String[] { SmsDatabase.ID, SmsDatabase.BODY, SmsDatabase.TYPE }, SmsDatabase.TYPE + " & ? == 0", new String[] { String.valueOf(SmsDatabase.Types.ENCRYPTION_MASK) }, null, null, null);
while (cursor.moveToNext()) {
long id = cursor.getLong(0);
String body = cursor.getString(1);
long type = cursor.getLong(2);
String encryptedBody = masterCipher.encryptBody(body);
ContentValues update = new ContentValues();
update.put(SmsDatabase.BODY, encryptedBody);
update.put(SmsDatabase.TYPE, type | SmsDatabase.Types.ENCRYPTION_SYMMETRIC_BIT);
db.update(SmsDatabase.TABLE_NAME, update, SmsDatabase.ID + " = ?", new String[] { String.valueOf(id) });
}
} finally {
if (cursor != null)
cursor.close();
}
}
}
db.setTransactionSuccessful();
db.endTransaction();
// DecryptingQueue.schedulePendingDecrypts(context, masterSecret);
MessageNotifier.updateNotification(context, masterSecret);
}
use of org.thoughtcrime.securesms.crypto.MasterCipher in project Signal-Android by WhisperSystems.
the class PlaintextBackupImporter method importPlaintext.
private static void importPlaintext(Context context, MasterSecret masterSecret) throws IOException {
Log.w("PlaintextBackupImporter", "importPlaintext()");
SmsDatabase db = DatabaseFactory.getSmsDatabase(context);
SQLiteDatabase transaction = db.beginTransaction();
try {
ThreadDatabase threads = DatabaseFactory.getThreadDatabase(context);
XmlBackup backup = new XmlBackup(getPlaintextExportFile().getAbsolutePath());
MasterCipher masterCipher = new MasterCipher(masterSecret);
Set<Long> modifiedThreads = new HashSet<Long>();
XmlBackup.XmlBackupItem item;
while ((item = backup.getNext()) != null) {
Recipients recipients = RecipientFactory.getRecipientsFromString(context, item.getAddress(), false);
long threadId = threads.getThreadIdFor(recipients);
SQLiteStatement statement = db.createInsertStatement(transaction);
if (item.getAddress() == null || item.getAddress().equals("null"))
continue;
if (!isAppropriateTypeForImport(item.getType()))
continue;
addStringToStatement(statement, 1, item.getAddress());
addNullToStatement(statement, 2);
addLongToStatement(statement, 3, item.getDate());
addLongToStatement(statement, 4, item.getDate());
addLongToStatement(statement, 5, item.getProtocol());
addLongToStatement(statement, 6, item.getRead());
addLongToStatement(statement, 7, item.getStatus());
addTranslatedTypeToStatement(statement, 8, item.getType());
addNullToStatement(statement, 9);
addStringToStatement(statement, 10, item.getSubject());
addEncryptedStingToStatement(masterCipher, statement, 11, item.getBody());
addStringToStatement(statement, 12, item.getServiceCenter());
addLongToStatement(statement, 13, threadId);
modifiedThreads.add(threadId);
statement.execute();
}
for (long threadId : modifiedThreads) {
threads.update(threadId, true);
}
Log.w("PlaintextBackupImporter", "Exited loop");
} catch (XmlPullParserException e) {
Log.w("PlaintextBackupImporter", e);
throw new IOException("XML Parsing error!");
} finally {
db.endTransaction(transaction);
}
}
use of org.thoughtcrime.securesms.crypto.MasterCipher in project Signal-Android by WhisperSystems.
the class EncryptingSmsDatabase method getEncryptedBody.
private String getEncryptedBody(MasterSecret masterSecret, String body) {
MasterCipher bodyCipher = new MasterCipher(masterSecret);
String ciphertext = bodyCipher.encryptBody(body);
plaintextCache.put(ciphertext, body);
return ciphertext;
}
Aggregations