use of org.thoughtcrime.securesms.crypto.DecryptingPartInputStream 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.DecryptingPartInputStream in project Signal-Android by WhisperSystems.
the class EncryptedMediaDataSource method getSize.
@Override
public long getSize() throws IOException {
DecryptingPartInputStream inputStream = new DecryptingPartInputStream(mediaFile, masterSecret);
byte[] buffer = new byte[4096];
long size = 0;
int read;
while ((read = inputStream.read(buffer)) != -1) {
size += read;
}
return size;
}
use of org.thoughtcrime.securesms.crypto.DecryptingPartInputStream in project Signal-Android by WhisperSystems.
the class EncryptedMediaDataSource method readAt.
@Override
public int readAt(long position, byte[] bytes, int offset, int length) throws IOException {
DecryptingPartInputStream inputStream = new DecryptingPartInputStream(mediaFile, masterSecret);
byte[] buffer = new byte[4096];
long headerRemaining = position;
while (headerRemaining > 0) {
int read = inputStream.read(buffer, 0, Util.toIntExact(Math.min((long) buffer.length, headerRemaining)));
if (read == -1)
return -1;
headerRemaining -= read;
}
int returnValue = inputStream.read(bytes, offset, length);
inputStream.close();
return returnValue;
}
Aggregations