Fix for defect 242393 (section 4.2.1 of security audit report) - This

fix makes the .miCASA* files to be owned by the user instead of root.
This commit is contained in:
Rajasekaran Nagarajan 2007-07-10 13:43:22 +00:00
parent f3105f7d76
commit 810c767431
7 changed files with 1742 additions and 1520 deletions

View File

@ -70,6 +70,7 @@ CSFILES=$(srcdir)/AssemblyInfo.cs \
$(srcdir)/common/UnixUserIdentifier.cs \ $(srcdir)/common/UnixUserIdentifier.cs \
$(srcdir)/common/Constants.cs \ $(srcdir)/common/Constants.cs \
$(srcdir)/common/CSSSLogger.cs \ $(srcdir)/common/CSSSLogger.cs \
$(srcdir)/common/CSSSUtils.cs \
$(srcdir)/common/CSSSException.cs \ $(srcdir)/common/CSSSException.cs \
$(srcdir)/communication/IPCChannel.cs \ $(srcdir)/communication/IPCChannel.cs \
$(srcdir)/communication/CommunicationFactory.cs \ $(srcdir)/communication/CommunicationFactory.cs \

View File

@ -1,169 +1,174 @@
using System; using System;
using System.IO; using System.IO;
using sscs.common; using sscs.common;
namespace sscs.cache namespace sscs.cache
{ {
/// <summary> /// <summary>
/// Summary description for MPFileWatcher. /// Summary description for MPFileWatcher.
/// </summary> /// </summary>
public class MPFileWatcher class MPFileWatcher
{ {
FileSystemWatcher fwatcher; FileSystemWatcher fwatcher;
private string m_dir = null; private string m_dir = null;
private string m_filename = null; private string m_filename = null;
private byte[] m_baMP = new byte[32]; private byte[] m_baMP = new byte[32];
private byte[] m_baMPIV = new byte[32]; private byte[] m_baMPIV = new byte[32];
private byte[] m_baMPSalt = null; private byte[] m_baMPSalt = null;
private bool m_bIgnoreFileDeletes = false; private bool m_bIgnoreFileDeletes = false;
private SecretStore m_store = null;
public MPFileWatcher(string MPFilePath, string MPFileName)
{ public MPFileWatcher(SecretStore store, string MPFilePath, string MPFileName)
m_dir = MPFilePath; {
m_filename = MPFileName; m_store = store;
m_dir = MPFilePath;
if ((MPFilePath != null) && (MPFileName != null)) m_filename = MPFileName;
{
LogMessage("Starting MPFile watcher on " + MPFilePath + "/" + MPFileName.Substring(1)); if ((MPFilePath != null) && (MPFileName != null))
fwatcher = new FileSystemWatcher(MPFilePath); {
fwatcher.Filter = MPFileName.Substring(1)+"*"; LogMessage("Starting MPFile watcher on " + MPFilePath + "/" + MPFileName.Substring(1));
fwatcher.Deleted += new FileSystemEventHandler(fwatcher_Deleted); fwatcher = new FileSystemWatcher(MPFilePath);
fwatcher.Renamed += new RenamedEventHandler(fwatcher_Renamed); fwatcher.Filter = MPFileName.Substring(1)+"*";
fwatcher.Changed += new FileSystemEventHandler(fwatcher_Changed); fwatcher.Deleted += new FileSystemEventHandler(fwatcher_Deleted);
fwatcher.EnableRaisingEvents = true; fwatcher.Renamed += new RenamedEventHandler(fwatcher_Renamed);
} fwatcher.Changed += new FileSystemEventHandler(fwatcher_Changed);
fwatcher.EnableRaisingEvents = true;
if (File.Exists(MPFilePath + MPFileName)) }
{
LoadAndCacheMPFiles(); if (File.Exists(MPFilePath + MPFileName))
} {
} LoadAndCacheMPFiles();
}
~MPFileWatcher() }
{
if (fwatcher != null) ~MPFileWatcher()
fwatcher.EnableRaisingEvents = false; {
fwatcher = null; if (fwatcher != null)
} fwatcher.EnableRaisingEvents = false;
internal void pauseWatcher() fwatcher = null;
{ }
m_bIgnoreFileDeletes = true; internal void pauseWatcher()
} {
m_bIgnoreFileDeletes = true;
internal void resumeWatcher() }
{
m_bIgnoreFileDeletes = false; internal void resumeWatcher()
} {
m_bIgnoreFileDeletes = false;
private void fwatcher_Deleted(object sender, FileSystemEventArgs e) }
{
if (!m_bIgnoreFileDeletes) private void fwatcher_Deleted(object sender, FileSystemEventArgs e)
{ {
LogMessage("MP file deleted"); if (!m_bIgnoreFileDeletes)
ReWriteFiles(); {
} LogMessage("MP file deleted");
} ReWriteFiles();
}
private void fwatcher_Changed(object sender, FileSystemEventArgs e) }
{
LogMessage("MP file Changed"); private void fwatcher_Changed(object sender, FileSystemEventArgs e)
LoadAndCacheMPFiles(); {
} LogMessage("MP file Changed");
LoadAndCacheMPFiles();
private void fwatcher_Renamed(object sender, RenamedEventArgs e) }
{
LogMessage("MP file renamed"); private void fwatcher_Renamed(object sender, RenamedEventArgs e)
fwatcher_Deleted(sender, e); {
} LogMessage("MP file renamed");
fwatcher_Deleted(sender, e);
private void LoadAndCacheMPFiles() }
{
LogMessage("Loading and caching MP files"); private void LoadAndCacheMPFiles()
{
try LogMessage("Loading and caching MP files");
{
FileStream fs = new FileStream(m_dir + m_filename, FileMode.Open, FileAccess.Read); try
fs.Read(m_baMP, 0, m_baMP.Length); {
fs.Flush(); FileStream fs = new FileStream(m_dir + m_filename, FileMode.Open, FileAccess.Read);
fs.Close(); fs.Read(m_baMP, 0, m_baMP.Length);
fs.Flush();
fs = new FileStream(m_dir + m_filename + ".IV", FileMode.Open, FileAccess.Read); fs.Close();
fs.Read(m_baMPIV, 0, m_baMPIV.Length);
fs.Flush(); fs = new FileStream(m_dir + m_filename + ".IV", FileMode.Open, FileAccess.Read);
fs.Close(); fs.Read(m_baMPIV, 0, m_baMPIV.Length);
fs.Flush();
if (File.Exists(m_dir + m_filename + ".salt")) fs.Close();
{
m_baMPSalt = new byte[64]; if (File.Exists(m_dir + m_filename + ".salt"))
fs = new FileStream(m_dir + m_filename + ".salt", FileMode.Open, FileAccess.Read); {
fs.Read(m_baMPSalt, 0, m_baMPSalt.Length); m_baMPSalt = new byte[64];
fs.Flush(); fs = new FileStream(m_dir + m_filename + ".salt", FileMode.Open, FileAccess.Read);
fs.Close(); fs.Read(m_baMPSalt, 0, m_baMPSalt.Length);
} fs.Flush();
fs.Close();
} }
catch (Exception e) }
{
LogMessage(e.ToString()); catch (Exception e)
} {
} LogMessage(e.ToString());
}
private void ReWriteFiles() }
{
try private void ReWriteFiles()
{ {
FileStream fs = new FileStream(m_dir + m_filename, FileMode.Create); try
fs.Write(m_baMP, 0, m_baMP.Length); {
fs.Flush(); FileStream fs = new FileStream(m_dir + m_filename, FileMode.Create);
fs.Close(); fs.Write(m_baMP, 0, m_baMP.Length);
fs.Flush();
File.SetAttributes(m_dir + m_filename, FileAttributes.Hidden); fs.Close();
}
catch (Exception e) File.SetAttributes(m_dir + m_filename, FileAttributes.Hidden);
{ CSSSUtils.SetSocketUserAsOwner(m_dir + m_filename, m_store.user.UserIdentifier);
LogMessage(e.ToString()); }
} catch (Exception e)
{
try LogMessage(e.ToString());
{ }
FileStream fs = new FileStream(m_dir + m_filename + ".IV", FileMode.Create);
fs.Write(m_baMPIV, 0, m_baMPIV.Length); try
fs.Flush(); {
fs.Close(); FileStream fs = new FileStream(m_dir + m_filename + ".IV", FileMode.Create);
fs.Write(m_baMPIV, 0, m_baMPIV.Length);
File.SetAttributes(m_dir + m_filename + ".IV", FileAttributes.Hidden); fs.Flush();
} fs.Close();
catch (Exception e)
{ File.SetAttributes(m_dir + m_filename + ".IV", FileAttributes.Hidden);
LogMessage(e.ToString()); CSSSUtils.SetSocketUserAsOwner(m_dir + m_filename + ".IV", m_store.user.UserIdentifier);
} }
catch (Exception e)
{
if (m_baMPSalt != null) LogMessage(e.ToString());
{ }
try
{
FileStream fs = new FileStream(m_dir + m_filename + ".salt", FileMode.Create); if (m_baMPSalt != null)
fs.Write(m_baMPSalt, 0, m_baMPSalt.Length); {
fs.Flush(); try
fs.Close(); {
FileStream fs = new FileStream(m_dir + m_filename + ".salt", FileMode.Create);
File.SetAttributes(m_dir + m_filename + ".salt", FileAttributes.Hidden); fs.Write(m_baMPSalt, 0, m_baMPSalt.Length);
} fs.Flush();
catch (Exception e) fs.Close();
{
LogMessage(e.ToString()); File.SetAttributes(m_dir + m_filename + ".salt", FileAttributes.Hidden);
} CSSSUtils.SetSocketUserAsOwner(m_dir + m_filename + ".salt", m_store.user.UserIdentifier);
} }
catch (Exception e)
} {
LogMessage(e.ToString());
private void LogMessage(string message) }
{ }
// Console.WriteLine(message);
CSSSLogger.DbgLog("MPFileWatcher:" + message); }
}
} private void LogMessage(string message)
} {
// Console.WriteLine(message);
CSSSLogger.DbgLog("MPFileWatcher:" + message);
}
}
}

