I have a requirment to send PGP Encrypted CSV Files to SFTP and i know nothing aboutr PGP. After a lot of research I could find following code on internet using 'Bouncy Castle' Library. The code seems gogod but does not work for me given my inexperience in PGP. Please help me in finding right values for:
publicKeyFileName
privateKeyFileName
pasPhrase
Below is my code:
namespace PgpEncryption
{
class Program
{
public static void Main()
{
EncryptAndSign();
}
private static void EncryptAndSign()
{
string publicKeyFileName = "";
string privateKeyFileName = "";
string pasPhrase = "";
PgpEncryptionKeys encryptionKeys
= new PgpEncryptionKeys(publicKeyFileName, privateKeyFileName, pasPhrase);
PgpEncrypt encrypter = new PgpEncrypt(encryptionKeys);
string encryptedFileName = "";
using (Stream outputStream = File.Create(encryptedFileName))
{
string fileToEncrypt = "";
encrypter.EncryptAndSign(outputStream, new FileInfo(fileToEncrypt));
}
}
}
}
public class PgpEncryptionKeys
{
public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase)
{
if (!File.Exists(publicKeyPath))
throw new ArgumentException("Public key file not found", "publicKeyPath");
if (!File.Exists(privateKeyPath))
throw new ArgumentException("Private key file not found", "privateKeyPath");
if (String.IsNullOrEmpty(passPhrase))
throw new ArgumentException("passPhrase is null or empty.", "passPhrase");
PublicKey = ReadPublicKey(publicKeyPath);
SecretKey = ReadSecretKey(privateKeyPath);
PrivateKey = ReadPrivateKey(passPhrase);
}
#region Secret Key
private PgpSecretKey ReadSecretKey(string privateKeyPath)
{
using (Stream keyIn = File.OpenRead(privateKeyPath))
using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
{
PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream);
PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle);
if (foundKey != null)
return foundKey;
}
throw new ArgumentException("Can't find signing key in key ring.");
}
private PgpSecretKey GetFirstSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle)
{
foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings())
{
PgpSecretKey key = (PgpSecretKey)kRing.GetSecretKeys();
if (key != null)
return key;
}
return null;
}
#endregion
#region Public Key
private PgpPublicKey ReadPublicKey(string publicKeyPath)
{
using (Stream keyIn = File.OpenRead(publicKeyPath))
using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
{
PgpPublicKeyRingBundle publicKeyRingBundle = new PgpPublicKeyRingBundle(inputStream);
PgpPublicKey foundKey = GetFirstPublicKey(publicKeyRingBundle);
if (foundKey != null)
return foundKey;
}
throw new ArgumentException("No encryption key found in public key ring.");
}
private PgpPublicKey GetFirstPublicKey(PgpPublicKeyRingBundle publicKeyRingBundle)
{
foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings())
{
PgpPublicKey key = (PgpPublicKey)kRing.GetPublicKeys();
//PgpPublicKey key = kRing.GetPublicKeys()
//.Cast<PgpPublicKey>()
// .Where(k => k.IsEncryptionKey)
// .FirstOrDefault();
if (key != null)
return key;
}
return null;
}
#endregion
#region Private Key
private PgpPrivateKey ReadPrivateKey(string passPhrase)
{
PgpPrivateKey privateKey = SecretKey.ExtractPrivateKey(passPhrase.ToCharArray());
if (privateKey != null)
return privateKey;
throw new ArgumentException("No private key found in secret key.");
}
#endregion
}
public class PgpEncrypt
{
private PgpEncryptionKeys m_encryptionKeys;
private const int BufferSize = 0x10000; // should always be power of 2
/// <summary>
/// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKeys.
/// </summary>
/// <param name="encryptionKeys"></param>
/// <exception cref="ArgumentNullException">encryptionKeys is null</exception>
public PgpEncrypt(PgpEncryptionKeys encryptionKeys)
{
if (encryptionKeys == null)
throw new ArgumentNullException("encryptionKeys", "encryptionKeys is null.");
m_encryptionKeys = encryptionKeys;
}
/// <summary>
/// Encrypt and sign the file pointed to by unencryptedFileInfo and
/// write the encrypted content to outputStream.
/// </summary>
/// <param name="outputStream">The stream that will contain the
/// encrypted data when this method returns.</param>
/// <param name="fileName">FileInfo of the file to encrypt</param>
public void EncryptAndSign(Stream outputStream, FileInfo unencryptedFileInfo)
{
if (outputStream == null)
throw new ArgumentNullException("outputStream", "outputStream is null.");
if (unencryptedFileInfo == null)
throw new ArgumentNullException("unencryptedFileInfo", "unencryptedFileInfo is null.");
if (!File.Exists(unencryptedFileInfo.FullName))
throw new ArgumentException("File to encrypt not found.");
using (Stream encryptedOut = ChainEncryptedOut(outputStream))
using (Stream compressedOut = ChainCompressedOut(encryptedOut))
{
PgpSignatureGenerator signatureGenerator = InitSignatureGenerator compressedOut);
using (Stream literalOut = ChainLiteralOut(compressedOut, unencryptedFileInfo))
using (FileStream inputFile = unencryptedFileInfo.OpenRead())
{
WriteOutputAndSign(compressedOut, literalOut, inputFile, signatureGenerator);
}
}
}
private static void WriteOutputAndSign(Stream compressedOut,Stream literalOut,FileStream inputFile,PgpSignatureGenerator signatureGenerator)
{
int length = 0;
byte[] buf = new byte[BufferSize];
while ((length = inputFile.Read(buf, 0, buf.Length)) > 0)
{
literalOut.Write(buf, 0, length);
signatureGenerator.Update(buf, 0, length);
}
signatureGenerator.Generate().Encode(compressedOut);
}
private Stream ChainEncryptedOut(Stream outputStream)
{
PgpEncryptedDataGenerator encryptedDataGenerator;
encryptedDataGenerator =
new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes,
new SecureRandom());
encryptedDataGenerator.AddMethod(m_encryptionKeys.PublicKey);
return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]);
}
private static Stream ChainCompressedOut(Stream encryptedOut)
{
PgpCompressedDataGenerator compressedDataGenerator =
new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
return compressedDataGenerator.Open(encryptedOut);
}
private static Stream ChainLiteralOut(Stream compressedOut, FileInfo file)
{
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Binary, file);
}
private PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut)
{
const bool IsCritical = false;
const bool IsNested = false;
PublicKeyAlgorithmTag tag = m_encryptionKeys.SecretKey.PublicKey.Algorithm;
PgpSignatureGenerator pgpSignatureGenerator =
new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha1);
pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, m_encryptionKeys.PrivateKey);
foreach (string userId in m_encryptionKeys.SecretKey.PublicKey.GetUserIds())
{
PgpSignatureSubpacketGenerator subPacketGenerator =
new PgpSignatureSubpacketGenerator();
subPacketGenerator.SetSignerUserId(IsCritical, userId);
pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Generate());
// Just the first one!
break;
}
pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compressedOut);
return pgpSignatureGenerator;
}
}
You should obtain public key of the recipient of the message, and generate your own secret key (if you need to sign files). Also PGP allows password-based encryption, if this suits your needs.
Also I would recommend to take a look on commercial libraries (like SecureBlackbox) as well. They are costy, but includes much better support, demos, documentation, etc.
i think you miss some of the code?
public class PgpEncryptionKeys {
public PgpPublicKey PublicKey { get; private set; }
public PgpPrivateKey PrivateKey { get; private set; }
public PgpSecretKey SecretKey { get; private set; }
Related
I'd like to export PFX (public + private part) to separate files (*.cer, *.key). PFX may (or may not) be password protected.
I've tried to achieve my goal, which is fine with certificate (public), but causes a problem with private key.
My bootastrap class is as below:
public class CertBootstrap
{
private readonly FileInfo CertificateFile;
private readonly SecureString CertificatePassword;
public bool HasPasswordBeenSet { get; private set; } = false;
public X509Certificate2 Certificate { get; private set; }
public CertBootstrap(FileInfo certificationFile, string password)
{
if(!certificationFile.Exists)
{
throw new FileNotFoundException(certificationFile.FullName);
}
CertificateFile = certificationFile;
HasPasswordBeenSet = true;
CertificatePassword = ConvertPassword(password);
}
public CertBootstrap(FileInfo certificationFile)
{
if(!certificationFile.Exists)
{
throw new FileNotFoundException(certificationFile.FullName);
}
CertificateFile = certificationFile;
HasPasswordBeenSet = false;
}
public CertBootstrap(string certificationFullFileName, string password)
{
var certificateFile = new FileInfo(certificationFullFileName);
if(certificateFile == null || !certificateFile.Exists)
{
throw new FileNotFoundException(certificationFullFileName);
}
CertificateFile = certificateFile;
HasPasswordBeenSet = true;
CertificatePassword = ConvertPassword(password);
}
public CertBootstrap(string certificationFullFileName)
{
var certificateFile = new FileInfo(certificationFullFileName);
if(certificateFile == null || !certificateFile.Exists)
{
throw new FileNotFoundException(certificationFullFileName);
}
CertificateFile = certificateFile;
HasPasswordBeenSet = false;
}
public bool VerifyPassword(string password)
{
try
{
byte[] fileContent = File.ReadAllBytes(CertificateFile.FullName);
var certificate = new X509Certificate2(fileContent, password);
}
catch(CryptographicException ex)
{
if((ex.HResult & 0xFFFF) == 0x56)
{
return false;
}
;
throw;
}
return true;
}
private static SecureString ConvertPassword(string password)
{
var secure = new SecureString();
foreach(char c in password)
{
secure.AppendChar(c);
}
return secure;
}
public void LoadBootstrap()
{
LoadBootstrap(X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
}
public void LoadBootstrap(X509KeyStorageFlags keyStorageFlags)
{
this.Certificate = this.HasPasswordBeenSet ? new X509Certificate2(this.CertificateFile.FullName, this.CertificatePassword, keyStorageFlags) : new X509Certificate2(this.CertificateFile.FullName);
}
private static RSA ExportPrivateKeyCoreNet5Net6(RSA privateKey)
{
var password = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString());
PbeParameters pPar = new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100_000);
try
{
byte[] tempG = privateKey.ExportEncryptedPkcs8PrivateKey(password, pPar);
using(RSA exportRewriter = RSA.Create())
{
exportRewriter.ExportParameters(true);
exportRewriter.ImportEncryptedPkcs8PrivateKey(password, tempG, out _);
return exportRewriter;
}
}
catch(Exception e)
{
//catch this error
string em = e.Message;
throw;
}
}
private static byte[] ExportPrivateKey(RSA privateKey)
{
try
{
return privateKey.ExportPkcs8PrivateKey();
}
catch(CryptographicException)
{
}
return ExportPrivateKeyCoreNet5Net6(privateKey).ExportRSAPublicKey();
}
public byte[] GeneratePrivateKeyPem()
{
byte[] privateCertKeyBytes = ExportPrivateKey(this.Certificate.GetRSAPrivateKey());
char[] newPemData = PemEncoding.Write("PRIVATE KEY", privateCertKeyBytes);
return newPemData.Select(c => (byte)c).ToArray();
}
public byte[] GenerateCertificatePem()
{
var certData = Certificate.RawData;
var newPemData = PemEncoding.Write("CERTIFICATE", certData);
return newPemData.Select(c => (byte)c).ToArray();
}
public FileInfo SaveCertificate()
{
var newData = GenerateCertificatePem();
var oldFile = Path.GetFileNameWithoutExtension(CertificateFile.FullName);
var newCertPemFile = new FileInfo($#"{CertificateFile.DirectoryName}\{oldFile}.cer");
return SaveNewCertFile(newCertPemFile, newData);
}
public FileInfo SavePrivateKey()
{
var newData = GeneratePrivateKeyPem();
var oldFile = Path.GetFileNameWithoutExtension(CertificateFile.FullName);
var newPrivateKeyPemFile = new FileInfo($#"{CertificateFile.DirectoryName}\{oldFile}.key");
return SaveNewCertFile(newPrivateKeyPemFile, newData);
}
public FileInfo SaveNewCertFile(FileInfo newFile, byte[] data)
{
File.WriteAllBytes(newFile.FullName, data);
return newFile;
}
}
With it, I'm trying to save private part:
// (...)
CertBootstrap certBootstrap = new CertBootstrap("simple.pfx");
certBootstrap.LoadBootstrap();
// (...)
certBootstrap.SavePrivateKey();
and it all ends up with exception: "The requested operation it not supported".
I found similar thread: Cannot export RSA private key parameters, the requested operation is not supported and tried to do the same (Export -> Import with password). But did not help.
Can You point me propper direction? Most probably I'm missing something, but am out of ideas for now.
Thank You in advance.
I'm new to C# and I'm having some difficulty with saving the XML Atom feed from Gmail to an xml file. I'm certain I'm miles off of where I need to be and I'm embarassed to be asking this but I'm not getting anywhere on my own:(
I'm using the GmailHandler class that's been floating around for some time.
GmailHandler.cs
using System;
using System.Data;
using System.Xml;
using System.Net;
using System.IO;
/*
* this code made by Ahmed Essawy
* AhmedEssawy#gmail.com
* http://fci-h.blogspot.com
*/
/// <summary>
/// Summary description for Class1
/// </summary>
public class GmailHandler
{
private string username;
private string password;
private string gmailAtomUrl;
public string GmailAtomUrl
{
get { return gmailAtomUrl; }
set { gmailAtomUrl = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
public GmailHandler(string _Username, string _Password, string _GmailAtomUrl)
{
Username = _Username;
Password = _Password;
GmailAtomUrl = _GmailAtomUrl;
}
public GmailHandler(string _Username, string _Password)
{
Username = _Username;
Password = _Password;
GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
}
public XmlDocument GetGmailAtom()
{
byte[] buffer = new byte[8192];
int byteCount = 0;
XmlDocument _feedXml = null;
try
{
System.Text.StringBuilder sBuilder = new System.Text.StringBuilder();
WebRequest webRequest = WebRequest.Create(GmailAtomUrl);
webRequest.PreAuthenticate = true;
System.Net.NetworkCredential credentials = new NetworkCredential(this.Username, this.Password);
webRequest.Credentials = credentials;
WebResponse webResponse = webRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
while ((byteCount = stream.Read(buffer, 0, buffer.Length)) > 0)
sBuilder.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, byteCount));
_feedXml = new XmlDocument();
_feedXml.LoadXml(sBuilder.ToString());
}
catch (Exception ex)
{
//add error handling
throw ex;
}
return _feedXml;
}
}
Then I've got my Program.cs here:
I'm assuming the issue is with the code below since I'm responsible for that, and not what's above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace GmailAtom
{
class Program
{
static void Main()
{
//Create the object from GmailHandler class
GmailHandler gmailFeed = new GmailHandler("username", "password");
//get the feed
XmlDocument myXml = gmailFeed.GetGmailAtom();
XmlTextWriter writer = new XmlTextWriter("data.xml", null);
writer.Formatting = Formatting.Indented;
myXml.Save(writer);
}
}
}
When I run the program I get a "WebException was unhandled - The remote server returned an error: (407) Proxy Authentication Required."
Any advice would be appreciated!
I have tried the code and it works fine (but I have no proxy in my network).
I have changed the GmailHandler.cs, the constructor now accepts a internet proxy.
using System;
using System.Data;
using System.Xml;
using System.Net;
using System.IO;
/*
* this code made by Ahmed Essawy
* AhmedEssawy#gmail.com
* http://fci-h.blogspot.com
*/
/// <summary>
/// Summary description for Class1
/// </summary>
public class GmailHandler
{
private string username;
private string password;
private string gmailAtomUrl;
private string proxy;
public string GmailAtomUrl
{
get { return gmailAtomUrl; }
set { gmailAtomUrl = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
public string Proxy
{
get { return proxy; }
set { proxy = value; }
}
public GmailHandler(string _Username, string _Password, string _GmailAtomUrl, string _proxy = null)
{
Username = _Username;
Password = _Password;
GmailAtomUrl = _GmailAtomUrl;
Proxy = _proxy;
}
public GmailHandler(string _Username, string _Password, string _proxy = null)
{
Username = _Username;
Password = _Password;
GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
Proxy = _proxy;
}
public XmlDocument GetGmailAtom()
{
byte[] buffer = new byte[8192];
int byteCount = 0;
XmlDocument _feedXml = null;
try
{
System.Text.StringBuilder sBuilder = new System.Text.StringBuilder();
WebRequest webRequest = WebRequest.Create(GmailAtomUrl);
if(!String.IsNullOrWhiteSpace(Proxy))
webRequest.Proxy = new WebProxy(Proxy, true);
webRequest.PreAuthenticate = true;
System.Net.NetworkCredential credentials = new NetworkCredential(this.Username, this.Password);
webRequest.Credentials = credentials;
WebResponse webResponse = webRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
while ((byteCount = stream.Read(buffer, 0, buffer.Length)) > 0)
sBuilder.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, byteCount));
_feedXml = new XmlDocument();
_feedXml.LoadXml(sBuilder.ToString());
}
catch (Exception ex)
{
//add error handling
throw ex;
}
return _feedXml;
}
}
Use this in your console application:
//Create the object from GmailHandler class
GmailHandler gmailFeed = new GmailHandler("username", "password", "http://proxyserver:80/");
//get the feed
XmlDocument myXml = gmailFeed.GetGmailAtom();
XmlTextWriter writer = new XmlTextWriter("data.xml", null);
writer.Formatting = Formatting.Indented;
myXml.Save(writer);
i want write some setting to ini file with this code that search to find key and update it and if can't find the key add it to file . but it show this error :
"Object reference not set to an instance of an object."
i try this code :
internal class IniData
{
public string Key;
public string Value;
}
internal class IniSection : Dictionary<string, IniData>
{
public string Name { get; set; }
}
internal class IniFile : Dictionary<string, IniSection>
{
public string Path { get; set; }
}
public sealed class IniManager
{
private static readonly Dictionary<string, IniFile> IniFiles;
static IniManager()
{
IniFiles = new Dictionary<string, IniFile>();
}
public static void WriteIni(string fileName, string section, string key, string value)
{
/* Check if ini file exists in the ini collection */
var fileKey = fileName.ToLower();
if (!IniFiles.ContainsKey(fileKey))
{
if (!ImportIni(fileKey))
{
/* Add a new blank file */
var ini = new IniFile { Path = fileName };
IniFiles.Add(fileKey, ini);
}
}
/* Find section */
if (IniFiles[fileKey].ContainsKey(section.ToLower()))
{
/* Find key, if exists replace it */
if (IniFiles[fileKey][section.ToLower()].ContainsKey(key.ToLower()))
{
IniFiles[fileKey][section.ToLower()][key.ToLower()].Value = value;
return;
}
var data = new IniData { Key = key, Value = value };
IniFiles[fileKey][section.ToLower()].Add(key.ToLower(), data);
}
else
{
/* Create new ini section */
var sec = new IniSection { Name = section };
var data = new IniData { Key = key, Value = value };
sec.Add(key.ToLower(), data);
IniFiles[fileKey].Add(section.ToLower(), sec);
}
}
private static bool ImportIni(string fileName)
{
if (!File.Exists(fileName)) { return false; }
string[] data;
try
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
using (var reader = new StreamReader(stream))
{
data = reader.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
reader.Close();
}
stream.Close();
}
}
catch (Exception) { return false; }
if (data.Length == 0) { return false; }
var file = new IniFile { Path = fileName };
var section = new IniSection();
foreach (var s in data)
{
if (s.StartsWith("[") && s.EndsWith("]"))
{
/* Section header */
if (section.Count > 0)
{
/* Add current section */
file.Add(section.Name.ToLower(), section);
}
section = new IniSection { Name = s.Replace("[", null).Replace("]", null) };
continue;
}
/* Using current section, parse ini keys/values */
var iniData = ParseIni(s);
section.Add(iniData.Key.ToLower(), iniData);
}
if (section.Count > 0)
{
/* Add current section */
//##################Erorr : Object reference not set to an instance of an object.
file.Add(section.Name.ToLower(), section);
}
IniFiles.Add(fileName, file);
return true;
}
private static IniData ParseIni(string s)
{
var parts = s.Split('=');
return new IniData { Key = parts[0].Trim(), Value = parts.Length > 1 ? parts[1].Trim() : string.Empty };
}
}
private void button9_Click(object sender, EventArgs e)
{
IniManager.WriteIni("seting.ini", "Sec", "key", "value");
}
Instead of implementing this yourself you should just use the API functions that Windows provide. Of course, if you need to run this on Mono or other platforms than Windows, you need to go back to a pure .NET implementation, but even so I would probably go look for an existing implementation instead of creating that wheel yourself.
Anywhere, here's the API functions:
GetPrivateProfileString
WritePrivateProfileString
Here's an example LINQPad program that uses them:
(hit F4 and paste the following two lines into the additional namespace tab):
System.Runtime.InteropServices
System.ComponentModel
Then try this program:
void Main()
{
var ini = new IniFile(#"d:\temp\test.ini");
ini.WriteValue("Section", "Key", "Value");
ini.ReadValue("Section", "Key").Dump();
ini["Main", "Key2"] = "Test";
ini["Main", "Key2"].Dump();
}
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName,string lpDefault, StringBuilder lpReturnedString, uint nSize,string lpFileName);
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);
public class IniFile
{
const int MAX_SIZE = 1024;
private readonly string _FilePath;
public IniFile(string filePath)
{
if (filePath == null)
throw new ArgumentNullException("filePath");
_FilePath = filePath;
}
public string this[string section, string key]
{
get
{
return ReadValue(section, key);
}
set
{
WriteValue(section, key, value);
}
}
public string ReadValue(string section, string key, string defaultValue = null)
{
var result = new StringBuilder(MAX_SIZE);
if (GetPrivateProfileString(section, key, defaultValue ?? string.Empty, result, (uint)result.Capacity, _FilePath) > 0)
return result.ToString();
throw new Win32Exception();
}
public void WriteValue(string section, string key, string value)
{
if (!WritePrivateProfileString(section, key, value, _FilePath))
throw new Win32Exception();
}
}
The problem here is that if the file starts with a key and not with a section, the foreach doesn't match the if (s.StartsWith("[") && s.EndsWith("]")) at all and so the Section.Name is never set, thus it is null when called in file.Add(section.Name.ToLower(), section);
BTW: your code seems quite buggy, try to redesign it at least in the main foreach of ImportIni
I am currently working on a application which will create a text file, encrypt the file using PGP public key(which is not a file but a hexadecimal number and a pgp name) and post it to an FTP on schedule. The person whom I post the information to needs the file to be PGP encrypted and has shared the public key(which is not a file but a hexadecimal number and a pgp name).
The place where I am stuck is the PGP encryption part. I see examples on how to encrypt a text file using a public key file or public key ring(which I understand is a set of keys) using bouncy castle library. But the information I have is a 32 bit hexa decimal key and a PGP name. I am not sure how exactly to encrypt the file using this information. Should I request the other party to send me the public key file? Is it possible to create the public key file from the information I have? I am pretty new to PGP encryption and am posting this after a lot of googling which didnt provide any information, so please help.
This is the code I have so far to encrypt file. As you can see the code takes the file as an input for the public key not a hexa decimal code and name. My question really is, is it even possible to do a pgp encryption using a pgp name and a hexa decimal number?
public class PGPHelper
{
private PgpEncryptionKeys m_encryptionKeys;
private const int BufferSize = 0x10000;
/// <summary>
/// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKeys.
/// </summary>
/// <param name="encryptionKeys"></param>
/// <exception cref="ArgumentNullException">encryptionKeys is null</exception>
public PGPHelper(PgpEncryptionKeys encryptionKeys)
{
if (encryptionKeys == null)
{
throw new ArgumentNullException("encryptionKeys", "encryptionKeys is null.");
}
m_encryptionKeys = encryptionKeys;
}
/// <summary>
/// Encrypt and sign the file pointed to by unencryptedFileInfo and
/// write the encrypted content to outputStream.
/// </summary>
/// <param name="outputStream">The stream that will contain the
/// encrypted data when this method returns.</param>
/// <param name="fileName">FileInfo of the file to encrypt</param>
public void Encrypt(Stream outputStream, FileInfo unencryptedFileInfo)
{
if (outputStream == null)
{
throw new ArgumentNullException("outputStream", "outputStream is null.");
}
if (unencryptedFileInfo == null)
{
throw new ArgumentNullException("unencryptedFileInfo", "unencryptedFileInfo is null.");
}
if (!File.Exists(unencryptedFileInfo.FullName))
{
throw new ArgumentException("File to encrypt not found.");
}
using (Stream encryptedOut = ChainEncryptedOut(outputStream))
{
using (Stream literalOut = ChainLiteralOut(encryptedOut, unencryptedFileInfo))
using (FileStream inputFile = unencryptedFileInfo.OpenRead())
{
WriteOutput(literalOut, inputFile);
}
}
}
private static void WriteOutput(Stream literalOut,
FileStream inputFile)
{
int length = 0;
byte[] buf = new byte[BufferSize];
while ((length = inputFile.Read(buf, 0, buf.Length)) > 0)
{
literalOut.Write(buf, 0, length);
}
}
private Stream ChainEncryptedOut(Stream outputStream)
{
PgpEncryptedDataGenerator encryptedDataGenerator;
encryptedDataGenerator =
new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes, new SecureRandom());
encryptedDataGenerator.AddMethod(m_encryptionKeys.PublicKey);
return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]);
}
private static Stream ChainLiteralOut(Stream encryptedOut, FileInfo file)
{
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
return pgpLiteralDataGenerator.Open(encryptedOut, PgpLiteralData.Binary, file);
}
}
public class PgpEncryptionKeys
{
public PgpPublicKey PublicKey { get; private set; }
/// <summary>
/// Initializes a new instance of the EncryptionKeys class.
/// Two keys are required to encrypt and sign data. Your private key and the recipients public key.
/// The data is encrypted with the recipients public key and signed with your private key.
/// </summary>
/// <param name="publicKeyPath">The key used to encrypt the data</param>
/// <exception cref="ArgumentException">Public key not found. Private key not found. Missing password</exception>
public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase)
{
if (!File.Exists(publicKeyPath))
{
throw new ArgumentException("Public key file not found", "publicKeyPath");
}
PublicKey = ReadPublicKey(publicKeyPath);
}
#region Public Key
private PgpPublicKey ReadPublicKey(string publicKeyPath)
{
using (Stream keyIn = File.OpenRead(publicKeyPath))
using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
{
PgpPublicKeyRingBundle publicKeyRingBundle = new PgpPublicKeyRingBundle(inputStream);
PgpPublicKey foundKey = GetFirstPublicKey(publicKeyRingBundle);
if (foundKey != null)
{
return foundKey;
}
}
throw new ArgumentException("No encryption key found in public key ring.");
}
private PgpPublicKey GetFirstPublicKey(PgpPublicKeyRingBundle publicKeyRingBundle)
{
foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings())
{
PgpPublicKey key = kRing.GetPublicKeys()
.Cast<PgpPublicKey>()
.Where(k => k.IsEncryptionKey)
.FirstOrDefault();
if (key != null)
{
return key;
}
}
return null;
}
#endregion
I'm writing a publicly accessible web application which will contain personal user data, such as names and birth dates, and I'm required to encrypt this data in a form that will be difficult for a human who might access the raw data to decrypt. I'm using Fluent NHibernate, mySQL, and C# 3.5.
What method should I use for industry standard encryption and decryption of user information? The method of encryption should not be database dependent.
How do I tell nHibernate to do transparent encryption/decryption on certain mapped classes with a simple property, like StorageType = StorageType.Encrypted. I don't mind if the resulting database table has just one or two columns, or one for each encrypted field. From what I've found, I should create my own data type from IUserDataType and encrypt the data in the constructor. Is this correct?
In true Blue Peter fashion, here's one I created earlier to do just this. It relies on a provider pattern to get the encryption algorithm but you could replace this with whatever you want.
This exposes a string property in your domain object, but persists it as a binary (array of bytes) representing the encrypted form. In my provider pattern code, Encrypt takes a string and returns a byte array, and Decrypt does the opposite.
[Serializable]
public class EncryptedStringType : PrimitiveType
{
public EncryptedStringType() : this(new BinarySqlType()) {}
public EncryptedStringType(SqlType sqlType) : base(sqlType) {}
public override string Name
{
get { return "String"; }
}
public override Type ReturnedClass
{
get { return typeof (string); }
}
public override Type PrimitiveClass
{
get { return typeof (string); }
}
public override object DefaultValue
{
get { return null; }
}
public override void Set(IDbCommand cmd, object value, int index)
{
if (cmd == null) throw new ArgumentNullException("cmd");
if (value == null)
{
((IDataParameter)cmd.Parameters[index]).Value = null;
}
else
{
((IDataParameter)cmd.Parameters[index]).Value = EncryptionManager.Provider.Encrypt((string)value);
}
}
public override object Get(IDataReader rs, int index)
{
if (rs == null) throw new ArgumentNullException("rs");
var encrypted = rs[index] as byte[];
if (encrypted == null) return null;
return EncryptionManager.Provider.Decrypt(encrypted);
}
public override object Get(IDataReader rs, string name)
{
return Get(rs, rs.GetOrdinal(name));
}
public override object FromStringValue(string xml)
{
if (xml == null)
{
return null;
}
if (xml.Length % 2 != 0)
{
throw new ArgumentException(
"The string is not a valid xml representation of a binary content.",
"xml");
}
var bytes = new byte[xml.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
string hexStr = xml.Substring(i * 2, (i + 1) * 2);
bytes[i] = (byte)(byte.MinValue
+ byte.Parse(hexStr, NumberStyles.HexNumber, CultureInfo.InvariantCulture));
}
return EncryptionManager.Provider.Decrypt(bytes);
}
public override string ObjectToSQLString(object value, Dialect dialect)
{
var bytes = value as byte[];
if (bytes == null)
{
return "NULL";
}
var builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
string hexStr = (bytes[i] - byte.MinValue).ToString("x", CultureInfo.InvariantCulture);
if (hexStr.Length == 1)
{
builder.Append('0');
}
builder.Append(hexStr);
}
return builder.ToString();
}
}
I would create an EncryptionService that encrypts strings using whatever Key you'd like. Then I would make 2 properties in your entity. One that NHibernate interacts with (Encrypted values) and another that you (or other developers) interact with that will automatically encrypt the values.
See: http://kockerbeck.blogspot.com/2009/08/fluent-nhibernate-encrypting-values.html
A sample EncryptionService, User entity and UserMap are below.
public class User
{
private readonly EncryptionService _encryptionService =
new EncryptionService();
public virtual int Id { get; set; }
public virtual DateTime? DateOfBirth
{
get
{
return _encryptionService.DecryptObject<DateTime?>(DateOfBirthEncrypted);
}
set
{
DateOfBirthEncrypted= _encryptionService.EncryptString(value.Value
.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
[Obsolete("Use the 'DateOfBirth' property -- this property is only to be used by NHibernate")]
public virtual string DateOfBirthEncrypted { get; set; }
}
public sealed class UserMap : ClassMap<User>
{
public UserMap()
{
WithTable("dbo.[User]");
Id(x => x.Id, "[ID]");
Map(x => x.DateOfBirthEncrypted, "DOB");
}
}
And the EncryptionService:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Services
{
public class EncryptionService : IEncryptionService
{
/// <summary>
/// Decrypts a string
/// </summary>
/// <param name="encryptedString"></param>
/// <returns></returns>
public String DecryptString(string encryptedString)
{
if (String.IsNullOrEmpty(encryptedString)) return String.Empty;
try
{
using (TripleDESCryptoServiceProvider cypher = new TripleDESCryptoServiceProvider())
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes("ENTERAKEYHERE", new byte[0]);
cypher.Key = pdb.GetBytes(16);
cypher.IV = pdb.GetBytes(8);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, cypher.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] data = Convert.FromBase64String(encryptedString);
cs.Write(data, 0, data.Length);
cs.Close();
return Encoding.Unicode.GetString(ms.ToArray());
}
}
}
}
catch
{
return String.Empty;
}
}
/// <summary>
/// Encrypts a string
/// </summary>
/// <param name="decryptedString"
/// <returns></returns>
public String EncryptString(string decryptedString)
{
if (String.IsNullOrEmpty(decryptedString)) return String.Empty;
using (TripleDESCryptoServiceProvider cypher = new TripleDESCryptoServiceProvider())
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes("ENTERAKEYHERE", new byte[0]);
cypher.Key = pdb.GetBytes(16);
cypher.IV = pdb.GetBytes(8);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, cypher.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] data = Encoding.Unicode.GetBytes(decryptedString);
cs.Write(data, 0, data.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
}
}
}
/// <summary>
/// Decrypts a given value as type of T, if unsuccessful the defaultValue is used
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public T DecryptObject<T>(object value, T defaultValue)
{
if (value == null) return defaultValue;
try
{
Type conversionType = typeof(T);
// Some trickery for Nullable Types
if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
conversionType = new NullableConverter(conversionType).UnderlyingType;
}
return (T)Convert.ChangeType(DecryptString(Convert.ToString(value)), conversionType);
}
catch
{
// Do nothing
}
return defaultValue;
}
}
}