Moving micasa 1.5 trunk to Novell forge.
This commit is contained in:
497
c_micasad/lss/CASACrypto.cs
Normal file
497
c_micasad/lss/CASACrypto.cs
Normal file
@@ -0,0 +1,497 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using sscs.common;
|
||||
using sscs.constants;
|
||||
|
||||
namespace sscs.crypto
|
||||
{
|
||||
public class CASACrypto
|
||||
{
|
||||
internal static byte[] Generate16ByteKeyFromString(string TheString)
|
||||
{
|
||||
byte[] baKey = new byte[16]; //return value
|
||||
try
|
||||
{
|
||||
Random rand = new Random(TheString.GetHashCode());
|
||||
rand.NextBytes(baKey);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Key generation failed");
|
||||
baKey = null;
|
||||
}
|
||||
return baKey;
|
||||
}
|
||||
|
||||
internal static bool StoreKeySetUsingMasterPasscode(byte[] key,
|
||||
byte[] IV, byte[] baMasterPasscode, string fileName)
|
||||
{
|
||||
bool bRet = false;
|
||||
try
|
||||
{
|
||||
|
||||
//Get an encryptor.
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform encryptor;
|
||||
encryptor = myRijndael.CreateEncryptor(baMasterPasscode, baMasterPasscode);
|
||||
|
||||
//Encrypt the data to a file
|
||||
FileStream fsEncrypt = new FileStream(fileName, FileMode.Create);
|
||||
|
||||
SHA256 sha = new SHA256Managed();
|
||||
byte[] hash = sha.ComputeHash(key);
|
||||
|
||||
fsEncrypt.Write(hash,0,hash.Length);
|
||||
fsEncrypt.Flush();
|
||||
|
||||
CryptoStream csEncrypt = new CryptoStream(fsEncrypt, encryptor, CryptoStreamMode.Write);
|
||||
|
||||
//Write all data to the crypto stream and flush it.
|
||||
csEncrypt.Write(key, 0, key.Length);
|
||||
csEncrypt.FlushFinalBlock();
|
||||
fsEncrypt.Close();
|
||||
bRet = true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Unable to store the generated key");
|
||||
bRet = false;
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
|
||||
internal static byte[] GetKeySetFromFile(byte[] baMasterPasscode,
|
||||
string fileName )
|
||||
{
|
||||
byte[] baSavedKey = null;
|
||||
try
|
||||
{
|
||||
if(!File.Exists(fileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Get a decryptor that uses the same key and IV
|
||||
* as the encryptor.
|
||||
*/
|
||||
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform decryptor = myRijndael.CreateDecryptor(baMasterPasscode, baMasterPasscode);
|
||||
//Now decrypt
|
||||
FileStream fsDecrypt = new FileStream(fileName, FileMode.Open);
|
||||
|
||||
byte[] storedHash = new byte[32];
|
||||
fsDecrypt.Read(storedHash,0,storedHash.Length);
|
||||
|
||||
CryptoStream csDecrypt = new CryptoStream(fsDecrypt, decryptor, CryptoStreamMode.Read);
|
||||
baSavedKey = new byte[32];
|
||||
|
||||
//Read the data out of the crypto stream.
|
||||
csDecrypt.Read(baSavedKey, 0, baSavedKey.Length);
|
||||
fsDecrypt.Close();
|
||||
|
||||
SHA256 sha = new SHA256Managed();
|
||||
byte[] newHash = sha.ComputeHash(baSavedKey);
|
||||
for( int i = 0 ; i < 32; i++ )
|
||||
{
|
||||
if(storedHash[i] != newHash[i])
|
||||
{
|
||||
CSSSLogger.DbgLog("Hash doesnot match");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return baSavedKey;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Unable to get the stored key");
|
||||
baSavedKey = null;
|
||||
}
|
||||
return baSavedKey;
|
||||
}
|
||||
|
||||
internal static void EncryptDataAndWriteToFile(byte[] xmlData,
|
||||
byte[] key, string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] IV = new byte[16];
|
||||
for(int z = 0 ; z < 16; z++ )
|
||||
IV[z] = key[z];
|
||||
|
||||
//Get an encryptor.
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
|
||||
|
||||
//Encrypt the data to a file
|
||||
FileStream fsEncrypt = new FileStream(fileName, FileMode.Create);
|
||||
SHA256 sha = new SHA256Managed();
|
||||
|
||||
byte[] hash = sha.ComputeHash(xmlData);
|
||||
|
||||
fsEncrypt.Write(hash,0,hash.Length);
|
||||
fsEncrypt.Flush();
|
||||
|
||||
CryptoStream csEncrypt = new CryptoStream(fsEncrypt, encryptor, CryptoStreamMode.Write);
|
||||
|
||||
//Write all data to the crypto stream and flush it.
|
||||
csEncrypt.Write(xmlData, 0, xmlData.Length);
|
||||
csEncrypt.FlushFinalBlock();
|
||||
fsEncrypt.Close();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Encrypting and storing to file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] ReadFileAndDecryptData(byte[] key,
|
||||
string fileName)
|
||||
{
|
||||
FileStream fsDecrypt = null;
|
||||
try
|
||||
{
|
||||
byte[] IV = new byte[16];
|
||||
for(int z = 0 ; z < 16; z++ )
|
||||
IV[z] = key[z];
|
||||
|
||||
//Get a decryptor that uses the same key and IV as the encryptor.
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
|
||||
|
||||
if(!File.Exists(fileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//Now decrypt
|
||||
fsDecrypt = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
byte[] storedHash = new byte[32];
|
||||
fsDecrypt.Read(storedHash,0,storedHash.Length);
|
||||
|
||||
CryptoStream csDecrypt = new CryptoStream(fsDecrypt, decryptor, CryptoStreamMode.Read);
|
||||
long fileLen = fsDecrypt.Length - 32;
|
||||
byte[] fromEncrypt = new byte[fileLen];
|
||||
|
||||
//Read the data out of the crypto stream.
|
||||
int bytesRead = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
|
||||
byte[] tmpEncrypt = new byte[bytesRead];
|
||||
for(int i = 0 ; i < bytesRead; i++ )
|
||||
tmpEncrypt[i] = fromEncrypt[i];
|
||||
|
||||
SHA256 sha = new SHA256Managed();
|
||||
byte[] newHash = sha.ComputeHash(tmpEncrypt);
|
||||
|
||||
for( int i = 0 ; i < 32; i++ )
|
||||
{
|
||||
if(storedHash[i] != newHash[i])
|
||||
{
|
||||
CSSSLogger.DbgLog("Hash doesnot match");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fsDecrypt.Close();
|
||||
return tmpEncrypt;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
if(fsDecrypt != null)
|
||||
{
|
||||
fsDecrypt.Close();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/* The methods EncryptData() and DecryptData() would be
|
||||
* required when we use a database to store secrets.
|
||||
*/
|
||||
|
||||
/* Encrypts the data with the key and returns the encrypted buffer.
|
||||
*/
|
||||
|
||||
internal static byte[] EncryptData(byte[] data, byte[] key)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
byte[] IV = new byte[16];
|
||||
int i = 0;
|
||||
for(i = 0 ; i < 16; i++ )
|
||||
IV[i] = key[i];
|
||||
|
||||
//Get an encryptor.
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
|
||||
MemoryStream ms1 = new MemoryStream();
|
||||
CryptoStream csEncrypt = new CryptoStream(ms1, encryptor, CryptoStreamMode.Write);
|
||||
|
||||
//Write all data to the crypto stream and flush it.
|
||||
csEncrypt.Write(data, 0, data.Length);
|
||||
csEncrypt.FlushFinalBlock();
|
||||
return ms1.ToArray();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Decrypts the buffer(encrypted) with the key and returns the
|
||||
* decrypted data.
|
||||
*/
|
||||
|
||||
internal static byte[] DecryptData(byte[] buffer, byte[] key)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] IV = new byte[16];
|
||||
for(int i = 0 ; i < 16; i++ )
|
||||
IV[i] = key[i];
|
||||
//Get a decryptor that uses the same key and IV as the encryptor.
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
|
||||
MemoryStream ms1 = new MemoryStream(buffer);
|
||||
CryptoStream csDecrypt = new CryptoStream(ms1, decryptor, CryptoStreamMode.Read);
|
||||
byte[] fromEncrypt = new byte[buffer.Length];
|
||||
//Read the data out of the crypto stream.
|
||||
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
|
||||
return fromEncrypt;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* This method checks if we can get the master passcode by
|
||||
* decrypting the passwds file ( where we store all possible
|
||||
* passwds cross-encrypted.
|
||||
*
|
||||
* TBD : As we are storing master passcode and the keys in 2
|
||||
* different files, we need to take care of cases when 1 of the files
|
||||
* is deleted.
|
||||
*/
|
||||
|
||||
internal static bool CheckIfMasterPasscodeIsAvailable(string desktopPasswd, string fileName)
|
||||
{
|
||||
return (File.Exists(fileName));
|
||||
}
|
||||
|
||||
internal static byte[] GetMasterPasscode(string desktopPasswd, string fileName)
|
||||
{
|
||||
byte[] mp = DecryptMasterPasscodeUsingString(desktopPasswd, fileName);
|
||||
return mp;
|
||||
}
|
||||
|
||||
/* TBD - There must be a way, where we establish the integrity of
|
||||
* the files where we store the keys and master passcode.
|
||||
* Use a marker ?
|
||||
*/
|
||||
|
||||
// Used to save the MasterPasscode encrypted with Desktop login, etc
|
||||
internal static void EncryptAndStoreMasterPasscodeUsingString(
|
||||
byte[] baMasterPasscode,
|
||||
string passwd,
|
||||
string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
byte[] baKey = Generate16ByteKeyFromString(passwd);
|
||||
|
||||
|
||||
//Get an encryptor.
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform encryptor;
|
||||
encryptor = myRijndael.CreateEncryptor(baKey, baKey);
|
||||
|
||||
//Encrypt the data to a file
|
||||
FileStream fsEncrypt = new FileStream(fileName,FileMode.Create);
|
||||
CryptoStream csEncrypt = new CryptoStream(fsEncrypt, encryptor,
|
||||
CryptoStreamMode.Write);
|
||||
|
||||
//Write all data to the crypto stream and flush it.
|
||||
|
||||
csEncrypt.Write(baMasterPasscode, 0, baMasterPasscode.Length);
|
||||
csEncrypt.FlushFinalBlock();
|
||||
fsEncrypt.Close();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
}
|
||||
}
|
||||
public static byte[] DecryptMasterPasscodeUsingString(string passwd,
|
||||
string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] baKey = Generate16ByteKeyFromString(passwd);
|
||||
|
||||
/* Get a decryptor that uses the same key and
|
||||
* IV as the encryptor.
|
||||
*/
|
||||
RijndaelManaged myRijndael = new RijndaelManaged();
|
||||
ICryptoTransform decryptor = myRijndael.CreateDecryptor(baKey,
|
||||
baKey);
|
||||
//Now decrypt
|
||||
FileStream fsDecrypt = new FileStream(fileName, FileMode.Open);
|
||||
CryptoStream csDecrypt = new CryptoStream(fsDecrypt, decryptor,
|
||||
CryptoStreamMode.Read);
|
||||
byte[] baSavedMasterPasscode = new byte[16];
|
||||
|
||||
//Read the data out of the crypto stream.
|
||||
csDecrypt.Read(baSavedMasterPasscode, 0, 16);
|
||||
fsDecrypt.Close();
|
||||
|
||||
return baSavedMasterPasscode;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Unable to decrypt master passode");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static byte[] GetMasterPasscodeUsingMasterPasswd(
|
||||
string mPasswd,
|
||||
string fileName)
|
||||
{
|
||||
byte[] baMasterPasscode;
|
||||
try
|
||||
{
|
||||
if(File.Exists(fileName))
|
||||
{
|
||||
/* Decrypt the passcode from the file using master passwd.
|
||||
* and return the decrypted passcode.
|
||||
*/
|
||||
baMasterPasscode = DecryptMasterPasscodeUsingString(mPasswd,
|
||||
fileName);
|
||||
return baMasterPasscode;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Failed to get master passcode from master password.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static byte[] GetMasterPasscodeUsingDesktopPasswd(
|
||||
string desktopPasswd,
|
||||
string fileName)
|
||||
{
|
||||
byte[] passcode;
|
||||
try
|
||||
{
|
||||
if(File.Exists(fileName))
|
||||
{
|
||||
/* Decrypt the passcode from the file using desktop passwd.
|
||||
* and return the decrypted passcode.
|
||||
*/
|
||||
passcode = DecryptMasterPasscodeUsingString(desktopPasswd,
|
||||
fileName);
|
||||
return passcode;
|
||||
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Failed to get master passcode using desktop passwd");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//internal static string GenerateMasterPasscodeUsingDesktopPasswd(
|
||||
internal static byte[] GenerateMasterPasscodeUsingString(
|
||||
string desktopPasswd,
|
||||
string fileName,
|
||||
string validationFile,
|
||||
UserIdentifier userId
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Generate passcode using desktop passwd and store
|
||||
* it in the passwd file encrypted with the desktop passwd.
|
||||
* Encrypt a well-known with the passcode and store it.
|
||||
* Return the generated passcode.
|
||||
*/
|
||||
Random random = new Random(desktopPasswd.GetHashCode());
|
||||
int randNum = random.Next();
|
||||
string randStr = randNum.ToString() + userId.GetUID().ToString();
|
||||
byte[] baPasscode = Generate16ByteKeyFromString(randStr);
|
||||
|
||||
EncryptAndStoreMasterPasscodeUsingString(baPasscode,
|
||||
desktopPasswd,
|
||||
fileName);
|
||||
EncryptDataAndWriteToFile(
|
||||
Encoding.Default.GetBytes(
|
||||
ConstStrings.MICASA_VALIDATION_STRING),
|
||||
baPasscode,
|
||||
validationFile);
|
||||
return baPasscode;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Generation of master passcode failed.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool ValidatePasscode(byte[] baPasscode, string fileName)
|
||||
{
|
||||
/* Here we decrpyt a well known string, throw exception
|
||||
* if not successful
|
||||
* A well-known string is encrpyted by the Passcode and saved
|
||||
*/
|
||||
|
||||
if ((baPasscode == null) || baPasscode.Length < 1 )
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] baString = ReadFileAndDecryptData(baPasscode, fileName);
|
||||
string sString = Encoding.Default.GetString(baString);
|
||||
char[] trimChars = {'\0'};
|
||||
sString = sString.TrimEnd(trimChars);
|
||||
if( ConstStrings.MICASA_VALIDATION_STRING.Equals(sString))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Validation of passcode failed.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
396
c_micasad/lss/LocalStorage.cs
Normal file
396
c_micasad/lss/LocalStorage.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
using System.Security.Cryptography;
|
||||
using System.Xml;
|
||||
using sscs.cache;
|
||||
using sscs.crypto;
|
||||
using sscs.common;
|
||||
using sscs.constants;
|
||||
using Novell.CASA.MiCasa.Common;
|
||||
|
||||
namespace sscs.lss
|
||||
{
|
||||
/// <summary>
|
||||
/*
|
||||
* This class is a service to store data persistently.
|
||||
* How it does this is determined by implementation within the
|
||||
* private methods (File system using file(s), database, etc)
|
||||
* The MasterPasscode can be used to generate the key for
|
||||
* encyption and decryption.
|
||||
* If encrpytion is used, the private methods will also manage
|
||||
* how the encyption key is to be stored and retrieved.
|
||||
* Each piece of data is located by a DataID.
|
||||
* This might be an individual credentail or
|
||||
* a complete store.
|
||||
*/
|
||||
|
||||
/* We might not need this as a separate class.
|
||||
* Depending on the db changes, we can change this later.
|
||||
*/
|
||||
|
||||
/// </summary>
|
||||
public class LocalStorage
|
||||
{
|
||||
private byte[] m_baGeneratedKey = null;
|
||||
private SecretStore userStore = null;
|
||||
|
||||
private int persistThreadSleepTime = 1000 * 60 * 5; //1000 * 30;
|
||||
private Thread persistThread = null;
|
||||
|
||||
private static string LINUXID = "Unix";
|
||||
|
||||
internal LocalStorage(SecretStore store,byte[] baMasterPasscode)
|
||||
{
|
||||
userStore = store;
|
||||
m_baGeneratedKey = baMasterPasscode;
|
||||
LoadPersistentStore();
|
||||
userStore.DumpSecretstore();
|
||||
persistThread = new Thread(new ThreadStart(PersistStoreThreadFn));
|
||||
persistThread.Start();
|
||||
}
|
||||
~LocalStorage()
|
||||
{
|
||||
if(persistThread != null)
|
||||
{
|
||||
persistThread.Abort();
|
||||
persistThread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
// allowing a user to choose the storage location is not approved yet
|
||||
private LocalStorage(SecretStore store,
|
||||
byte[] baMasterPasscode, string sStorageDirectory)
|
||||
{
|
||||
userStore = store;
|
||||
m_baGeneratedKey = baMasterPasscode;
|
||||
LoadPersistentStore();
|
||||
userStore.DumpSecretstore();
|
||||
persistThread = new Thread(new ThreadStart(PersistStoreThreadFn));
|
||||
persistThread.Start();
|
||||
}
|
||||
|
||||
public void StorePersistentData(string sDataID, byte[] baData)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public byte[] RetrievePersistentData(string sDataID)
|
||||
{
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool StopPersistence()
|
||||
{
|
||||
if(persistThread != null)
|
||||
{
|
||||
persistThread.Abort();
|
||||
persistThread.Join();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private string GetDecryptedXml()
|
||||
{
|
||||
try
|
||||
{
|
||||
string fileName = userStore.GetPersistenceFilePath();
|
||||
if(!File.Exists(fileName))
|
||||
return null;
|
||||
|
||||
byte[] baPasscode = CASACrypto.GetMasterPasscode(userStore.GetDesktopPasswd(),userStore.GetPasscodeByDesktopFilePath());
|
||||
if( null == baPasscode )
|
||||
return null;
|
||||
|
||||
byte[] key = CASACrypto.GetKeySetFromFile(baPasscode,userStore.GetKeyFilePath());
|
||||
if( null == key )
|
||||
return null;
|
||||
|
||||
byte[] decryptedBuffer = CASACrypto.ReadFileAndDecryptData(key,fileName);
|
||||
|
||||
if( null == decryptedBuffer )
|
||||
return null;
|
||||
|
||||
char[] chArr = new char[decryptedBuffer.Length];
|
||||
for(int z = 0; z < decryptedBuffer.Length; z++ )
|
||||
{
|
||||
chArr[z] = (char)decryptedBuffer[z];
|
||||
}
|
||||
string toReturn = new string(chArr);
|
||||
return toReturn;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
CSSSLogger.DbgLog("Unable to get persistent store");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/* This method, uses the key to decrypt the persistent store
|
||||
* and populates userStore with the persistent data.
|
||||
*/
|
||||
private bool LoadPersistentStore()
|
||||
{
|
||||
try
|
||||
{
|
||||
string xpath = "";
|
||||
XmlDocument doc = new XmlDocument();
|
||||
|
||||
string xmlToLoad = GetDecryptedXml();
|
||||
if(xmlToLoad != null)
|
||||
{
|
||||
doc.LoadXml(xmlToLoad);
|
||||
|
||||
#if false
|
||||
XmlTextWriter writer = new XmlTextWriter("/home/poorna/.miCASA.xml",null);
|
||||
writer.Formatting = Formatting.Indented;
|
||||
doc.Save(writer);
|
||||
writer.Close();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
xpath = "//" + XmlConsts.miCASANode;
|
||||
XmlNode miCASANode = doc.SelectSingleNode(xpath);
|
||||
if(miCASANode != null)
|
||||
{
|
||||
xpath = "descendant::" + XmlConsts.keyChainNode;
|
||||
XmlNodeList keyChainNodeList = miCASANode.SelectNodes(xpath);
|
||||
foreach(XmlNode node in keyChainNodeList)
|
||||
{
|
||||
XmlAttributeCollection attrColl = node.Attributes;
|
||||
string keyChainId = (attrColl[XmlConsts.idAttr]).Value + "\0";
|
||||
KeyChain keyChain = null;
|
||||
|
||||
if( userStore.CheckIfKeyChainExists(keyChainId) == false )
|
||||
{
|
||||
keyChain = new KeyChain(keyChainId);
|
||||
userStore.AddKeyChain(keyChain);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyChain = userStore.GetKeyChain(keyChainId);
|
||||
}
|
||||
xpath = "descendant::" + XmlConsts.secretNode;
|
||||
XmlNodeList secretNodeList = node.SelectNodes(xpath);
|
||||
foreach(XmlNode secretNode in secretNodeList)
|
||||
{
|
||||
attrColl = secretNode.Attributes;
|
||||
string secretId = (attrColl[XmlConsts.idAttr]).Value + "\0";
|
||||
xpath = "descendant::" + XmlConsts.valueNode;
|
||||
Secret secret = new Secret(secretId);
|
||||
if( keyChain.CheckIfSecretExists(secretId) == false)
|
||||
{
|
||||
keyChain.AddSecret(secret);
|
||||
XmlNode secretValNode = (secretNode.SelectSingleNode(xpath));
|
||||
xpath = "descendant::" + XmlConsts.keyNode;
|
||||
|
||||
XmlNodeList keyNodeList = secretValNode.SelectNodes(xpath);
|
||||
|
||||
secret = keyChain.GetSecret(secretId);
|
||||
foreach(XmlNode keyNode in keyNodeList)
|
||||
{
|
||||
attrColl = keyNode.Attributes;
|
||||
string key;
|
||||
try
|
||||
{
|
||||
key = (attrColl[XmlConsts.idAttr]).Value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// LinkedKey node, continue
|
||||
continue;
|
||||
}
|
||||
xpath = "descendant::" + XmlConsts.keyValueNode;
|
||||
XmlNode keyValNode = keyNode.SelectSingleNode(xpath);
|
||||
string keyValue = keyValNode.InnerText;
|
||||
secret.SetKeyValue(key,keyValue);
|
||||
|
||||
|
||||
// add linked keys
|
||||
xpath = "descendant::" + XmlConsts.linkedKeyNode;
|
||||
XmlNodeList linkNodeList = keyNode.SelectNodes(xpath);
|
||||
foreach(XmlNode linkNode in linkNodeList)
|
||||
{
|
||||
// get TargetSecretID
|
||||
xpath = "descendant::" + XmlConsts.linkedTargetSecretNode;
|
||||
XmlNode targetSecretNode = linkNode.SelectSingleNode(xpath);
|
||||
string sSecretID = targetSecretNode.InnerText + "\0";
|
||||
|
||||
// get TargetSecretKey
|
||||
xpath = "descendant::" + XmlConsts.linkedTargetKeyNode;
|
||||
XmlNode targetKeyNode = linkNode.SelectSingleNode(xpath);
|
||||
string sKeyID = targetKeyNode.InnerText;
|
||||
|
||||
LinkedKeyInfo lki = new LinkedKeyInfo(sSecretID, sKeyID);
|
||||
KeyValue kv = secret.GetKeyValue(key);
|
||||
kv.AddLink(lki);
|
||||
}
|
||||
|
||||
}
|
||||
}//if ends
|
||||
}
|
||||
|
||||
}//end of traversing keyChainNodeList
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void PersistStoreThreadFn()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
Thread.Sleep(persistThreadSleepTime);
|
||||
PersistStore();
|
||||
}
|
||||
}
|
||||
|
||||
/* Persists the store to an xml file.
|
||||
* TBD : Would we require any form of encoding?
|
||||
*/
|
||||
|
||||
internal void PersistStore()
|
||||
{
|
||||
// userStore.DumpSecretstore();
|
||||
try
|
||||
{
|
||||
string fileName = userStore.GetPersistenceFilePath();
|
||||
|
||||
if(File.Exists(fileName))
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
|
||||
MemoryStream ms1 = new MemoryStream();
|
||||
XmlTextWriter writer = new XmlTextWriter(ms1,null);
|
||||
writer.Formatting = Formatting.Indented;
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement(XmlConsts.miCASANode);
|
||||
writer.WriteAttributeString(XmlConsts.versionAttr,"1.5");
|
||||
|
||||
{
|
||||
IDictionaryEnumerator iter = (IDictionaryEnumerator)userStore.GetKeyChainEnumerator();
|
||||
char [] tmpId;
|
||||
string sTmpId;
|
||||
while( iter.MoveNext() )
|
||||
{
|
||||
KeyChain kc = (KeyChain)iter.Value;
|
||||
writer.WriteStartElement(XmlConsts.keyChainNode);
|
||||
string kcId = kc.GetKey();
|
||||
tmpId = new char[kcId.Length-1];
|
||||
for(int i = 0; i < kcId.Length-1; i++ )
|
||||
tmpId[i] = kcId[i];
|
||||
sTmpId = new string(tmpId);
|
||||
|
||||
writer.WriteAttributeString(XmlConsts.idAttr,sTmpId);
|
||||
/* If we need to store time
|
||||
writer.WriteStartElement(XmlConsts.timeNode);
|
||||
writer.WriteAttributeString(XmlConsts.createdTimeNode,kc.CreatedTime.ToString());
|
||||
writer.WriteAttributeString(XmlConsts.modifiedTimeNode,kc.ModifiedTime.ToString());
|
||||
writer.WriteEndElement();
|
||||
*/
|
||||
|
||||
IDictionaryEnumerator secIter = (IDictionaryEnumerator)(kc.GetAllSecrets());
|
||||
while(secIter.MoveNext())
|
||||
{
|
||||
Secret secret = (Secret)secIter.Value;
|
||||
writer.WriteStartElement(XmlConsts.secretNode);
|
||||
string secretId = secret.GetKey();
|
||||
tmpId = new char[secretId.Length-1];
|
||||
for(int i = 0; i < secretId.Length-1; i++ )
|
||||
tmpId[i] = secretId[i];
|
||||
sTmpId = new string(tmpId);
|
||||
|
||||
writer.WriteAttributeString(XmlConsts.idAttr,sTmpId);
|
||||
/* If we need to store time
|
||||
writer.WriteStartElement(XmlConsts.timeNode);
|
||||
writer.WriteAttributeString(XmlConsts.createdTimeNode,secret.CreatedTime.ToString());
|
||||
writer.WriteAttributeString(XmlConsts.modifiedTimeNode,secret.ModifiedTime.ToString());
|
||||
writer.WriteEndElement();
|
||||
*/
|
||||
|
||||
writer.WriteStartElement(XmlConsts.valueNode);
|
||||
// byte[] byteArr = secret.GetValue();
|
||||
|
||||
IDictionaryEnumerator etor = (IDictionaryEnumerator)secret.GetKeyValueEnumerator();
|
||||
while(etor.MoveNext())
|
||||
{
|
||||
string sKey = (string)etor.Key;
|
||||
string value = secret.GetKeyValue(sKey).GetValue();
|
||||
writer.WriteStartElement(XmlConsts.keyNode);
|
||||
writer.WriteAttributeString(XmlConsts.idAttr, sKey);
|
||||
writer.WriteStartElement(XmlConsts.keyValueNode);
|
||||
writer.WriteString(value);
|
||||
writer.WriteEndElement();
|
||||
/* If we need to store time
|
||||
writer.WriteStartElement(XmlConsts.timeNode);
|
||||
writer.WriteAttributeString(XmlConsts.createdTimeNode,(secret.GetKeyValueCreatedTime(sKey)).ToString());
|
||||
writer.WriteAttributeString(XmlConsts.modifiedTimeNode,(secret.GetKeyValueModifiedTime(sKey)).ToString());
|
||||
writer.WriteEndElement();
|
||||
*/
|
||||
// write all LinkKeys
|
||||
Hashtable htLinkedKeys = secret.GetLinkedKeys(sKey);
|
||||
if (htLinkedKeys != null)
|
||||
{
|
||||
IDictionaryEnumerator etorLinked = (IDictionaryEnumerator)htLinkedKeys.GetEnumerator();
|
||||
while(etorLinked.MoveNext())
|
||||
{
|
||||
LinkedKeyInfo lki = (LinkedKeyInfo)etorLinked.Value;
|
||||
writer.WriteStartElement(XmlConsts.linkedKeyNode);
|
||||
|
||||
writer.WriteStartElement(XmlConsts.linkedTargetSecretNode);
|
||||
writer.WriteString(lki.GetLinkedSecretID().Substring(0, lki.GetLinkedSecretID().Length-1));
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteStartElement(XmlConsts.linkedTargetKeyNode);
|
||||
writer.WriteString(lki.GetLinkedKeyID());
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
/*
|
||||
char[] chArr = new char[byteArr.Length];
|
||||
for(int z = 0; z < byteArr.Length; z++)
|
||||
chArr[z] = (char)byteArr[z];
|
||||
|
||||
string stringToStore = new string(chArr);
|
||||
writer.WriteString(stringToStore);
|
||||
*/
|
||||
|
||||
writer.WriteEndElement(); //end of value node
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
writer.WriteEndElement(); //keychain
|
||||
}
|
||||
}
|
||||
writer.WriteEndElement(); //miCASA node
|
||||
writer.WriteEndDocument();
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
|
||||
byte[] key = CASACrypto.GetKeySetFromFile(CASACrypto.GetMasterPasscode(userStore.GetDesktopPasswd(),userStore.GetPasscodeByDesktopFilePath()),userStore.GetKeyFilePath());
|
||||
CASACrypto.EncryptDataAndWriteToFile(ms1.ToArray(),key,fileName);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
CSSSLogger.ExpLog(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user