//reads contact info from database and creates Contact objects private void loadContacts() { contactsList.Clear(); //empty list, if reading from database might as well reload everything SQLiteDataReader reader = db.retrieve("SELECT * FROM Users"); //gets all user records //if(reader.HasRows) //if any data was read from the DB Contact contact; //temporary contact object to add to list while (reader.Read()) //iterate over each tuple returned from the database { int ID = Convert.ToInt32((long)reader["userID"]); //sqlite handles primary key field as int64 byte[] encUsername = (byte[])reader["username"]; byte[] encIPAddress = (byte[])reader["IPAddress"]; byte[] IV = (byte[])reader["IV"]; //initialisation vector encUsername and ecnIPAddress were encrypted with byte[] masterKey = Globals.getMasterKey(); //decrypts and gets master key string username = CryptoUtility.AESDecrypt(encUsername, masterKey, IV); //decrypt username string IPAddress = CryptoUtility.AESDecrypt(encIPAddress, masterKey, IV); //decrypt IPAddress contact = new Contact(ID, username, IPAddress); //puts contact info into object contactsList.Add(contact); } }
/// <summary> /// Takes the ID of a key in the database and returns a byte array containing the key. /// This method uses caching as it will be used frequently, this is to prevent unnecessary database reads. /// </summary> /// <param name="keyID">ID of key to fetch from keys table</param> /// <returns>byte[] containing key</returns> public byte[] getKey(int keyID) { if (isCached(keyID)) //check if the key has been cached already { return(retrieveFromCache(keyID)); //return cached key } else //otherwise get key from database and store it in cache { SQLiteDataReader reader = db.retrieve($"SELECT AESKey, IV FROM Keys WHERE keyID = {keyID}"); //will get only one entry if (!reader.HasRows) //no entry with <keyID> { return(new byte[0]); //return empty byte array } reader.Read(); //prepares reader to extract values byte[] encKey = (byte[])reader["AESKey"]; //extract encrypted key byte[] IV = (byte[])reader["IV"]; //extract initialisation vector it was encrypted with byte[] key = decryptKey(encKey, IV); //decrypt key storeInCache(keyID, key); //store in cache return(key); //return decrypted key } }
/// <summary> /// Takes a contact and returns a list containg all messages exchanged between local and contact. /// </summary> /// <param name="contact">Contace for which to get history of exchanges messages</param> /// <returns>List of messages associated with the provided contact</returns> public List <Message> getMessageHistory(Contact contact) { List <Message> messages = new List <Message>(); Message message; //temp var to hold messages before being put into list //for <contactID> select every message, initialisation vector to decrypt the message, the ID of the key it's encrypted with, and bool if it was sent or received SQLiteDataReader reader = db.retrieve($"SELECT sent, message, IV, keyID FROM Messages WHERE (conversationID = \"{contact.ID}\")"); //API BUG - SELECT with explicit fields fails ONLY when the fields are in brackets, lord knows why while (reader.Read()) //iterate over all existing records { bool sent = (bool)reader["sent"]; //extract if message was sent or received byte[] encMessageBytes = (byte[])reader["message"]; //extract message byte[] messageIV = (byte[])reader["IV"]; //extract initialisation vector for message int keyID = Convert.ToInt32((long)reader["keyID"]); //extract ID of key that encrypted message. sqlite handles forien keys to primary keys as int64. byte[] messageKey = keyManager.getKey(keyID); //gets plain key from manager (must be discarded once done with) //passes encrypted message bytes, plain key and IV to CryptoUtility and gets decrypted message in return string messageString = CryptoUtility.AESDecrypt(encMessageBytes, messageKey, messageIV); messageKey = null; //garbage collect key bytes int senderID; int targetID; if (sent) //message was sent by local { senderID = 0; targetID = contact.ID; } else //message was sent by contact { senderID = contact.ID; targetID = 0; } message = new Message(messageString, senderID, targetID); //create the message object messages.Add(message); //store it in list } return(messages); }