We have an legacy web application which is using Persits Software's aspEncrypt. I have thousands of files encrypted with that setup so I need to stay compatible.
I am trying to write a new utility application in C# to match that same encryption. The goal here is to NOT use aspEncrypt in the new application and to match the encryption using the stuff built into the .NET framework. If successful then I could use the same legacy decryption routines on both the legacy and new files.
Sample code for how I handle the encryption step using aspEncrypt:
public static int EncryptFileWithRawKey2()
{
string InputFile = #"D:\TEMP\004\testfile.txt"; // contains single line of ANSI text with no end of line characters "hello this is a file"
string OutPutFile = #"D:\TEMP\004\testfile.txt.3.xxx";
string RawKey = "4CDD1518CD6662C9D1583A8732173EDC";
int iRet = 0;
ASPENCRYPTLib.ICryptoKey eKey = null;
try
{
ASPENCRYPTLib.CryptoManager CM = new ASPENCRYPTLib.CryptoManager();
ASPENCRYPTLib.ICryptoContext Context = CM.OpenContext("", 0, 0);
ASPENCRYPTLib.ICryptoBlob Blob = CM.CreateBlob();
Blob.Hex = RawKey;
eKey = Context.ImportRawKey(Blob, ASPENCRYPTLib.CryptoAlgorithms.calgRC2);
ASPENCRYPTLib.ICryptoBlob IVblob = CM.CreateBlob();
IVblob.Hex = "0000000000000000";
eKey.SetIV(IVblob);
eKey.Mode = ASPENCRYPTLib.CryptoCipherModes.ccmCBC;
eKey.Padding = ASPENCRYPTLib.CryptoCipherPadding.ccpPKCS5;
eKey.EffectiveLength = 40;
eKey.EncryptFile(InputFile.Trim(), OutPutFile.Trim());
if (File.Exists(OutPutFile) == true)
iRet = 1;
}
catch (Exception e)
{
Console.WriteLine("EncryptFileWithRawKey2 FAILED");
Console.WriteLine(e.ToString());
iRet = - 1;
}
return iRet;
}
And here is the code I wrote in what has so far been an unsuccessful attempt to match it:
public static void EncryptTextToFile2()
{
String Data = "hello this is a file";
String FileName = #"D:\TEMP\004\testfile.txt.4.xxx";
String sTempKey = "4CDD1518CD6662C9D1583A8732173EDC";
byte[] Key;
byte[] IV;
try
{
Key = StringToByteArray(sTempKey);
IV = StringToByteArray("0000000000000000");
FileStream fStream = File.Open(FileName, FileMode.OpenOrCreate);
RC2 RC2alg = RC2.Create();
RC2alg.Padding = PaddingMode.PKCS7;
RC2alg.Mode = CipherMode.CBC;
RC2alg.KeySize = 40;
RC2alg.EffectiveKeySize = 40;
CryptoStream cStream = new CryptoStream(fStream, RC2alg.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
cStream.FlushFinalBlock();
StreamWriter sWriter = new StreamWriter(cStream);
sWriter.WriteLine(Data);
sWriter.Close();
cStream.Close();
fStream.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
}
}
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
The output from the two routines does not match. I cannot change the logic which uses the AspEncrypt libraries so I need to change the second section of code in some way to match the output from the first.
Related
I've been working on a project to verify digital signature of provided XML documents.
The document schema is as provided below.
<?xml version="1.0" encoding="UTF-8"?>
<XMLReport>
<INNER_CONTENT>----content----</INNER_CONTENT>
<Signature>
<SIGNALGO>SHA512</SIGNALGO>
<KeyInfo>3082010A0282010100D8F165280...........</KeyInfo>
<SignatureValue>{data}</SignatureValue>
<HASH>{data}</HASH>
</Signature>
</XMLReport>
So far, I've tried to decrypt the SignatureValue in the provided document using the public key constructed from the KeyInfo field. I'm using the BouncyCastle library to do the above, but it's been throwing me the below exception.
Org.BouncyCastle.Crypto.InvalidCipherTextException: 'block incorrect'
The error occurs at the below code:
var decryptedBytes = decryptEngine.ProcessBlock(Encoding.GetEncoding(1256).GetBytes(segment), 0, segment.Length);
Am I approaching this the wrong way? Some help to solve this issue is much appreciated.
Edit:
public static string RsaDecryptWithPublic(string encryptedData, string publicKey) {
var decryptedResult = string.Empty;
try {
Int32 EncryptedLength = 256;
int len = encryptedData.Length;
var length = len / EncryptedLength;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using(var txtreader = new StringReader(publicKey)) {
var keyParameter = (AsymmetricKeyParameter) new PemReader(txtreader).ReadObject();
decryptEngine.Init(false, keyParameter);
}
var sb = new StringBuilder();
string resultData = "";
for (var i = 0; i < length; i++) {
string segment = encryptedData.Substring(i * EncryptedLength, EncryptedLength);
try {
var decryptedBytes = decryptEngine.ProcessBlock(Encoding.GetEncoding(1256).GetBytes(segment), 0, segment.Length);
resultData = Encoding.GetEncoding(1256).GetString(decryptedBytes);
} catch (Exception GenEx) {
string error = GenEx.Message;
}
sb.Append(resultData);
}
decryptedResult = sb.ToString();
} catch (Exception ex) {
}
return decryptedResult;
}
I have a .Net library that I am using to access a third party REST service. I stored the security information in the Properties/Settings. It works great. The thing is, I wanted to make sure my security information wasn't sitting around in a text file somewhere that could be compromised. I looked in the application.exe.config file and I didn't see a section for application settings. There is not a .config file for the .dll. I looked at https://learn.microsoft.com/en-us/visualstudio/ide/managing-application-settings-dotnet?view=vs-2019 and it said that application settings would not work in a library/dll. This is clearly not the case since it is working. Does anyone know where it stores the settings for a library/dll? Is there a best practice to store sensitive data for a windows forms app using .Net Framework 4.7.2?
Like other projects, dlls can also use Properties.Settings to store user data.
As to store sensitive data, You can try to encrypt / decrypt the data. Then store the encrypted string into Settings.
The following is an encrypt demo you can refer to.
// dll
namespace dlltest
{
public class Class1
{
public void Show()
{
Console.WriteLine(Properties.Settings.Default.EncryptedString);
string key = "A123456."; // 8 or 16 characters
DES des = new DES();
Console.WriteLine("1.Encrypt\n2.Decrypt");
string option = Console.ReadLine();
switch (option)
{
// Encrypt
case "1":
Console.WriteLine("Input a string");
string str = Console.ReadLine();
Properties.Settings.Default.EncryptedString = des.DesEncrypt(str, key);
Properties.Settings.Default.Save();
break;
// Decrypt
case "2":
Console.WriteLine(des.DesDecrypt(Properties.Settings.Default.EncryptedString, key));
break;
}
Console.ReadLine();
}
}
public class DES
{
// DES Encrypt
public string DesEncrypt(string pToEncrypt, string sKey)
{
StringBuilder ret = new StringBuilder();
try
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = Encoding.Default.GetBytes(pToEncrypt);
des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
foreach (byte b in ms.ToArray())
{
ret.AppendFormat("{0:X2}", b);
}
ret.ToString();
}
catch { }
return ret.ToString();
}
// DES Decrypt
public string DesDecrypt(string pToDecrypt, string sKey)
{
MemoryStream ms = new MemoryStream();
try
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
for (int x = 0; x < pToDecrypt.Length / 2; x++)
{
int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
inputByteArray[x] = (byte)i;
}
des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
StringBuilder ret = new StringBuilder();
}
catch { }
return System.Text.Encoding.Default.GetString(ms.ToArray());
}
}
}
I'm trying to decrypt a string which is also base64 encoded, but I am receiving an when I try to decrypt the string.
The error I am receiving is:
{System.FormatException: Invalid length for a Base-64 char array or string.
at this line in the decrypt function below:
MemoryStream ms = new MemoryStream(Convert.FromBase64String(inString));
Encrpyt/Decrypt functions:
//ENCRYPT
public static bool stringEncrypt(string inString,ref string outstring)
{
try
{
if(String.IsNullOrEmpty(inString)){return false;}
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,provider.CreateEncryptor(PWbytes,PWbytes),CryptoStreamMode.Write);
StreamWriter sw = new StreamWriter(cs);
sw.Write(inString);
sw.Flush();
cs.FlushFinalBlock();
sw.Flush();
outstring = Convert.ToBase64String(ms.GetBuffer(),0,(int)ms.Length);
return true;
}
catch(Exception ex)
{
clsCommonBase.AppendToExceptionFile("Encrypt : " + ex.Message);
return false;
}
}
//DECRPYT
public static bool stringDecrypt(string inString,ref string outstring)
{
try
{
if(String.IsNullOrEmpty(inString)){return false;};
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
MemoryStream ms = new MemoryStream(Convert.FromBase64String(inString));
CryptoStream cs = new CryptoStream(ms, provider.CreateDecryptor(PWbytes,PWbytes),CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cs);
outstring = sr.ReadToEnd();
return true;
}
catch(Exception ex)
{
clsCommonBase.AppendToExceptionFile("Decrypt : " + ex.Message);
return false;
}
}
Solved using the simple solution in the following link
How do I encode and decode a base64 string?
Also added some code in the encoding function to ensure the plain text string will be converted to a valid length base64 string.
Code:
public static string Base64Encode(string plainText)
{
//check plain text string and pad if needed
int mod4 = plainText.Length % 4;
if (mod4 > 0)
{
plainText += new string('=', 4 - mod4);
}
//convert to base64 and return
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
public static string Base64Decode(string base64EncodedData)
{
//decode base64 and return as string
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
I have an application in C# that encrypt my files with AES algorithm with this method:
private static void encryptFile(string inputFile, string outputFile, string strKey)
{
try
{
using (RijndaelManaged aes = new RijndaelManaged())
{
byte[] key = Encoding.UTF8.GetBytes(strKey);
byte[] IV = Encoding.UTF8.GetBytes(strKey);
using (FileStream fsCrypt = new FileStream(outputFile, FileMode.Create))
{
using (ICryptoTransform encryptor = aes.CreateEncryptor(key, IV))
{
using (CryptoStream cs = new CryptoStream(fsCrypt, encryptor, CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
}
}
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
The file is encrypted without an issue.
Then I want to decrypt the encrypted file with my Android (2.2) application. So I do this:
private void decriptFile() throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException, IOException {
//byte[] docBytes = serialize(myDoc);
byte[] b = new byte[0];
try {
Resources res = getResources();
InputStream in_s = res.openRawResource(R.raw.output27);
b = new byte[in_s.available()];
in_s.read(b);
//txtHelp.setText(new String(b));
} catch (Exception e) {
// e.printStackTrace();
//txtHelp.setText("Error: can't show help.");
}
//byte[] dataBytes = FileUtils.readFileToByteArray(File file);
byte[] key = new byte[0];
try {
// key = ("HR$2pIjHR$2pIj12").getBytes("UTF-8");
key = ("HR$2pIjHR$2pIj12").getBytes("UTF-8");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec k = new SecretKeySpec(key, "AES");
IvParameterSpec iv = new IvParameterSpec(key);
c.init(Cipher.DECRYPT_MODE, k, iv);
// IllegalBlockSizeException Occurred
//File folder = new File(Environment.getExternalStorageDirectory(),
//"test");
File folder = new File("/sdcard",
"test");
if (!folder.exists()) {
folder.mkdir();
}
byte[] decryptedDocBytes = c.doFinal(b);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(folder.getPath()+"/test.epub"));
bos.write(decryptedDocBytes);
bos.flush();
bos.close();
//DocumentsContract.Document decryptedDoc = (DocumentsContract.Document)deserialize(decryptedDocBytes);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//IvParameterSpec iv = new IvParameterSpec(key);
//And my serialize/deserialize methods:
}
This time decryption works fine.For decrypting same file in Objective C
I am using the following method:
- (NSData *)decrypt:(NSData *)plainText key:(NSData *)aSymmetricKey padding:(CCOptions *)pkcs7
{
//return [self doCipher:plainText key:aSymmetricKey context:kCCDecrypt padding:pkcs7];
return [self doCipher2:plainText iv:[self generateRandomIV:128] key:aSymmetricKey context:kCCDecrypt error:nil];
}
- (NSData *)doCipher2:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
0, //kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:#"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
This time no luck.What might be the problem??
Any help would be appreciated.
In the Android version you specify PKCS5Padding but no padding it the iOS version. Note that PKCS5Padding andPKCS7Padding amount to the same thing, there is just a definition difference.
Change:
0, //kCCOptionPKCS7Padding,
to
kCCOptionPKCS7Padding,
I wrote one app using C# to read data from a serial port and show the data on a textbox in hex string format. Finally, I saved all data to a binary file. If data is big (maybe > 20mb) it throws an out of memory error. How can I solve this? Here is my code:
private void btn_Save_Click(object sender, EventArgs e)
{
SaveFileDialog save_log = new SaveFileDialog();
save_log.DefaultExt = ".bin";
save_log.Filter = "Binary File (*.bin)|*.bin";
// Determine if the user selected a file name from the saveFileDialog.
if (save_log.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
save_log.FileName.Length > 0)
{
try
{
string hexString = Content.Text.ToString();
FileStream stream = new FileStream(save_log.FileName, FileMode.Create, FileAccess.ReadWrite);
stream.Write(Hex_to_ByteArray(hexString), 0, Hex_to_ByteArray(hexString).Length);
stream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private byte[] Hex_to_ByteArray(string s)
{
s = s.Replace(" ", "");
byte[] buffer = new byte[s.Length / 2];
for (int i = 0; i < s.Length; i += 2)
{
buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
}
return buffer;
}
You're creating the byte array twice. Also, the .Replace over such a long string doesn't help. You can avoid all this:
try
{
var stream = new FileStream(
save_log.FileName,
FileMode.Create,
FileAccess.ReadWrite);
WriteHexStringToFile(Content.Text, stream);
stream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
private void WriteHexStringToFile(string hexString, FileStream stream)
{
var twoCharacterBuffer = new StringBuilder();
var oneByte = new byte[1];
foreach (var character in hexString.Where(c => c != ' '))
{
twoCharacterBuffer.Append(character);
if (twoCharacterBuffer.Length == 2)
{
oneByte[0] = (byte)Convert.ToByte(twoCharacterBuffer.ToString(), 16);
stream.Write(oneByte, 0, 1);
twoCharacterBuffer.Clear();
}
}
}
Also, take a look at Encoding and/or BinaryFormatter which might do all of this for you.
Update:
First of all, please note that your whole idea of storing megabytes of data in a string is a nonsense, and you shouldn't do that. You should process your data in smaller parts. Because of this nonsense I'm unable to provide you with a working demo (on IDEONE for example), because of resource limitations of online compilers. I've tested the code on my machine, and as you can see I can even process 50 MB strings - but it all depends on the amount of memory you have available. If you do such things, then on every machine it will be easy to reach the limit of available memory. And the methods you ask about in this particular question are irrelevant - the problem is because you fill your memory with tons of data in your Content.Text string. When memory is almost full, the OutOfMemoryException can occur at almost any place in your code.
You can view the whole picture in your browser to see all the details.
Use IEnumerable. That will avoid the large byte array.
I don't know what is in Content.Text. If it's a byte array, maybe you can change
static internal IEnumerable<byte>Hex_to_Byte(string s)
into
static internal IEnumerable<byte>Hex_to_Byte(byte[] bytes)
and modify the code a bit
FileStream stream = new FileStream(save_log.FileName, FileMode.Create, FileAccess.ReadWrite);
foreach( byte b in Hex_to_Byte(hexString) )
stream.WriteByte(b);
stream.Close();
static internal IEnumerable<byte>Hex_to_Byte(string s)
{
bool haveFirstByte = false;
int firstByteValue = 0;
foreach( char c in s)
{
if( char.IsWhiteSpace(c))
continue;
if( !haveFirstByte)
{
haveFirstByte = true;
firstByteValue = GetHexValue(c) << 4;
}
else
{
haveFirstByte = false;
yield return unchecked((byte)(firstByteValue + GetHexValue(c)));
}
}
}
static string hexChars = "0123456789ABCDEF";
static int GetHexValue(char c)
{
int v = hexChars.IndexOf(char.ToUpper(c));
if (v < 0)
throw new ArgumentOutOfRangeException("c", string.Format("not a hex char: {0}"));
return v;
}