Add project files.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Data
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SacsAesIvCrypter
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public static String AesIvDelimiter { get; } = ";";
|
||||
public static String AesIvPrefix { get; } = "AESIV:";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ref. https://xamarinhelp.com/cryptography-in-xamarin-forms/
|
||||
// For reversible encryption, AES is generally the recommended standard.
|
||||
// AES 256 requires a 32 byte key to encrypt.
|
||||
// Either generate a 32 byte key or use any string and convert it into a key with CreateKey.
|
||||
// NB The salt will remain the same here for each key generated - it does not need to be randomized as with hashing.
|
||||
//-------------------------------------------------------------------
|
||||
private static byte[] CreateKey (string password, int keyBytes = 32)
|
||||
{
|
||||
byte[] salt = new byte[] { 80, 70, 60, 50, 40, 30, 20, 10 };
|
||||
int iterations = 300;
|
||||
DeriveBytes keyGenerator = new Rfc2898DeriveBytes(password, salt, iterations);
|
||||
return keyGenerator.GetBytes(keyBytes);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Encrypt String.
|
||||
// Return the encrypted text with the IV appended to the end.
|
||||
// In AES, the IV is a randomizer, making sure that no two identical messages ever give the same encrypted output.
|
||||
// The IV can be public and does not need to be hidden.
|
||||
//-------------------------------------------------------------------
|
||||
public static string Encrypt (this string clearValue, string encryptionKey)
|
||||
{
|
||||
using (Aes aes = Aes.Create())
|
||||
{
|
||||
aes.Key = CreateKey(encryptionKey);
|
||||
byte[] aesIV = aes.IV;
|
||||
byte[] encrypted = Encrypt(clearValue, aes.Key, aesIV);
|
||||
return Convert.ToBase64String(encrypted) + AesIvDelimiter + Convert.ToBase64String(aesIV);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public static byte[] Encrypt (string plainText, byte[] key, byte[] iv)
|
||||
{
|
||||
if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException($"{nameof(plainText)}");
|
||||
if (key == null || key.Length <= 0) throw new ArgumentNullException($"{nameof(key)}");
|
||||
if (iv == null || iv.Length <= 0) throw new ArgumentNullException($"{nameof(iv)}");
|
||||
byte[] encrypted;
|
||||
using (Aes aes = Aes.Create())
|
||||
{
|
||||
aes.Key = key;
|
||||
aes.IV = iv;
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
using (ICryptoTransform encryptor = aes.CreateEncryptor())
|
||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
||||
using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
|
||||
{
|
||||
streamWriter.Write(plainText);
|
||||
}
|
||||
encrypted = memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Decrypt String.
|
||||
// Decryption requires the encrypted value and the secret key.
|
||||
// This function is directly related to the above encryption process and will
|
||||
// assume that the IV is at the end of the string passed in.
|
||||
// To decrypt a message encrypted by another function, the IV will have to be passed explicitly.
|
||||
//-------------------------------------------------------------------
|
||||
public static string Decrypt (this string encryptedValue, string encryptionKey)
|
||||
{
|
||||
String[] valueParts = encryptedValue.Split(new String[] { AesIvDelimiter }, StringSplitOptions.None);
|
||||
if (valueParts.Length != 2)
|
||||
{
|
||||
SaLogger.Warn("SacsAesIvCrypter.Decrypt Missing IV - assuming not encrypted");
|
||||
return encryptedValue;
|
||||
//throw new CryptographicException("Decrypt failure: Missing IV");
|
||||
}
|
||||
return Decrypt(Convert.FromBase64String(valueParts[0]), CreateKey(encryptionKey), Convert.FromBase64String(valueParts[1]));
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public static string Decrypt (byte[] cipherText, byte[] key, byte[] iv)
|
||||
{
|
||||
if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException($"{nameof(cipherText)}");
|
||||
if (key == null || key.Length <= 0) throw new ArgumentNullException($"{nameof(key)}");
|
||||
if (iv == null || iv.Length <= 0) throw new ArgumentNullException($"{nameof(iv)}");
|
||||
|
||||
string plaintext = "";
|
||||
using (Aes aes = Aes.Create())
|
||||
{
|
||||
aes.Key = key;
|
||||
aes.IV = iv;
|
||||
using (MemoryStream memoryStream = new MemoryStream(cipherText))
|
||||
using (ICryptoTransform decryptor = aes.CreateDecryptor())
|
||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
||||
using (StreamReader streamReader = new StreamReader(cryptoStream))
|
||||
plaintext = streamReader.ReadToEnd();
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Data
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Very basic CSV data handling.
|
||||
/// <para>For more advanced CSV features, see SaCsvHelper in SacsWinOffice.</para>
|
||||
/// </summary>
|
||||
public static class SacsCsvHandler
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public static String ToCsv (this IEnumerable<String> values, char fieldDelimiter = ',', char textDelimiter = '"')
|
||||
{
|
||||
String data = "";
|
||||
int valueCount = 0;
|
||||
foreach (String rawValue in values)
|
||||
{
|
||||
valueCount++;
|
||||
String value = rawValue;
|
||||
if (value.Contains(fieldDelimiter.ToString()) || value.Contains(textDelimiter.ToString()))
|
||||
value = textDelimiter + value.Replace(textDelimiter.ToString(), textDelimiter.ToString() + textDelimiter.ToString()) + textDelimiter;
|
||||
data += (valueCount > 1 ? fieldDelimiter.ToString() : "") + value;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Extract comma delimited fields from data record.
|
||||
/// <para>Fields starting with double quotes are terminated with the next single double quotes character.</para>
|
||||
/// <para>Embedded double quotes pairs are treated as a single double quotes character.</para>
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static List<String> ParseCsvRecord (String data, char fieldDelimiter = ',', char textDelimiter = '"')
|
||||
{
|
||||
List<String> fields = new List<string>();
|
||||
if (data == null) return fields;
|
||||
|
||||
// Parse control properties.
|
||||
String currentField = "";
|
||||
bool inTextField = false;
|
||||
bool previousCharTextDelim = false;
|
||||
|
||||
// Parse the data.
|
||||
foreach (char c in data)
|
||||
{
|
||||
if (inTextField)
|
||||
{
|
||||
if (c == textDelimiter)
|
||||
{
|
||||
// Text delimiter found.
|
||||
if (!previousCharTextDelim)
|
||||
{
|
||||
// Make a note that a text delimiter has been found.
|
||||
previousCharTextDelim = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2nd text delimiter found - add single text delimiter to field.
|
||||
currentField += c;
|
||||
previousCharTextDelim = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (previousCharTextDelim)
|
||||
{
|
||||
// Non-text delimiter foudn after text delimiter - End of text field.
|
||||
inTextField = false;
|
||||
previousCharTextDelim = false;
|
||||
if (c == fieldDelimiter)
|
||||
{
|
||||
// End of field.
|
||||
fields.Add(currentField);
|
||||
currentField = "";
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
currentField += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-text field.
|
||||
if (c == fieldDelimiter)
|
||||
{
|
||||
// End of field.
|
||||
fields.Add(currentField);
|
||||
currentField = "";
|
||||
continue;
|
||||
}
|
||||
if (currentField.Length == 0 && c == textDelimiter)
|
||||
{
|
||||
// First character of field is text delimiter.
|
||||
inTextField = true;
|
||||
continue;
|
||||
}
|
||||
// Append character to field.
|
||||
currentField += c;
|
||||
}
|
||||
}
|
||||
fields.Add(currentField);
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Data
|
||||
{
|
||||
//=======================================================================
|
||||
public class SacsData
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
/// <summary>Construction - Empty data.</summary>
|
||||
public SacsData () { }
|
||||
/// <summary>Construction - Data from byte array.</summary>
|
||||
public SacsData (byte[] data)
|
||||
{
|
||||
DataBuffer = new byte[data?.Length ?? 0];
|
||||
DataLength = data?.Length ?? 0;
|
||||
if (DataLength > 0)
|
||||
Array.Copy(data, 0, DataBuffer, 0, DataLength);
|
||||
CheckForNull();
|
||||
}
|
||||
/// <summary>
|
||||
/// Construction - Data from string.
|
||||
/// <para>Encoding: ASCII</para>
|
||||
/// </summary>
|
||||
public SacsData (string data) :
|
||||
this(data, Encoding.ASCII)
|
||||
{ }
|
||||
/// <summary>Construction - Data from string with specific encoding.</summary>
|
||||
public SacsData (string data, Encoding encoding) :
|
||||
this(encoding.GetBytes(data))
|
||||
{
|
||||
StringEncoding = encoding;
|
||||
}
|
||||
/// <summary>Copy construction.</summary>
|
||||
public SacsData (SacsData data) :
|
||||
this(data.DataBuffer)
|
||||
{
|
||||
StringEncoding = data.StringEncoding;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
/// <summary>Data buffer - cannot be replaced but individual entries can be amended.</summary>
|
||||
public byte[] DataBuffer { get; protected set; } = new byte[0];
|
||||
/// <summary>Length of data may be less than the buffer length.</summary>
|
||||
public int DataLength { get; protected set; }
|
||||
/// <summary>Encoding used to convert data to String.</summary>
|
||||
public Encoding StringEncoding { get; set; } = Encoding.ASCII;
|
||||
/// <summary>Does the data contain null (0x00) values?<para>In which case conversion to String will be invalid.</para></summary>
|
||||
public bool ContainsNull { get; protected set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
private void CheckForNull()
|
||||
{
|
||||
ContainsNull = Array.Exists(DataBuffer, item => item == 0);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Conversion to String.
|
||||
public override String ToString ()
|
||||
{
|
||||
return String.Format(GetType().Name + " [Length: {0}]", DataLength);
|
||||
}
|
||||
public static implicit operator String (SacsData data)
|
||||
{
|
||||
return data.StringEncoding.GetString(data.DataBuffer);
|
||||
}
|
||||
public String NullTerminatedString
|
||||
{
|
||||
get
|
||||
{
|
||||
int nullIdx = Array.IndexOf(DataBuffer,(byte)0);
|
||||
if (nullIdx >= 0)
|
||||
return StringEncoding.GetString(DataBuffer.Take(nullIdx).ToArray());
|
||||
return StringEncoding.GetString(DataBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Append data.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Data
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Legacy basic data encryption.
|
||||
/// <para>Ref. ItemOptions, Session registration</para>
|
||||
/// </summary>
|
||||
public static class SacsDataFn
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private static String acknowledge = "Sarand Software Solutions: www.sarand.com";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// S t r i n g E n c r y p t i o n
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Encrypt string data.</summary>
|
||||
public static String _saecs (String data, SacsData keyData = null)
|
||||
{
|
||||
// Raw data must be a multiple of 3 + 2 in length to allow
|
||||
// for 4 char header and blocks of 3 encoded chars:
|
||||
data = StringUtil.PadRight(data, ((data.Length / 3) * 3) + 2, ' ');
|
||||
// Encrypt the data.
|
||||
SacsData encryptedData = _saecp (new SacsData(data), keyData);
|
||||
// Encode the encrypted data.
|
||||
SacsData encodedData = _saecd (encryptedData.DataBuffer);
|
||||
// Convert the result to a string.
|
||||
String result = (encodedData != null ? (String)encodedData : "");
|
||||
// Return the results.
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Decrypt string data.</summary>
|
||||
public static String _sadcs (String data, SacsData keyData = null)
|
||||
{
|
||||
// Decode the data.
|
||||
SacsData decodedData = _sadcd (new SacsData(data).DataBuffer);
|
||||
// Decrypt the data.
|
||||
SacsData decryptedData = _sadcp (decodedData.DataBuffer, keyData);
|
||||
// Convert to string.
|
||||
String rawData = (decryptedData != null ? (String)decryptedData : "");
|
||||
// Return the results.
|
||||
return rawData.TrimEnd(new char[] { ' ' });
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// E n c r y p t i o n
|
||||
//-------------------------------------------------------------------
|
||||
// Encrypted data includes a header with the following structure:
|
||||
// Bytes 1 & 2 0x5aec "SArand EnCrypted"
|
||||
// Byte 3 bits 0-2 Encryption method (currently only '0' supported).
|
||||
// Byte 4 Reserved.
|
||||
//-------------------------------------------------------------------
|
||||
public static SacsData _saecp (SacsData rawData, SacsData keyData)
|
||||
{
|
||||
// Select encryption parameters.
|
||||
// Dictates which sequence of encryption techniques is used (0 - 7).
|
||||
int encryptMethod = 0;
|
||||
#if DEBUG
|
||||
if (encryptMethod != 0)
|
||||
SaLogger.Warn("_saecp: Unknown enryption method - " + encryptMethod);
|
||||
#endif
|
||||
byte[] encryptedData = null;
|
||||
int encryptedDataLength = 0;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Version 1.0.0 - just use the RC4 method with default key.
|
||||
if (encryptMethod == 0)
|
||||
{
|
||||
SacsData dataRC4 = new SacsData(RC4 (rawData, keyData));
|
||||
encryptedData = dataRC4.DataBuffer;
|
||||
encryptedDataLength = dataRC4.DataLength;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Header length - May differ by encryption method.
|
||||
ushort resultHeaderLength = 4;
|
||||
// Create a buffer for the result.
|
||||
int resultLength = (rawData.DataLength + resultHeaderLength);
|
||||
byte[] resultBuffer = new byte [resultLength];
|
||||
if (encryptMethod == 0)
|
||||
{
|
||||
// First two bytes always the same.
|
||||
// 'SA' = "Sarand".
|
||||
resultBuffer[0] = 0x5a;
|
||||
// 'EC' = "Encrypted".
|
||||
resultBuffer[1] = 0xec;
|
||||
// Next byte holds the encrypt method in the 3 high bits:
|
||||
resultBuffer[2] = (byte)(encryptMethod << 5);
|
||||
resultBuffer[3] = 0;
|
||||
}
|
||||
// Copy the encrypted data to the remaining portion of the buffer.
|
||||
Array.Copy(encryptedData, 0, resultBuffer, resultHeaderLength, encryptedData.Length);
|
||||
// Return data.
|
||||
return new SacsData(resultBuffer);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// D e c r y p t i o n
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Decryot data.</summary>
|
||||
public static SacsData _sadcp (byte[] rawData, SacsData keyData)
|
||||
{
|
||||
// Decode the header.
|
||||
if (rawData == null || rawData.Length == 0)
|
||||
{
|
||||
// No data.
|
||||
return new SacsData();
|
||||
}
|
||||
if (rawData.Length < 4)
|
||||
{
|
||||
SaLogger.Warn("_sadcp Invalid data length: " + rawData.Length + ". Expected multiple of 4.");
|
||||
return new SacsData();
|
||||
}
|
||||
byte headerChar1 = rawData[0];
|
||||
byte headerChar2 = rawData[1];
|
||||
// High 3 bits of header byte #3.
|
||||
int encryptMethod = rawData[2]>>5;
|
||||
// May differ by encryption method.
|
||||
ushort resultHeaderLength = 4;
|
||||
// Verify the encrypted header:
|
||||
if (headerChar1 != 0x5a || headerChar2 != 0xec)
|
||||
{
|
||||
SaLogger.Warn("_sadcp Invalid header.");
|
||||
return new SacsData();
|
||||
}
|
||||
if (encryptMethod != 0)
|
||||
{
|
||||
SaLogger.Warn("_sadcp Invalid encryption method.");
|
||||
return new SacsData();
|
||||
}
|
||||
|
||||
// Decrypt data.
|
||||
SacsData resultData = new SacsData();
|
||||
// Method '0' - simple RC4 decryption.
|
||||
if (encryptMethod == 0)
|
||||
{
|
||||
resultData = RC4(rawData.Skip(resultHeaderLength).ToArray(), keyData);
|
||||
}
|
||||
// Convert the data to the return type:
|
||||
return resultData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// E n c o d i n g
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Encode data.</summary>
|
||||
public static SacsData _saecd (byte[] pData)
|
||||
{
|
||||
// Prepare a buffer for the results.
|
||||
int dataLength = pData.Length;
|
||||
byte[] encodeBuffer = new byte[((dataLength + 2) / 3) * 4];
|
||||
int iBufPos = 0;
|
||||
// Data is encoded in lots of 3 bytes at a time.
|
||||
// Each lot of 3 bytes becoms 4 bytes in the encoded data set:
|
||||
for (uint i = 0; i < dataLength; i += 3)
|
||||
{
|
||||
byte byte0 = pData[i];
|
||||
byte byte1 = (byte)(i < dataLength - 1 ? pData[i+1] : 0);
|
||||
byte byte2 = (byte)(i < dataLength - 2 ? pData[i+2] : 0);
|
||||
// The 3 data bytes are first converted to 4 6-bit values:
|
||||
// Raw: abcdefgh ijklmnop qrstuvwx
|
||||
// Conv: 00abcdef 00ghijkl 00mnopqr 00stuvwx
|
||||
// Each of the resulting 4 bytes is then incremented by 0x20 (ascii code for a space):
|
||||
encodeBuffer[iBufPos++] = ENC(byte0 >> 2); // Byte 1 bits 7-2
|
||||
encodeBuffer[iBufPos++] = ENC((byte0 << 4) & 0x30 | (byte1 >> 4) & 0x0F); // Byte 1 bits 1-0 & Byte 2 bits 7-4
|
||||
encodeBuffer[iBufPos++] = ENC((byte1 << 2) & 0x3C | (byte2 >> 6) & 0x03); // Byte 2 bits 3-0 & Byte 3 bits 7-6
|
||||
encodeBuffer[iBufPos++] = ENC(byte2 & 0x3F); // Byte 3 bits 5-0
|
||||
}
|
||||
SacsData pdEncode = new SacsData(encodeBuffer);
|
||||
return pdEncode;
|
||||
}
|
||||
private static byte ENC (int data)
|
||||
{
|
||||
return (byte)((data & 0x3F) + 0x20/*Space*/);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Decode data.</summary>
|
||||
public static SacsData _sadcd (byte[] rawData)
|
||||
{
|
||||
// The encoded data must be a multiple of 4 bytes.
|
||||
if (rawData == null || rawData.Length % 4 != 0)
|
||||
{
|
||||
SaLogger.Warn("_sadcd Data is not a multiple of 4 bytes. Length: " + (rawData?.Length ?? 0));
|
||||
return new SacsData();
|
||||
}
|
||||
// Prepare a buffer for the results.
|
||||
byte[] resultsBuffer = new byte[rawData.Length / 4 * 3];
|
||||
int bufferIdx = 0;
|
||||
// Iterate through the encoded data in blocks of four bytes.
|
||||
for (uint idx = 0; idx < rawData.Length; idx += 4)
|
||||
{
|
||||
byte p = rawData[idx];
|
||||
int c1 = (DEC(rawData[idx+0]) << 2) | (DEC(rawData[idx+1]) >> 4);
|
||||
#if DEBUG
|
||||
int z = rawData[idx+1];
|
||||
z = DEC(z);
|
||||
z = z << 4;
|
||||
z = rawData[idx + 2];
|
||||
z = DEC(z);
|
||||
z = z >> 2;
|
||||
z = (DEC(rawData[idx + 1]) << 4) | (DEC(rawData[idx + 2]) >> 2);
|
||||
#endif
|
||||
int c2 = (DEC(rawData[idx+1]) << 4) | (DEC(rawData[idx+2]) >> 2);
|
||||
int c3 = (DEC(rawData[idx+2]) << 6) | DEC(rawData[idx+3]);
|
||||
resultsBuffer[bufferIdx++] = (byte)c1;
|
||||
resultsBuffer[bufferIdx++] = (byte)c2;
|
||||
resultsBuffer[bufferIdx++] = (byte)c3;
|
||||
}
|
||||
return new SacsData(resultsBuffer);
|
||||
}
|
||||
private static byte DEC (int data)
|
||||
{
|
||||
#if DEBUG
|
||||
int z = data - 0x20;
|
||||
z = z & 0x3F;
|
||||
#endif
|
||||
return (byte)((data - 0x20/*Space*/) & 0x3F);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R C 4 E n c r y p t i o n
|
||||
//-------------------------------------------------------------------
|
||||
// www.systweak.com & www.codeproject.com/cpp/crypt_routine.asp
|
||||
// This Crypt routine uses an algorithm created by Rodney Thayer.
|
||||
// This algorithm can use keys of various sizes.
|
||||
// With a 40-bit key (5 characters) it can be freely exported from the U.S.
|
||||
// The cipher is considered robust with 128 bits of key material but can use up to 2048 bits.
|
||||
// It is compatible with RSA’s RC4 algorithm.
|
||||
//---------------------------------------------------------------------------
|
||||
// The only moral here is that we are generating a 256 bit key given from the user. To encrypt we always pick a random byte from the key and encrypt the text with that key. If we have a large pattern of repeating text with this algorithm the key repeat interval (distance between n repetitions) will be approximately of 21700 (2 to the 1700th power).
|
||||
// For very good security I recommend using 128 bits (16 characters) of key material. If you want optimal security you could use 2048 bits (256 characters) of key material (but this is usually considered an overkill).
|
||||
// This routine is constructed from a draft taken from Internet Engineering Task Force (IETF) at http://www.ietf.cnri.reston.va.us/home.htm
|
||||
// I have tested the routine on a 27 MB file to test that it produce valid decrypted output from input and get the valid results.
|
||||
// We do not enter the key so we will be using default key provide by the crypt routine:
|
||||
// TCHAR HelloCrypt[] = "Hello Crypt";
|
||||
// Encrypt: Crypt(HelloCrypt, _tcslen(HelloCrypt));
|
||||
// Decrypt: Crypt(HelloCrypt, _tcslen(HelloCrypt));
|
||||
// If we have to supply a key we have to use crypt as follows:
|
||||
// TCHAR Data[] = "abcdefghijklmnopqrstuvwxyz"
|
||||
// TCHAR Key[] = "Strong key";
|
||||
// Encrypt: Crypt(Data, _tcslen(Data), Key, _tcslen(Data));
|
||||
// Decrypt: Crypt(Data, _tcslen(Data), Key, _tcslen(Data));
|
||||
//---------------------------------------------------------------------------
|
||||
internal static SacsData RC4 (SacsData dataRaw, SacsData keyData)
|
||||
{
|
||||
return RC4(dataRaw.DataBuffer, keyData != null ? keyData.DataBuffer : null);
|
||||
}
|
||||
internal static SacsData RC4 (byte[] rawData, SacsData keyData)
|
||||
{
|
||||
return RC4(rawData, keyData != null ? keyData.DataBuffer : null);
|
||||
}
|
||||
public static SacsData RC4 (byte[] rawData, byte[] userKey = null)
|
||||
{
|
||||
// Key buffers (256 bytes = 1024 bits):
|
||||
byte[] keyBuffer = new byte[257];
|
||||
Array.Clear(keyBuffer, 0, keyBuffer.Length);
|
||||
|
||||
// Initialize the key buffer.
|
||||
for (int keyIdx = 0; keyIdx <= 255U; keyIdx++)
|
||||
keyBuffer[keyIdx] = (byte)keyIdx;
|
||||
|
||||
// Either use the specific key supplied, or the default (unsecured) key:
|
||||
byte[] keyData = Encoding.ASCII.GetBytes(acknowledge);
|
||||
int keyLength = StringUtil.GetLength(acknowledge);
|
||||
if (userKey != null && userKey.Length > 0)
|
||||
{
|
||||
keyData = userKey;
|
||||
keyLength = userKey.Length;
|
||||
}
|
||||
// Scramble this raw key into the key buffer.
|
||||
uint rootKeyIdx = 0;
|
||||
for (int dataIdx = 0; dataIdx < 256; dataIdx++)
|
||||
{
|
||||
// Position in the root key.
|
||||
rootKeyIdx = (rootKeyIdx + (uint)keyBuffer[dataIdx] + keyData[dataIdx % keyLength]) % 256U;
|
||||
byte temp = keyBuffer[dataIdx];
|
||||
keyBuffer[dataIdx] = keyBuffer[rootKeyIdx];
|
||||
keyBuffer[rootKeyIdx] = temp;
|
||||
}
|
||||
#if DEBUG_X
|
||||
// Retrieve the contents of the key buffer in a readable form.
|
||||
String key = "";
|
||||
for (int keyBufferIdx = 0; keyBufferIdx <= 12; keyBufferIdx++) key += ((char)keyBuffer[keyBufferIdx]).ToString() + ".";
|
||||
#endif
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
// Create a buffer for the encrypted data:
|
||||
byte[]resultData = new byte [rawData.Length];
|
||||
for (uint x = 0; x < rawData.Length; x++)
|
||||
{
|
||||
// Increment i.
|
||||
i = (int)((i + 1U) % 256U);
|
||||
// Increment j.
|
||||
j = (int)((j + (uint)keyBuffer[i]) % 256U);
|
||||
// Scramble pKeyBuf #1 further so encryption routine will only repeat itself at great interval.
|
||||
byte temp = keyBuffer[i];
|
||||
keyBuffer[i] = keyBuffer[j];
|
||||
keyBuffer[j] = temp;
|
||||
// Get ready to create pseudo random byte for encryption key.
|
||||
int t = (int)(((int) keyBuffer[i] + (int)keyBuffer[j]) % 256U);
|
||||
// Get the target byte:
|
||||
byte k = keyBuffer[t];
|
||||
// Xor with the data and done:
|
||||
byte raw = rawData[x];
|
||||
resultData[x] = (byte)(raw ^ k);
|
||||
}
|
||||
// Create the return value.
|
||||
return new SacsData(resultData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Data
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SacsShaHasher
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public static String ShaSaltDelim { get; } = ":";
|
||||
public static String Sha256Prefix { get; } = "Sha256:";
|
||||
public static String Sha384Prefix { get; } = "Sha384:";
|
||||
public static String Sha512Prefix { get; } = "Sha512:";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ref. https://xamarinhelp.com/cryptography-in-xamarin-forms/
|
||||
// Hash Salt.
|
||||
// To add a salt to the hash, append the Salt (random string) to the value.
|
||||
// The Salt can be stored with the hashed value.
|
||||
// Salts do not need to be kept secret and should be different for each hash.
|
||||
// This is to reduce the impact of pre-built hash tables, eg. where common passwords (‘password’) generate the same Hash.
|
||||
// It also stops the same password generating the identical Hash for 2 different accounts.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Non-reversible encryption.
|
||||
/// <para>Result is converted to Base64 string to ensure that all bytes are properly recorded, as UTF8 doesn’t have an exact byte match for each possible byte sequence.</para>
|
||||
/// <para>Algorythm must be dispoed by calling routine.</para>
|
||||
/// </summary>
|
||||
public static string HashString (this string value, HashAlgorithm algorythm)
|
||||
{
|
||||
return Convert.ToBase64String(algorythm.ComputeHash(System.Text.Encoding.UTF8.GetBytes(value)));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Non-reversible encryption using Sha256.
|
||||
/// <para>Result is converted to Base64 string to ensure that all bytes are properly recorded, as UTF8 doesn’t have an exact byte match for each possible byte sequence.</para>
|
||||
/// </summary>
|
||||
public static string HashSha256 (this string value)
|
||||
{
|
||||
using (HashAlgorithm algorythm = SHA256.Create())
|
||||
{
|
||||
return HashString(value, algorythm);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Non-reversible encryption using Sha384.
|
||||
/// <para>Result is converted to Base64 string to ensure that all bytes are properly recorded, as UTF8 doesn’t have an exact byte match for each possible byte sequence.</para>
|
||||
/// </summary>
|
||||
public static string HashSha384 (this string value)
|
||||
{
|
||||
using (HashAlgorithm algorythm = SHA384.Create())
|
||||
{
|
||||
return HashString(value, algorythm);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Non-reversible encryption using Sha512.
|
||||
/// <para>Result is converted to Base64 string to ensure that all bytes are properly recorded, as UTF8 doesn’t have an exact byte match for each possible byte sequence.</para>
|
||||
/// </summary>
|
||||
public static string HashSha512 (this string value)
|
||||
{
|
||||
using (HashAlgorithm algorythm = SHA512.Create())
|
||||
{
|
||||
return HashString(value, algorythm);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
Reference in New Issue
Block a user