View File

@ -116,7 +116,7 @@ namespace sscs.cache
String sPersistentDir = GetPersistenceDirectory(); String sPersistentDir = GetPersistenceDirectory();
if (sPersistentDir != null && sPersistentDir.Length > 0) if (sPersistentDir != null && sPersistentDir.Length > 0)
{ {
mpWatcher = new MPFileWatcher(GetPersistenceDirectory(), ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE); mpWatcher = new MPFileWatcher(this, GetPersistenceDirectory(), ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE);
} }
} }
} }
@ -176,16 +176,16 @@ namespace sscs.cache
{ {
try try
{ {
byte[] baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(sDesktopPassword, GetPasscodeByDesktopFilePath(), false); byte[] baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(sDesktopPassword, GetPasscodeByDesktopFilePath(), false, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
ReEncryptPasscodeUsingRandomSalt(baPasscode, sDesktopPassword, GetPasscodeByDesktopFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, sDesktopPassword, GetPasscodeByDesktopFilePath());
return true; return true;
} }
// try old salt // try old salt
baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(sDesktopPassword, GetPasscodeByDesktopFilePath(), true); baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(sDesktopPassword, GetPasscodeByDesktopFilePath(), true, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
ReEncryptPasscodeUsingRandomSalt(baPasscode, sDesktopPassword, GetPasscodeByDesktopFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, sDesktopPassword, GetPasscodeByDesktopFilePath());
return true; return true;
} }
@ -230,7 +230,8 @@ namespace sscs.cache
*/ */
baPasscode = CASACrypto.GenerateServerMasterPasscode( baPasscode = CASACrypto.GenerateServerMasterPasscode(
GetServerPasscodeBySystemKeyFilePath(), GetServerPasscodeBySystemKeyFilePath(),
GetServerValidationFilePath()); GetServerValidationFilePath(),
user.UserIdentifier);
if (null == baPasscode) if (null == baPasscode)
{ {
@ -246,8 +247,8 @@ namespace sscs.cache
} }
} }
baPasscode = CASACrypto.GetServerMasterPasscodeUsingSystemKey(GetServerPasscodeBySystemKeyFilePath()); baPasscode = CASACrypto.GetServerMasterPasscodeUsingSystemKey(GetServerPasscodeBySystemKeyFilePath(), user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetServerValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetServerValidationFilePath(), user.UserIdentifier))
{ {
slss = new LocalStorage(this, baPasscode, true); slss = new LocalStorage(this, baPasscode, true);
bIsServerStorePersistent = true; bIsServerStorePersistent = true;
@ -335,23 +336,23 @@ namespace sscs.cache
} }
} }
baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(desktopPasswd, GetPasscodeByDesktopFilePath(), false); baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(desktopPasswd, GetPasscodeByDesktopFilePath(), false, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
bIsStorePersistent = true; bIsStorePersistent = true;
ReEncryptPasscodeUsingRandomSalt(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath());
return true; return true;
} }
else else
{ {
// try old encryption method // try old encryption method
baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(desktopPasswd, GetPasscodeByDesktopFilePath(), true); baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(desktopPasswd, GetPasscodeByDesktopFilePath(), true, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
// rewrite file using new encryption // rewrite file using new encryption
ReEncryptPasscodeUsingRandomSalt(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath());
//CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath()); //CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath(), user.UserIdentifier);
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
bIsStorePersistent = true; bIsStorePersistent = true;
return true; return true;
@ -381,7 +382,7 @@ namespace sscs.cache
myRijndael.GenerateKey(); myRijndael.GenerateKey();
key = myRijndael.Key; key = myRijndael.Key;
CASACrypto.StoreKeySetUsingMasterPasscode(key, IV, baPasscode, fileName); CASACrypto.StoreKeySetUsingMasterPasscode(key, IV, baPasscode, fileName, user.UserIdentifier);
} }
catch (Exception) catch (Exception)
{ {
@ -410,10 +411,10 @@ namespace sscs.cache
*/ */
if (desktopPasswd != null) if (desktopPasswd != null)
{ {
baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(desktopPasswd, GetPasscodeByDesktopFilePath(), false); baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(desktopPasswd, GetPasscodeByDesktopFilePath(), false, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath(), user.UserIdentifier);
return true; return true;
} }
else else
@ -422,20 +423,23 @@ namespace sscs.cache
baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd( baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(
desktopPasswd, desktopPasswd,
GetPasscodeByDesktopFilePath(), GetPasscodeByDesktopFilePath(),
true); true,
user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
// rewrite file using new method // rewrite file using new method
CASACrypto.EncryptAndStoreMasterPasscodeUsingString( CASACrypto.EncryptAndStoreMasterPasscodeUsingString(
baPasscode, baPasscode,
desktopPasswd, desktopPasswd,
GetPasscodeByDesktopFilePath()); GetPasscodeByDesktopFilePath(),
user.UserIdentifier);
CASACrypto.EncryptAndStoreMasterPasscodeUsingString( CASACrypto.EncryptAndStoreMasterPasscodeUsingString(
baPasscode, baPasscode,
mPasswd, mPasswd,
GetPasscodeByMasterPasswdFilePath()); GetPasscodeByMasterPasswdFilePath(),
user.UserIdentifier);
return true; return true;
} }
else else
@ -447,8 +451,8 @@ namespace sscs.cache
baPasscode = CASACrypto.GenerateMasterPasscodeUsingString(mPasswd, GetPasscodeByMasterPasswdFilePath(), GetValidationFilePath(), user.UserIdentifier); baPasscode = CASACrypto.GenerateMasterPasscodeUsingString(mPasswd, GetPasscodeByMasterPasswdFilePath(), GetValidationFilePath(), user.UserIdentifier);
if (baPasscode != null) if (baPasscode != null)
{ {
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath(), user.UserIdentifier);
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath(), user.UserIdentifier);
if (File.Exists(GetPersistenceFilePath())) if (File.Exists(GetPersistenceFilePath()))
{ {
File.Delete(GetPersistenceFilePath()); File.Delete(GetPersistenceFilePath());
@ -493,7 +497,7 @@ namespace sscs.cache
GenerateAndStoreEncryptionKey(baPasscode, GetKeyFilePath()); GenerateAndStoreEncryptionKey(baPasscode, GetKeyFilePath());
} }
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath(), user.UserIdentifier);
if (bIsStorePersistent == false) if (bIsStorePersistent == false)
{ {
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
@ -514,12 +518,12 @@ namespace sscs.cache
//If validation succeeds,start persistence. //If validation succeeds,start persistence.
if (desktopPasswd == null) if (desktopPasswd == null)
{ {
baPasscode = CASACrypto.DecryptMasterPasscodeUsingString(mPasswd, GetPasscodeByMasterPasswdFilePath(), false); baPasscode = CASACrypto.DecryptMasterPasscodeUsingString(mPasswd, GetPasscodeByMasterPasswdFilePath(), false, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
if (bIsStorePersistent == false) if (bIsStorePersistent == false)
{ {
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
ReEncryptPasscodeUsingRandomSalt(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath());
bIsStorePersistent = true; bIsStorePersistent = true;
} }
@ -528,11 +532,11 @@ namespace sscs.cache
else else
{ {
// try validation, if it fails, try decryption using the old method // try validation, if it fails, try decryption using the old method
baPasscode = CASACrypto.DecryptMasterPasscodeUsingString(mPasswd, GetPasscodeByMasterPasswdFilePath(), true); baPasscode = CASACrypto.DecryptMasterPasscodeUsingString(mPasswd, GetPasscodeByMasterPasswdFilePath(), true, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
// rewrite file // rewrite file
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath(), user.UserIdentifier);
if (bIsStorePersistent == false) if (bIsStorePersistent == false)
{ {
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
@ -549,13 +553,13 @@ namespace sscs.cache
else else
{ //There are 2 cases - either desktop passwd has changed { //There are 2 cases - either desktop passwd has changed
//or it hasnt. //or it hasnt.
baPasscode = CASACrypto.GetMasterPasscodeUsingMasterPasswd(mPasswd, GetPasscodeByMasterPasswdFilePath(), false); baPasscode = CASACrypto.GetMasterPasscodeUsingMasterPasswd(mPasswd, GetPasscodeByMasterPasswdFilePath(), false, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
RewriteDesktopPasswdFile(baPasscode, desktopPasswd); RewriteDesktopPasswdFile(baPasscode, desktopPasswd);
if (bIsStorePersistent == false) if (bIsStorePersistent == false)
{ {
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
ReEncryptPasscodeUsingRandomSalt(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath());
bIsStorePersistent = true; bIsStorePersistent = true;
} }
@ -563,13 +567,13 @@ namespace sscs.cache
} }
else else
{ {
baPasscode = CASACrypto.GetMasterPasscodeUsingMasterPasswd(mPasswd, GetPasscodeByMasterPasswdFilePath(), true); baPasscode = CASACrypto.GetMasterPasscodeUsingMasterPasswd(mPasswd, GetPasscodeByMasterPasswdFilePath(), true, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
RewriteDesktopPasswdFile(baPasscode, desktopPasswd); RewriteDesktopPasswdFile(baPasscode, desktopPasswd);
if (bIsStorePersistent == false) if (bIsStorePersistent == false)
{ {
lss = new LocalStorage(this, baPasscode); lss = new LocalStorage(this, baPasscode);
ReEncryptPasscodeUsingRandomSalt(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, mPasswd, GetPasscodeByMasterPasswdFilePath());
bIsStorePersistent = true; bIsStorePersistent = true;
} }
@ -592,7 +596,7 @@ namespace sscs.cache
{ {
try try
{ {
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, desktopPasswd, GetPasscodeByDesktopFilePath(), user.UserIdentifier);
CSSSLogger.DbgLog("Re-encryted passcode with desktop passwd"); CSSSLogger.DbgLog("Re-encryted passcode with desktop passwd");
} }
catch (Exception e) catch (Exception e)
@ -606,20 +610,20 @@ namespace sscs.cache
{ {
try try
{ {
byte[] baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(oldDesktopPasswd, GetPasscodeByDesktopFilePath(), false); byte[] baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(oldDesktopPasswd, GetPasscodeByDesktopFilePath(), false, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
ReEncryptPasscodeUsingRandomSalt(baPasscode, oldDesktopPasswd, GetPasscodeByDesktopFilePath()); ReEncryptPasscodeUsingRandomSalt(baPasscode, oldDesktopPasswd, GetPasscodeByDesktopFilePath());
return baPasscode; return baPasscode;
} }
else else
{ {
// try old method // try old method
baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(oldDesktopPasswd, GetPasscodeByDesktopFilePath(), true); baPasscode = CASACrypto.GetMasterPasscodeUsingDesktopPasswd(oldDesktopPasswd, GetPasscodeByDesktopFilePath(), true, user.UserIdentifier);
if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath())) if (CASACrypto.ValidatePasscode(baPasscode, GetValidationFilePath(), user.UserIdentifier))
{ {
// rewrite file now // rewrite file now
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, oldDesktopPasswd, GetPasscodeByDesktopFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, oldDesktopPasswd, GetPasscodeByDesktopFilePath(), user.UserIdentifier);
return baPasscode; return baPasscode;
} }
@ -652,9 +656,9 @@ namespace sscs.cache
//Create a new key and initialization vector. //Create a new key and initialization vector.
myRijndael.GenerateKey(); myRijndael.GenerateKey();
key = myRijndael.Key; key = myRijndael.Key;
CASACrypto.StoreKeySetUsingMasterPasscode(key,IV,sMasterPasscode,GetKeyFilePath()); CASACrypto.StoreKeySetUsingMasterPasscode(key,IV,sMasterPasscode,GetKeyFilePath(), user.UserIdentifier);
//Store the master passcode encrypted with the desktopPasswd //Store the master passcode encrypted with the desktopPasswd
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(sMasterPasscode, desktopPasswd, GetPasswdFilePath()); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(sMasterPasscode, desktopPasswd, GetPasswdFilePath(), user.UserIdentifier);
lss = new LocalStorage(this,sMasterPasscode); lss = new LocalStorage(this,sMasterPasscode);
bIsStorePersistent = true; bIsStorePersistent = true;
bRet = true; bRet = true;
@ -857,11 +861,11 @@ namespace sscs.cache
internal bool ChangeMasterPassword(string sCurrentPWD, string sNewPWD) internal bool ChangeMasterPassword(string sCurrentPWD, string sNewPWD)
{ {
string sMasterFilePath = GetPasscodeByMasterPasswdFilePath(); string sMasterFilePath = GetPasscodeByMasterPasswdFilePath();
byte[] baPasscode = CASACrypto.GetMasterPasscodeUsingMasterPasswd(sCurrentPWD, sMasterFilePath, false); byte[] baPasscode = CASACrypto.GetMasterPasscodeUsingMasterPasswd(sCurrentPWD, sMasterFilePath, false, user.UserIdentifier);
if (baPasscode != null) if (baPasscode != null)
{ {
PauseFileWatcher(); PauseFileWatcher();
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, sNewPWD, sMasterFilePath); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, sNewPWD, sMasterFilePath, user.UserIdentifier);
ResumeFileWatcher(); ResumeFileWatcher();
return true; return true;
} }
@ -907,6 +911,11 @@ namespace sscs.cache
return user.GetUserName(); return user.GetUserName();
} }
internal UserIdentifier GetUserIdentifier()
{
return user.UserIdentifier;
}
internal string GetPersistenceDirectory() internal string GetPersistenceDirectory()
{ {
if (m_persistenceDirectory != null) if (m_persistenceDirectory != null)
@ -917,53 +926,62 @@ namespace sscs.cache
return null; return null;
} }
else else
{ {
string sUserHomeDir = GetUserHomeDirectory(); string sUserHomeDir = GetUserHomeDirectory();
if (sUserHomeDir != null) if (sUserHomeDir != null)
{ {
// the user might have set a different one
// the user might have set a different one // load the policy file and check.
// load the policy file and check. UIPol uiPolicy = (UIPol)ICASAPol.GetPolicy(CASAPolType.UI_POL, sUserHomeDir, GetUserName());
UIPol uiPolicy = (UIPol)ICASAPol.GetPolicy(CASAPolType.UI_POL, sUserHomeDir, GetUserName()); if (uiPolicy != null)
if (uiPolicy != null) {
{ string sDir = uiPolicy.GetConfigSetting(ConstStrings.CONFIG_PERSISTENT_DIRECTORY);
string sDir = uiPolicy.GetConfigSetting(ConstStrings.CONFIG_PERSISTENT_DIRECTORY); if ((sDir != null) && (sDir.Length > 0))
if ((sDir != null) && (sDir.Length > 0)) {
{ m_persistenceDirectory = sDir;
m_persistenceDirectory = sDir; if (IsDirectoryOwnedByUser(sDir))
return m_persistenceDirectory; {
} ChangeFileOwnershipForMiCasaFiles(sDir);
} return m_persistenceDirectory;
} }
else else
{ {
// user not logged in yet CSSSLogger.log(true, "CASA Warning: " + GetUserName() + " has persistent directory set to " + sDir);
return null; return null;
}
}
}
}
else
{
// user not logged in yet
return null;
} }
} }
m_persistenceDirectory = MigrateMiCasaFiles(); m_persistenceDirectory = MigrateMiCasaFiles();
return m_persistenceDirectory; ChangeFileOwnershipForMiCasaFiles(null);
return m_persistenceDirectory;
} }
internal string MigrateMiCasaFiles() internal string MigrateMiCasaFiles()
{ {
string sSeperator = "/"; string sSeperator = "/";
#if LINUX #if LINUX
// for v1.7, we are storing MiCasa files in /home/.casa/[username] // for v1.7, we are storing MiCasa files in /home/.casa/[username]
// let's migrate the files if needed // let's migrate the files if needed
string sNewPath = POLICY_DIRECTORY + "/" + user.GetUserName(); string sNewPath = POLICY_DIRECTORY + "/" + user.GetUserName();
#else #else
string sNewPath = GetUserHomeDirectory() + "\\CASA"; string sNewPath = GetUserHomeDirectory() + "\\CASA";
System.Diagnostics.Trace.WriteLine("Migrate files to " + sNewPath); System.Diagnostics.Trace.WriteLine("Migrate files to " + sNewPath);
if (!Directory.Exists(sNewPath)) if (!Directory.Exists(sNewPath))
{ {
Directory.CreateDirectory(sNewPath); Directory.CreateDirectory(sNewPath);
} }
sSeperator = "\\"; sSeperator = "\\";
#endif #endif
try try
@ -991,6 +1009,48 @@ namespace sscs.cache
return (sNewPath); return (sNewPath);
} }
internal void ChangeFileOwnershipForMiCasaFiles(string sDir)
{
#if LINUX
string sSeperator = "/";
string sNewPath;
if (sDir != null)
{
sNewPath = sDir;
}
else
{
sNewPath = POLICY_DIRECTORY + "/" + user.GetUserName();
}
try
{
if (CSSSUtils.IsFileOwnedByRoot(sNewPath + sSeperator + ".miCASA"))
{
if(CSSSUtils.CompareSocketAndFileUserIds(sNewPath + sSeperator + ".miCASA", user.UserIdentifier))
return;
else
{
String[] miCASAFiles = Directory.GetFiles(sNewPath, ".miCASA*");
if ((miCASAFiles != null) && (miCASAFiles.Length > 0))
{
for (int i = 0; i < miCASAFiles.Length; i++)
{
string sFileName = miCASAFiles[i].Substring(miCASAFiles[i].LastIndexOf(sSeperator));
CSSSUtils.SetSocketUserAsOwner(sNewPath + sFileName, user.UserIdentifier);
}
}
}
}
}
catch (Exception e)
{
CSSSLogger.DbgLog(e.ToString());
}
#endif
}
internal bool SetPeristenceDirectory(string sNewDirectory) internal bool SetPeristenceDirectory(string sNewDirectory)
{ {
if (Directory.Exists(sNewDirectory)) if (Directory.Exists(sNewDirectory))
@ -999,11 +1059,12 @@ namespace sscs.cache
if (mpWatcher != null) if (mpWatcher != null)
{ {
mpWatcher.pauseWatcher(); mpWatcher.pauseWatcher();
mpWatcher = new MPFileWatcher(sNewDirectory, ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE); mpWatcher = new MPFileWatcher(this, sNewDirectory, ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE);
mpWatcher.resumeWatcher(); mpWatcher.resumeWatcher();
} }
m_persistenceDirectory = sNewDirectory; m_persistenceDirectory = sNewDirectory;
ChangeFileOwnershipForMiCasaFiles(m_persistenceDirectory);
return true; return true;
} }
@ -1097,7 +1158,7 @@ namespace sscs.cache
// encrypt if an encryptionstring was passed // encrypt if an encryptionstring was passed
if ((sEncryptionString != null) && (sEncryptionString.Length > 0)) if ((sEncryptionString != null) && (sEncryptionString.Length > 0))
{ {
byte[] baKey = sscs.crypto.CASACrypto.Generate16ByteKeyFromString(sEncryptionString, null, false, false); byte[] baKey = sscs.crypto.CASACrypto.Generate16ByteKeyFromString(sEncryptionString, null, false, false, user.UserIdentifier);
// now encypt it. // now encypt it.
baSecrets = sscs.crypto.CASACrypto.EncryptData(baSecrets, baKey, ref baIV); baSecrets = sscs.crypto.CASACrypto.EncryptData(baSecrets, baKey, ref baIV);
@ -1115,7 +1176,7 @@ namespace sscs.cache
if (sEncryptionString != null) if (sEncryptionString != null)
{ {
// decrypt the buffer using the string passed in. // decrypt the buffer using the string passed in.
byte[] baKey = sscs.crypto.CASACrypto.Generate16ByteKeyFromString(sEncryptionString, null, false, false); byte[] baKey = sscs.crypto.CASACrypto.Generate16ByteKeyFromString(sEncryptionString, null, false, false, user.UserIdentifier);
byte[] baBuffer = sscs.crypto.CASACrypto.DecryptData(encryptedXmlSecrets, baKey, baIV); byte[] baBuffer = sscs.crypto.CASACrypto.DecryptData(encryptedXmlSecrets, baKey, baIV);
MergeXMLSecrets(baBuffer); MergeXMLSecrets(baBuffer);
} }
@ -1127,14 +1188,14 @@ namespace sscs.cache
String sXMLData = Encoding.ASCII.GetString(decryptedXmlSecrets); String sXMLData = Encoding.ASCII.GetString(decryptedXmlSecrets);
doc.LoadXml(sXMLData); doc.LoadXml(sXMLData);
LocalStorage.AddXMLSecretsToStore(this, doc); LocalStorage.AddXMLSecretsToStore(this, doc);
} }
private void ReEncryptPasscodeUsingRandomSalt(byte[] baPasscode, string sPassword, string sFilepath) private void ReEncryptPasscodeUsingRandomSalt(byte[] baPasscode, string sPassword, string sFilepath)
{ {
if (!File.Exists(sFilepath + ".salt")) if (!File.Exists(sFilepath + ".salt"))
{ {
CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, sPassword, sFilepath); CASACrypto.EncryptAndStoreMasterPasscodeUsingString(baPasscode, sPassword, sFilepath, user.UserIdentifier);
} }
} }
internal void CreatePolicyDirectory() internal void CreatePolicyDirectory()

View File

@ -0,0 +1,162 @@
/***********************************************************************
*
* Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com.
*
***********************************************************************/
using System;
using System.IO;
using System.Text;
#if LINUX
using Mono.Unix;
using Mono.Unix.Native;
#endif
using sscs.common;
using sscs.constants;
namespace sscs.common
{
class CSSSUtils
{
public static bool IsFileOwnedByRoot(string filePath)
{
#if LINUX
try
{
int retVal = -1;
int fd = -1;
Stat fStatus;
fd = Syscall.open(filePath, OpenFlags.O_NOFOLLOW);
retVal = Syscall.fstat(fd, out fStatus);
if ( retVal < 0 )
{
CSSSLogger.DbgLog("fstat() failed...");
return false;
}
if(fStatus.st_uid != 0)
{
CSSSLogger.DbgLog("File not owned by root: {0}");
return false;
}
retVal = Syscall.close(fd);
if ( retVal < 0 )
{
CSSSLogger.DbgLog("close() failed...");
return false;
}
return true;
}
catch(Exception e)
{
CSSSLogger.ExpLog(e.ToString());
CSSSLogger.DbgLog("Failed while checking whether the file is owned by root or not");
}
return false;
#else
return true;
#endif
}
public static bool SetSocketUserAsOwner(string filePath, UserIdentifier userID)
{
#if LINUX
try
{
int retVal = -1;
int fd = -1;
fd = Syscall.open(filePath, OpenFlags.O_NOFOLLOW);
UnixUserInfo uui = new UnixUserInfo(userID.GetUID());
retVal = Syscall.fchown(fd, (uint) uui.UserId, (uint) uui.GroupId);
if ( retVal < 0 )
{
CSSSLogger.DbgLog("fchown() failed...");
return false;
}
retVal = Syscall.close(fd);
if ( retVal < 0 )
{
CSSSLogger.DbgLog("close() failed...");
return false;
}
return true;
}
catch(Exception e)
{
CSSSLogger.ExpLog(e.ToString());
CSSSLogger.DbgLog("Unable to set the owner of the file to the socket user");
}
return false;
#else
return true;
#endif
}
public static bool CompareSocketAndFileUserIds(string filePath, UserIdentifier userID)
{
#if LINUX
try
{
int retVal = -1;
int fd = -1;
Stat fStatus;
fd = Syscall.open(filePath, OpenFlags.O_NOFOLLOW);
retVal = Syscall.fstat(fd, out fStatus);
if ( retVal < 0 )
{
CSSSLogger.DbgLog("fstat() failed...");
return false;
}
if(fStatus.st_uid != userID.GetUID())
{
return false;
}
retVal = Syscall.close(fd);
if ( retVal < 0 )
{
CSSSLogger.DbgLog("close() failed...");
return false;
}
return true;
}
catch(Exception e)
{
CSSSLogger.ExpLog(e.ToString());
CSSSLogger.DbgLog("Failed during the comparision of the user ids on the file and socket");
}
return false;
#else
return true;
#endif
}
}
}

View File

@ -26,6 +26,7 @@ using System.Text;
using System.Security.Cryptography; using System.Security.Cryptography;
#if LINUX #if LINUX
using Mono.Unix; using Mono.Unix;
using Mono.Unix.Native;
#endif #endif
using sscs.common; using sscs.common;
using sscs.constants; using sscs.constants;
@ -40,12 +41,12 @@ namespace sscs.crypto
private const int HASH_SIZE = 32; private const int HASH_SIZE = 32;
private const uint MAX_FILE_SIZE = 16 * 1024 * 1024; //16 MB private const uint MAX_FILE_SIZE = 16 * 1024 * 1024; //16 MB
internal static byte[] Generate16ByteKeyFromString(string sTheString, string sFilepath, bool bUseOldMethod, bool bGenerateRandomSalt) internal static byte[] Generate16ByteKeyFromString(string sTheString, string sFilepath, bool bUseOldMethod, bool bGenerateRandomSalt, UserIdentifier userID)
{ {
byte[] baKey = new byte[16]; //return value byte[] baKey = new byte[16]; //return value
try try
{ {
Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes(sTheString, SALTSIZE, ITERATION_COUNT, bUseOldMethod, sFilepath, bGenerateRandomSalt); Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes(sTheString, SALTSIZE, ITERATION_COUNT, bUseOldMethod, sFilepath, bGenerateRandomSalt, userID);
baKey = pkcs5.GetBytes(16); baKey = pkcs5.GetBytes(16);
} }
catch(Exception e) catch(Exception e)
@ -58,7 +59,7 @@ namespace sscs.crypto
} }
internal static bool StoreKeySetUsingMasterPasscode(byte[] key, internal static bool StoreKeySetUsingMasterPasscode(byte[] key,
byte[] IV, byte[] baMasterPasscode, string fileName) byte[] IV, byte[] baMasterPasscode, string fileName, UserIdentifier userID)
{ {
bool bRet = false; bool bRet = false;
FileStream fsEncrypt = null; FileStream fsEncrypt = null;
@ -69,7 +70,7 @@ namespace sscs.crypto
//Get an encryptor. //Get an encryptor.
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
ICryptoTransform encryptor; ICryptoTransform encryptor;
encryptor = myRijndael.CreateEncryptor(baMasterPasscode, GenerateAndSaveIV(fileName, myRijndael)); encryptor = myRijndael.CreateEncryptor(baMasterPasscode, GenerateAndSaveIV(fileName, myRijndael, userID));
//Encrypt the data to a file //Encrypt the data to a file
fsEncrypt = new FileStream(fileName, FileMode.Create); fsEncrypt = new FileStream(fileName, FileMode.Create);
@ -88,6 +89,15 @@ namespace sscs.crypto
//Write all data to the crypto stream and flush it. //Write all data to the crypto stream and flush it.
csEncrypt.Write(key, 0, key.Length); csEncrypt.Write(key, 0, key.Length);
csEncrypt.FlushFinalBlock(); csEncrypt.FlushFinalBlock();
csEncrypt.Close();
fsEncrypt.Close();
if (!CSSSUtils.SetSocketUserAsOwner(fileName, userID))
{
CSSSLogger.DbgLog("Unable to set the owner of the key file to the socket user");
}
bRet = true; bRet = true;
} }
catch(Exception e) catch(Exception e)
@ -100,11 +110,12 @@ namespace sscs.crypto
csEncrypt.Close(); csEncrypt.Close();
if( fsEncrypt != null ) if( fsEncrypt != null )
fsEncrypt.Close(); fsEncrypt.Close();
return bRet; return bRet;
} }
internal static byte[] GetKeySetFromFile(byte[] baMasterPasscode, internal static byte[] GetKeySetFromFile(byte[] baMasterPasscode,
string fileName ) string fileName, UserIdentifier userID )
{ {
byte[] baSavedKey = null; byte[] baSavedKey = null;
FileStream fsDecrypt = null; FileStream fsDecrypt = null;
@ -114,7 +125,7 @@ namespace sscs.crypto
{ {
#if LINUX #if LINUX
UnixFileInfo fsTest = new UnixFileInfo (fileName); UnixFileInfo fsTest = new UnixFileInfo (fileName);
if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink) if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(fileName, userID))
#else #else
if(!File.Exists(fileName)) if(!File.Exists(fileName))
#endif #endif
@ -127,7 +138,7 @@ namespace sscs.crypto
*/ */
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
ICryptoTransform decryptor = myRijndael.CreateDecryptor(baMasterPasscode, RetrieveIV(fileName, baMasterPasscode)); ICryptoTransform decryptor = myRijndael.CreateDecryptor(baMasterPasscode, RetrieveIV(fileName, baMasterPasscode, userID));
//Now decrypt //Now decrypt
fsDecrypt = new FileStream(fileName, FileMode.Open); fsDecrypt = new FileStream(fileName, FileMode.Open);
@ -181,7 +192,7 @@ namespace sscs.crypto
{ {
//Get an decryptor. //Get an decryptor.
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, baIV); ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, baIV);
csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Read); csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
//Read all data to the crypto stream and flush it. //Read all data to the crypto stream and flush it.
@ -233,7 +244,7 @@ namespace sscs.crypto
internal static void EncryptDataAndWriteToFile(byte[] xmlData, internal static void EncryptDataAndWriteToFile(byte[] xmlData,
byte[] key, string fileName) byte[] key, string fileName, UserIdentifier userID)
{ {
FileStream fsEncrypt = null; FileStream fsEncrypt = null;
CryptoStream csEncrypt = null; CryptoStream csEncrypt = null;
@ -241,7 +252,7 @@ namespace sscs.crypto
{ {
//Get an encryptor. //Get an encryptor.
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
byte[] baIV = GenerateAndSaveIV(fileName, myRijndael); byte[] baIV = GenerateAndSaveIV(fileName, myRijndael, userID);
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, baIV); ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, baIV);
@ -249,8 +260,8 @@ namespace sscs.crypto
//Encrypt the data to a file //Encrypt the data to a file
fsEncrypt = new FileStream(fileName, FileMode.Create); fsEncrypt = new FileStream(fileName, FileMode.Create);
// make hidden // make hidden
File.SetAttributes(fileName, FileAttributes.Hidden); File.SetAttributes(fileName, FileAttributes.Hidden);
SHA256 sha = new SHA256Managed(); SHA256 sha = new SHA256Managed();
@ -266,15 +277,21 @@ namespace sscs.crypto
fsClear.Write(dup, 0, dup.Length); fsClear.Write(dup, 0, dup.Length);
fsClear.Flush(); fsClear.Flush();
fsClear.Close(); fsClear.Close();
CSSSUtils.SetSocketUserAsOwner(fileName + ".xml", userID);
#endif #endif
csEncrypt = new CryptoStream(fsEncrypt, encryptor, CryptoStreamMode.Write); csEncrypt = new CryptoStream(fsEncrypt, encryptor, CryptoStreamMode.Write);
//Write all data to the crypto stream and flush it. //Write all data to the crypto stream and flush it.
csEncrypt.Write(xmlData, 0, xmlData.Length); csEncrypt.Write(xmlData, 0, xmlData.Length);
csEncrypt.FlushFinalBlock(); csEncrypt.FlushFinalBlock();
csEncrypt.Close();
fsEncrypt.Close();
if (!CSSSUtils.SetSocketUserAsOwner(fileName, userID)) {
CSSSLogger.DbgLog("Unable to set the owner of the encrypted file to the socket user");
}
} }
catch(Exception e) catch(Exception e)
{ {
@ -287,7 +304,7 @@ namespace sscs.crypto
fsEncrypt.Close(); fsEncrypt.Close();
} }
internal static void ComputeHashAndWriteToFile(byte[] baPasscode, string fileName) internal static void ComputeHashAndWriteToFile(byte[] baPasscode, string fileName, UserIdentifier userID)
{ {
FileStream fsHash = null; FileStream fsHash = null;
@ -295,14 +312,21 @@ namespace sscs.crypto
try try
{ {
SHA256 shaM = new SHA256Managed(); SHA256 shaM = new SHA256Managed();
hash = shaM.ComputeHash(baPasscode); hash = shaM.ComputeHash(baPasscode);
fsHash = new FileStream(fileName, FileMode.Create); fsHash = new FileStream(fileName, FileMode.Create);
File.SetAttributes(fileName, FileAttributes.Hidden); File.SetAttributes(fileName, FileAttributes.Hidden);
fsHash.Write(hash, 0, hash.Length); fsHash.Write(hash, 0, hash.Length);
fsHash.Flush(); fsHash.Flush();
fsHash.Close();
if (!CSSSUtils.SetSocketUserAsOwner(fileName, userID))
{
CSSSLogger.DbgLog("Unable to set the owner of the hash file to the socket user");
}
} }
catch(Exception e) catch(Exception e)
{ {
@ -315,7 +339,7 @@ namespace sscs.crypto
} }
internal static byte[] ReadFileAndDecryptData(byte[] key, internal static byte[] ReadFileAndDecryptData(byte[] key,
string fileName) string fileName, UserIdentifier userID)
{ {
FileStream fsDecrypt = null; FileStream fsDecrypt = null;
CryptoStream csDecrypt = null; CryptoStream csDecrypt = null;
@ -328,16 +352,16 @@ namespace sscs.crypto
//Get a decryptor that uses the same key and IV as the encryptor. //Get a decryptor that uses the same key and IV as the encryptor.
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
byte[] baIV = RetrieveIV(fileName, IV); byte[] baIV = RetrieveIV(fileName, IV, userID);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, baIV); ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, baIV);
#if LINUX #if LINUX
UnixFileInfo fsTest = new UnixFileInfo (fileName); UnixFileInfo fsTest = new UnixFileInfo (fileName);
if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink) if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(fileName, userID))
#else #else
if(!File.Exists(fileName)) if(!File.Exists(fileName))
#endif #endif
{ {
return null; return null;
} }
@ -347,23 +371,23 @@ namespace sscs.crypto
fsDecrypt.Read(storedHash,0,storedHash.Length); fsDecrypt.Read(storedHash,0,storedHash.Length);
csDecrypt = new CryptoStream(fsDecrypt, decryptor, CryptoStreamMode.Read); csDecrypt = new CryptoStream(fsDecrypt, decryptor, CryptoStreamMode.Read);
if(fsDecrypt.Length < HASH_SIZE ) if(fsDecrypt.Length < HASH_SIZE )
{ {
csDecrypt.Close(); csDecrypt.Close();
fsDecrypt.Close(); fsDecrypt.Close();
return null; return null;
} }
if(fsDecrypt.Length > MAX_FILE_SIZE ) if(fsDecrypt.Length > MAX_FILE_SIZE )
{ {
CSSSLogger.DbgLog("Size of the secret file exceeded the maximum allowed."); CSSSLogger.DbgLog("Size of the secret file exceeded the maximum allowed.");
csDecrypt.Close(); csDecrypt.Close();
fsDecrypt.Close(); fsDecrypt.Close();
return null; return null;
} }
ulong fileLen = (ulong)(fsDecrypt.Length - HASH_SIZE); ulong fileLen = (ulong)(fsDecrypt.Length - HASH_SIZE);
byte[] fromEncrypt = new byte[fileLen]; byte[] fromEncrypt = new byte[fileLen];
//Read the data out of the crypto stream. //Read the data out of the crypto stream.
int bytesRead = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); int bytesRead = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
@ -407,24 +431,24 @@ namespace sscs.crypto
if (csDecrypt != null) if (csDecrypt != null)
{ {
try try
{ {
csDecrypt.Close(); csDecrypt.Close();
} }
catch catch
{ {
} }
} }
if( fsDecrypt != null ) if( fsDecrypt != null )
{ {
try try
{ {
fsDecrypt.Close(); fsDecrypt.Close();
} }
catch catch
{ {
} }
} }
return null; return null;
} }
@ -508,9 +532,9 @@ namespace sscs.crypto
return (File.Exists(fileName)); return (File.Exists(fileName));
} }
internal static byte[] GetMasterPasscode(string desktopPasswd, string fileName) internal static byte[] GetMasterPasscode(string desktopPasswd, string fileName, UserIdentifier userID)
{ {
byte[] mp = DecryptMasterPasscodeUsingString(desktopPasswd, fileName, false); byte[] mp = DecryptMasterPasscodeUsingString(desktopPasswd, fileName, false, userID);
return mp; return mp;
} }
@ -523,24 +547,25 @@ namespace sscs.crypto
internal static void EncryptAndStoreMasterPasscodeUsingString( internal static void EncryptAndStoreMasterPasscodeUsingString(
byte[] baMasterPasscode, byte[] baMasterPasscode,
string passwd, string passwd,
string fileName) string fileName,
UserIdentifier userID)
{ {
FileStream fsEncrypt = null; FileStream fsEncrypt = null;
CryptoStream csEncrypt = null; CryptoStream csEncrypt = null;
try try
{ {
if(File.Exists(fileName)) if(File.Exists(fileName))
File.Delete(fileName); File.Delete(fileName);
byte[] baKey = Generate16ByteKeyFromString(passwd, fileName, false, true); byte[] baKey = Generate16ByteKeyFromString(passwd, fileName, false, true, userID);
//Get an encryptor. //Get an encryptor.
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
ICryptoTransform encryptor; ICryptoTransform encryptor;
encryptor = myRijndael.CreateEncryptor(baKey, GenerateAndSaveIV(fileName, myRijndael)); encryptor = myRijndael.CreateEncryptor(baKey, GenerateAndSaveIV(fileName, myRijndael, userID));
//Encrypt the data to a file //Encrypt the data to a file
fsEncrypt = new FileStream(fileName,FileMode.Create); fsEncrypt = new FileStream(fileName,FileMode.Create);
csEncrypt = new CryptoStream(fsEncrypt, encryptor, csEncrypt = new CryptoStream(fsEncrypt, encryptor,
@ -552,9 +577,13 @@ namespace sscs.crypto
csEncrypt.Close(); csEncrypt.Close();
fsEncrypt.Close(); fsEncrypt.Close();
// make hidden // make hidden
File.SetAttributes(fileName, FileAttributes.Hidden); File.SetAttributes(fileName, FileAttributes.Hidden);
if (!CSSSUtils.SetSocketUserAsOwner(fileName, userID))
{
CSSSLogger.DbgLog("Unable to set the owner of the MPC file to the socket user");
}
} }
catch(Exception e) catch(Exception e)
{ {
@ -568,11 +597,10 @@ namespace sscs.crypto
{ {
fsEncrypt.Close(); fsEncrypt.Close();
} }
} }
public static byte[] DecryptMasterPasscodeUsingString(string passwd, public static byte[] DecryptMasterPasscodeUsingString(string passwd,
string fileName, bool bTryOldMethod) string fileName, bool bTryOldMethod, UserIdentifier userID)
{ {
FileStream fsDecrypt = null; FileStream fsDecrypt = null;
CryptoStream csDecrypt = null; CryptoStream csDecrypt = null;
@ -580,27 +608,26 @@ namespace sscs.crypto
try try
{ {
byte[] baKey = Generate16ByteKeyFromString(passwd, fileName, bTryOldMethod, false); byte[] baKey = Generate16ByteKeyFromString(passwd, fileName, bTryOldMethod, false, userID);
/* Get a decryptor that uses the same key and /* Get a decryptor that uses the same key and
* IV as the encryptor. * IV as the encryptor.
*/ */
RijndaelManaged myRijndael = new RijndaelManaged(); RijndaelManaged myRijndael = new RijndaelManaged();
ICryptoTransform decryptor = myRijndael.CreateDecryptor(baKey, RetrieveIV(fileName, baKey)); ICryptoTransform decryptor = myRijndael.CreateDecryptor(baKey, RetrieveIV(fileName, baKey, userID));
//Now decrypt //Now decrypt
#if LINUX #if LINUX
UnixFileInfo fsTest = new UnixFileInfo (fileName); UnixFileInfo fsTest = new UnixFileInfo (fileName);
if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink) if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(fileName, userID))
#else #else
if (!File.Exists(fileName)) if (!File.Exists(fileName))
#endif #endif
{ {
return null; return null;
} }
fsDecrypt = new FileStream(fileName, FileMode.Open); fsDecrypt = new FileStream(fileName, FileMode.Open);
csDecrypt = new CryptoStream(fsDecrypt, decryptor, csDecrypt = new CryptoStream(fsDecrypt, decryptor, CryptoStreamMode.Read);
CryptoStreamMode.Read);
baSavedMasterPasscode = new byte[16]; baSavedMasterPasscode = new byte[16];
//Read the data out of the crypto stream. //Read the data out of the crypto stream.
@ -633,7 +660,8 @@ namespace sscs.crypto
internal static byte[] GetMasterPasscodeUsingMasterPasswd( internal static byte[] GetMasterPasscodeUsingMasterPasswd(
string mPasswd, string mPasswd,
string fileName, string fileName,
bool bUseOldMethod) bool bUseOldMethod,
UserIdentifier userID)
{ {
byte[] baMasterPasscode; byte[] baMasterPasscode;
try try
@ -643,7 +671,7 @@ namespace sscs.crypto
/* Decrypt the passcode from the file using master passwd. /* Decrypt the passcode from the file using master passwd.
* and return the decrypted passcode. * and return the decrypted passcode.
*/ */
baMasterPasscode = DecryptMasterPasscodeUsingString(mPasswd, fileName, bUseOldMethod); baMasterPasscode = DecryptMasterPasscodeUsingString(mPasswd, fileName, bUseOldMethod, userID);
return baMasterPasscode; return baMasterPasscode;
} }
else else
@ -660,7 +688,8 @@ namespace sscs.crypto
internal static byte[] GetMasterPasscodeUsingDesktopPasswd( internal static byte[] GetMasterPasscodeUsingDesktopPasswd(
string desktopPasswd, string desktopPasswd,
string fileName, string fileName,
bool bUseOldMethod) bool bUseOldMethod,
UserIdentifier userID)
{ {
byte[] passcode; byte[] passcode;
try try
@ -671,7 +700,7 @@ namespace sscs.crypto
* and return the decrypted passcode. * and return the decrypted passcode.
*/ */
passcode = DecryptMasterPasscodeUsingString(desktopPasswd, passcode = DecryptMasterPasscodeUsingString(desktopPasswd,
fileName, bUseOldMethod); fileName, bUseOldMethod, userID);
return passcode; return passcode;
} }
@ -689,12 +718,13 @@ namespace sscs.crypto
internal static byte[] GetServerMasterPasscodeUsingMasterPasswd( internal static byte[] GetServerMasterPasscodeUsingMasterPasswd(
string mPasswd, string mPasswd,
string fileName, string fileName,
bool bUseOldMethod) bool bUseOldMethod,
UserIdentifier userID)
{ {
return GetMasterPasscodeUsingMasterPasswd ( mPasswd, fileName, bUseOldMethod); return GetMasterPasscodeUsingMasterPasswd ( mPasswd, fileName, bUseOldMethod, userID);
} }
internal static byte[] GetServerMasterPasscodeUsingSystemKey(string fileName) internal static byte[] GetServerMasterPasscodeUsingSystemKey(string fileName, UserIdentifier userID)
{ {
byte[] baSavedMasterPasscode = null; byte[] baSavedMasterPasscode = null;
@ -702,7 +732,7 @@ namespace sscs.crypto
{ {
#if LINUX #if LINUX
UnixFileInfo fsTest = new UnixFileInfo (fileName); UnixFileInfo fsTest = new UnixFileInfo (fileName);
if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink) if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(fileName, userID))
#else #else
if (!File.Exists(fileName)) if (!File.Exists(fileName))
#endif #endif
@ -716,7 +746,7 @@ namespace sscs.crypto
fs.Close(); fs.Close();
baSavedMasterPasscode = new byte[16]; baSavedMasterPasscode = new byte[16];
baSavedMasterPasscode = ProtectedData.Unprotect( encryptedMasterPasscode, RetrieveIV(fileName, new byte[16]), DataProtectionScope.CurrentUser ); baSavedMasterPasscode = ProtectedData.Unprotect( encryptedMasterPasscode, RetrieveIV(fileName, new byte[16], userID), DataProtectionScope.CurrentUser );
} }
catch (CryptographicException e) catch (CryptographicException e)
{ {
@ -732,7 +762,7 @@ namespace sscs.crypto
string desktopPasswd, string desktopPasswd,
string fileName, string fileName,
string validationFile, string validationFile,
UserIdentifier userId UserIdentifier userID
) )
{ {
try try
@ -747,9 +777,9 @@ namespace sscs.crypto
EncryptAndStoreMasterPasscodeUsingString(baPasscode, EncryptAndStoreMasterPasscodeUsingString(baPasscode,
desktopPasswd, desktopPasswd,
fileName); fileName,
userID);
ComputeHashAndWriteToFile(baPasscode, validationFile + "Hash"); //Hash of MPC is written to ".miCASAValidateHash" file ComputeHashAndWriteToFile(baPasscode, validationFile + "Hash", userID); //Hash of MPC is written to ".miCASAValidateHash" file
return baPasscode; return baPasscode;
} }
catch(Exception e) catch(Exception e)
@ -762,7 +792,8 @@ namespace sscs.crypto
internal static byte[] GenerateServerMasterPasscode( internal static byte[] GenerateServerMasterPasscode(
string fileName, string fileName,
string validationFile string validationFile,
UserIdentifier userID
) )
{ {
byte[] baPasscode = null; byte[] baPasscode = null;
@ -775,14 +806,18 @@ namespace sscs.crypto
myRijndael.GenerateKey(); myRijndael.GenerateKey();
baPasscode = myRijndael.Key; baPasscode = myRijndael.Key;
byte [] encryptedMasterPasscode = ProtectedData.Protect( baPasscode, GenerateAndSaveIV(fileName, null), DataProtectionScope.CurrentUser ); byte [] encryptedMasterPasscode = ProtectedData.Protect( baPasscode, GenerateAndSaveIV(fileName, null, userID), DataProtectionScope.CurrentUser );
FileStream fs = new FileStream(fileName, FileMode.Create); FileStream fs = new FileStream(fileName, FileMode.Create);
File.SetAttributes(fileName, FileAttributes.Hidden); File.SetAttributes(fileName, FileAttributes.Hidden);
fs.Write(encryptedMasterPasscode, 0, encryptedMasterPasscode.Length); fs.Write(encryptedMasterPasscode, 0, encryptedMasterPasscode.Length);
fs.Flush(); fs.Flush();
fs.Close(); fs.Close();
ComputeHashAndWriteToFile(baPasscode, validationFile + "Hash"); //Hash of MPC is written to ".miCASASrvValidateHash" file if (!CSSSUtils.SetSocketUserAsOwner(fileName, userID))
{
CSSSLogger.DbgLog("Unable to set the owner of the server MPC file to the socket user");
}
ComputeHashAndWriteToFile(baPasscode, validationFile + "Hash", userID); //Hash of MPC is written to ".miCASASrvValidateHash" file
} }
catch(Exception e) catch(Exception e)
@ -794,14 +829,14 @@ namespace sscs.crypto
return baPasscode; return baPasscode;
} }
public static bool CompareHashes(byte[] baPasscode, string fileName) public static bool CompareHashes(byte[] baPasscode, string fileName, UserIdentifier userID)
{ {
FileStream fsHash = null; FileStream fsHash = null;
try try
{ {
#if LINUX #if LINUX
UnixFileInfo fsTest = new UnixFileInfo (fileName); UnixFileInfo fsTest = new UnixFileInfo (fileName);
if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink) if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(fileName, userID))
#else #else
if (!File.Exists(fileName)) if (!File.Exists(fileName))
#endif #endif
@ -840,7 +875,7 @@ namespace sscs.crypto
return false; return false;
} }
public static bool ValidatePasscode(byte[] baPasscode, string fileName) public static bool ValidatePasscode(byte[] baPasscode, string fileName, UserIdentifier userID)
{ {
/* Here we decrpyt a well known string, throw exception /* Here we decrpyt a well known string, throw exception
* if not successful * if not successful
@ -854,7 +889,7 @@ namespace sscs.crypto
try try
{ {
if(CompareHashes(baPasscode, fileName + "Hash")) if(CompareHashes(baPasscode, fileName + "Hash", userID))
{ {
CSSSLogger.DbgLog("Using the hash of MPC for validating the MPC"); CSSSLogger.DbgLog("Using the hash of MPC for validating the MPC");
return true; return true;
@ -862,7 +897,7 @@ namespace sscs.crypto
else else
{ {
CSSSLogger.DbgLog("Using the validation string encrypted with MPC for validating the MPC"); CSSSLogger.DbgLog("Using the validation string encrypted with MPC for validating the MPC");
byte[] baString = ReadFileAndDecryptData(baPasscode, fileName); byte[] baString = ReadFileAndDecryptData(baPasscode, fileName, userID);
string sString = Encoding.Default.GetString(baString); string sString = Encoding.Default.GetString(baString);
char[] trimChars = {'\0'}; char[] trimChars = {'\0'};
sString = sString.TrimEnd(trimChars); sString = sString.TrimEnd(trimChars);
@ -880,27 +915,27 @@ namespace sscs.crypto
} }
catch(Exception e) catch(Exception e)
{ {
CSSSLogger.ExpLog(e.ToString()); CSSSLogger.ExpLog(e.ToString());
CSSSLogger.DbgLog("Validation of passcode failed."); CSSSLogger.DbgLog("Validation of passcode failed.");
} }
return false; return false;
} }
private static byte[] GenerateAndSaveIV(string sFileName, RijndaelManaged theRiManaged) private static byte[] GenerateAndSaveIV(string sFileName, RijndaelManaged theRiManaged, UserIdentifier userID)
{ {
byte[] baIV = null; byte[] baIV = null;
if ( theRiManaged != null ) if ( theRiManaged != null )
{ {
theRiManaged.GenerateIV(); theRiManaged.GenerateIV();
baIV = theRiManaged.IV; baIV = theRiManaged.IV;
} }
else else
{ {
RandomNumberGenerator rng = RandomNumberGenerator.Create (); RandomNumberGenerator rng = RandomNumberGenerator.Create ();
baIV = new byte [16]; baIV = new byte [16];
rng.GetBytes (baIV); rng.GetBytes (baIV);
} }
try try
{ {
@ -911,6 +946,11 @@ namespace sscs.crypto
fs.Close(); fs.Close();
File.SetAttributes(sFileName + ".IV", FileAttributes.Hidden); File.SetAttributes(sFileName + ".IV", FileAttributes.Hidden);
if (!CSSSUtils.SetSocketUserAsOwner(sFileName + ".IV", userID))
{
CSSSLogger.DbgLog("Unable to set the owner of the IV file to the socket user");
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -920,13 +960,23 @@ namespace sscs.crypto
return baIV; return baIV;
} }
private static byte[] RetrieveIV(string sFileName, byte[] baOrigValue) private static byte[] RetrieveIV(string sFileName, byte[] baOrigValue, UserIdentifier userID)
{ {
byte[] IV = new byte[16]; byte[] IV = new byte[16];
// check for file existence // check for file existence
try try
{ {
#if LINUX
UnixFileInfo fsTest = new UnixFileInfo (sFileName + ".IV");
if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(sFileName + ".IV", userID))
#else
if (!File.Exists(sFileName + ".IV"))
#endif
{
return null;
}
FileStream fs = new FileStream(sFileName + ".IV", FileMode.Open); FileStream fs = new FileStream(sFileName + ".IV", FileMode.Open);
fs.Read(IV, 0, 16); fs.Read(IV, 0, 16);
fs.Close(); fs.Close();

File diff suppressed because it is too large Load Diff

View File

@ -20,312 +20,326 @@
* *
***********************************************************************/ ***********************************************************************/
// //
// Rfc2898DeriveBytes.cs: RFC2898 (PKCS#5 v2) Key derivation for Password Based Encryption // Rfc2898DeriveBytes.cs: RFC2898 (PKCS#5 v2) Key derivation for Password Based Encryption
// //
// Author: // Author:
// Sebastien Pouliot (sebastien@ximian.com) // Sebastien Pouliot (sebastien@ximian.com)
// //
// (C) 2003 Motus Technologies Inc. (http://www.motus.com) // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// //
//using System.Runtime.InteropServices; //using System.Runtime.InteropServices;
using System; using System;
using System.Text; using System.Text;
using System.IO; using System.IO;
using System.Security.Cryptography; using System.Security.Cryptography;
using sscs.lss; using sscs.lss;
using sscs.common; using sscs.common;
namespace sscs.crypto { namespace sscs.crypto {
//[ComVisible (true)] //[ComVisible (true)]
public class Rfc2898DeriveBytes : DeriveBytes { public class Rfc2898DeriveBytes : DeriveBytes {
private const int defaultIterations = 1000; private const int defaultIterations = 1000;
private int _iteration; private int _iteration;
private byte[] _salt; private byte[] _salt;
private HMACSHA1 _hmac; private HMACSHA1 _hmac;
private byte[] _buffer; private byte[] _buffer;
private int _pos; private int _pos;
private int _f; private int _f;
// constructors // constructors
public Rfc2898DeriveBytes (string password, byte[] salt) public Rfc2898DeriveBytes (string password, byte[] salt)
: this (password, salt, defaultIterations) : this (password, salt, defaultIterations)
{ {
} }
public Rfc2898DeriveBytes (string password, byte[] salt, int iterations) public Rfc2898DeriveBytes (string password, byte[] salt, int iterations)
{ {
if (password == null) if (password == null)
throw new ArgumentNullException ("password"); throw new ArgumentNullException ("password");
Salt = salt; Salt = salt;
IterationCount = iterations; IterationCount = iterations;
_hmac = new HMACSHA1 (Encoding.UTF8.GetBytes (password)); _hmac = new HMACSHA1 (Encoding.UTF8.GetBytes (password));
} }
public Rfc2898DeriveBytes (byte[] password, byte[] salt, int iterations) public Rfc2898DeriveBytes (byte[] password, byte[] salt, int iterations)
{ {
if (password == null) if (password == null)
throw new ArgumentNullException ("password"); throw new ArgumentNullException ("password");
Salt = salt; Salt = salt;
IterationCount = iterations; IterationCount = iterations;
_hmac = new HMACSHA1 (password); _hmac = new HMACSHA1 (password);
} }
public Rfc2898DeriveBytes (string password, int saltSize) public Rfc2898DeriveBytes (string password, int saltSize)
: this (password, saltSize, defaultIterations) : this (password, saltSize, defaultIterations)
{ {
} }
public Rfc2898DeriveBytes(string password, int saltSize, int iterations) public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
: this (password, saltSize, iterations, false, null, false) : this (password, saltSize, iterations, false, null, false, null)
{ {
} }
public Rfc2898DeriveBytes (string password, int saltSize, int iterations, bool bUseOldMethod, string sFilepath, bool bGenerateAndSaveRandomSalt) public Rfc2898DeriveBytes (string password, int saltSize, int iterations, bool bUseOldMethod, string sFilepath, bool bGenerateAndSaveRandomSalt, UserIdentifier userID)
{ {
if (password == null) if (password == null)
throw new ArgumentNullException ("password"); throw new ArgumentNullException ("password");
if (saltSize < 0) if (saltSize < 0)
throw new ArgumentOutOfRangeException ("invalid salt length"); throw new ArgumentOutOfRangeException ("invalid salt length");
if (bUseOldMethod) if (bUseOldMethod)
{ {
Salt = GenerateOldSalt(password, saltSize); Salt = GenerateOldSalt(password, saltSize);
} }
else else
{ {
if (bGenerateAndSaveRandomSalt) if (bGenerateAndSaveRandomSalt)
{ {
Salt = GenerateAndSaveRandomSalt(saltSize, sFilepath); Salt = GenerateAndSaveRandomSalt(saltSize, sFilepath, userID);
} }
else else
{ {
// load saved salt if one was saved // load saved salt if one was saved
if ((sFilepath != null) && (File.Exists(sFilepath + ".salt"))) if ((sFilepath != null) && (File.Exists(sFilepath + ".salt")))
{ {
Salt = LoadSavedSalt(sFilepath); Salt = LoadSavedSalt(sFilepath, userID);
} }
else else
{ {
Salt = GenerateNewSalt(password, saltSize); Salt = GenerateNewSalt(password, saltSize);
} }
} }
} }
IterationCount = iterations; IterationCount = iterations;
_hmac = new HMACSHA1 (Encoding.UTF8.GetBytes (password)); _hmac = new HMACSHA1 (Encoding.UTF8.GetBytes (password));
} }
private byte[] GenerateAndSaveRandomSalt(int saltSize, string sFilepath) private byte[] GenerateAndSaveRandomSalt(int saltSize, string sFilepath, UserIdentifier userID)
{ {
byte[] randomSalt = new byte[saltSize]; byte[] randomSalt = new byte[saltSize];
FastRandom fr = new FastRandom(); FastRandom fr = new FastRandom();
fr.NextBytes(randomSalt); fr.NextBytes(randomSalt);
// save salt // save salt
try try
{ {
FileStream fs = new FileStream(sFilepath + ".salt", FileMode.OpenOrCreate); FileStream fs = new FileStream(sFilepath + ".salt", FileMode.OpenOrCreate);
fs.Write(randomSalt, 0, randomSalt.Length); fs.Write(randomSalt, 0, randomSalt.Length);
fs.Flush(); fs.Flush();
fs.Close(); fs.Close();
File.SetAttributes(sFilepath + ".salt", FileAttributes.Hidden); File.SetAttributes(sFilepath + ".salt", FileAttributes.Hidden);
} if (!CSSSUtils.SetSocketUserAsOwner(sFilepath + ".salt", userID))
catch (Exception e) {
{ CSSSLogger.DbgLog("Unable to set the owner of the file to the socket user");
CSSSLogger.DbgLog(e.ToString()); }
} }
catch (Exception e)
return randomSalt; {
} CSSSLogger.DbgLog(e.ToString());
}
private byte[] LoadSavedSalt(string sFilePath)
{ return randomSalt;
byte[] baSalt = null; }
try private byte[] LoadSavedSalt(string sFilePath, UserIdentifier userID)
{ {
FileStream fs = new FileStream(sFilePath + ".salt", FileMode.Open); byte[] baSalt = null;
baSalt = new byte[fs.Length];
fs.Read(baSalt, 0, (int)fs.Length); try
fs.Close(); {
} #if LINUX
catch (Exception e) Mono.Unix.UnixFileInfo fsTest = new Mono.Unix.UnixFileInfo (sFilePath + ".salt");
{ if((fsTest == null) || !(fsTest.Exists) || fsTest.IsSymbolicLink || !CSSSUtils.CompareSocketAndFileUserIds(sFilePath + ".salt", userID))
CSSSLogger.DbgLog(e.ToString()); #else
} if (!File.Exists(sFilePath + ".salt"))
return baSalt; #endif
} {
return null;
private static byte[] GenerateOldSalt(string password, int saltSize) }
{
byte[] buffer = new byte[saltSize]; FileStream fs = new FileStream(sFilePath + ".salt", FileMode.Open);
Random rand = new Random(password.GetHashCode()); baSalt = new byte[fs.Length];
rand.NextBytes(buffer); fs.Read(baSalt, 0, (int)fs.Length);
return buffer; fs.Close();
} }
catch (Exception e)
private static byte[] GenerateNewSalt(string password, int saltSize) {
{ CSSSLogger.DbgLog(e.ToString());
int j = 0; }
byte[] buffer = new byte[saltSize]; return baSalt;
}
// iterate thru each character, creating a new Random,
// getting 2 bytes from each, until our salt buffer is full. private static byte[] GenerateOldSalt(string password, int saltSize)
for (int i = 0; i < password.Length;) {
{ byte[] buffer = new byte[saltSize];
char letter = password[i]; Random rand = new Random(password.GetHashCode());
int iLetter = (int)letter; rand.NextBytes(buffer);
return buffer;
FastRandom ranNum = new FastRandom(iLetter * (j+1)); }
byte[] temp = new byte[2];
ranNum.NextBytes(temp); private static byte[] GenerateNewSalt(string password, int saltSize)
{
for (int k = 0; k < temp.Length; k++) int j = 0;
{ byte[] buffer = new byte[saltSize];
buffer[j++] = temp[k];
// get out if buffer is full // iterate thru each character, creating a new Random,
if (j >= saltSize) // getting 2 bytes from each, until our salt buffer is full.
{ for (int i = 0; i < password.Length;)
return buffer; {
} char letter = password[i];
} int iLetter = (int)letter;
i++; FastRandom ranNum = new FastRandom(iLetter * (j+1));
byte[] temp = new byte[2];
// reset i if at end of password ranNum.NextBytes(temp);
if ((i + 1) > password.Length)
{ for (int k = 0; k < temp.Length; k++)
i = 0; {
} buffer[j++] = temp[k];
// get out if buffer is full
if (j >= saltSize)
} {
return buffer;
return buffer; }
} }
// properties i++;
public int IterationCount
{ // reset i if at end of password
get { return _iteration; } if ((i + 1) > password.Length)
set { {
if (value < 1) i = 0;
throw new ArgumentOutOfRangeException ("IterationCount < 1"); }
_iteration = value;
} }
}
return buffer;
public byte[] Salt { }
get { return (byte[]) _salt.Clone (); }
set { // properties
if (value == null) public int IterationCount
throw new ArgumentNullException ("Salt"); {
if (value.Length < 8) get { return _iteration; }
throw new ArgumentException ("Salt < 8 bytes"); set {
if (value < 1)
_salt = (byte[])value.Clone (); throw new ArgumentOutOfRangeException ("IterationCount < 1");
}
} _iteration = value;
}
// methods }
private byte[] F (byte[] s, int c, int i) public byte[] Salt {
{ get { return (byte[]) _salt.Clone (); }
byte[] data = new byte [s.Length + 4]; set {
Buffer.BlockCopy (s, 0, data, 0, s.Length); if (value == null)
byte[] int4 = BitConverter.GetBytes (i); throw new ArgumentNullException ("Salt");
Array.Reverse (int4, 0, 4); if (value.Length < 8)
Buffer.BlockCopy (int4, 0, data, s.Length, 4); throw new ArgumentException ("Salt < 8 bytes");
// this is like j=0 _salt = (byte[])value.Clone ();
byte[] u1 = _hmac.ComputeHash (data); }
data = u1; }
// so we start at j=1
for (int j=1; j < c; j++) { // methods
byte[] un = _hmac.ComputeHash (data);
// xor private byte[] F (byte[] s, int c, int i)
for (int k=0; k < 20; k++) {
u1 [k] = (byte)(u1 [k] ^ un [k]); byte[] data = new byte [s.Length + 4];
data = un; Buffer.BlockCopy (s, 0, data, 0, s.Length);
} byte[] int4 = BitConverter.GetBytes (i);
return u1; Array.Reverse (int4, 0, 4);
} Buffer.BlockCopy (int4, 0, data, s.Length, 4);
public override byte[] GetBytes (int cb) // this is like j=0
{ byte[] u1 = _hmac.ComputeHash (data);
if (cb < 1) data = u1;
throw new ArgumentOutOfRangeException ("cb"); // so we start at j=1
for (int j=1; j < c; j++) {
int l = cb / 20; // HMACSHA1 == 160 bits == 20 bytes byte[] un = _hmac.ComputeHash (data);
int r = cb % 20; // remainder // xor
if (r != 0) for (int k=0; k < 20; k++)
l++; // rounding up u1 [k] = (byte)(u1 [k] ^ un [k]);
data = un;
byte[] result = new byte [cb]; }
int rpos = 0; return u1;
if (_pos > 0) { }
int count = Math.Min (20 - _pos, cb);
Buffer.BlockCopy (_buffer, _pos, result, 0, count); public override byte[] GetBytes (int cb)
if (count >= cb) {
return result; if (cb < 1)
_pos = 0; throw new ArgumentOutOfRangeException ("cb");
rpos = 20 - cb;
r = cb - rpos; int l = cb / 20; // HMACSHA1 == 160 bits == 20 bytes
} int r = cb % 20; // remainder
if (r != 0)
for (int i=1; i <= l; i++) { l++; // rounding up
_buffer = F (_salt, _iteration, ++_f);
int count = ((i == l) ? r : 20); byte[] result = new byte [cb];
Buffer.BlockCopy (_buffer, _pos, result, rpos, count); int rpos = 0;
rpos += _pos + count; if (_pos > 0) {
_pos = ((count == 20) ? 0 : count); int count = Math.Min (20 - _pos, cb);
} Buffer.BlockCopy (_buffer, _pos, result, 0, count);
if (count >= cb)
return result; return result;
} _pos = 0;
rpos = 20 - cb;
public override void Reset () r = cb - rpos;
{ }
_buffer = null;
_pos = 0; for (int i=1; i <= l; i++) {
_f = 0; _buffer = F (_salt, _iteration, ++_f);
} int count = ((i == l) ? r : 20);
} Buffer.BlockCopy (_buffer, _pos, result, rpos, count);
} rpos += _pos + count;
_pos = ((count == 20) ? 0 : count);
}
return result;
}
public override void Reset ()
{
_buffer = null;
_pos = 0;
_f = 0;
}
}
}