// @file MySecret.cs
// @version 4.0.1a (2026-03-16T09:17Z)
// @author David Ireland <https://cryptosys.net/contact>
// @copyright 2007-26 DI Management Services Pty Ltd
// @license Apache-2.0
using System;
using System.Text;
using System.Diagnostics;
using CryptoSysAPI;
/*
Requires CryptoSys API to be installed on your system.
Available from <https://cryptosys.net/api.html>
* EITHER include `CryptoSysAPI.cs` in this project
* OR add a Reference to `diCrSysAPINet.dll` which should have been installed in
* `C:\Program Files (x86)\CryptoSys\DotNet`.
*/
namespace MySecretForm
{
/// <summary>
/// MySecret crypto functions
/// </summary>
public class MySecret
{
// Internal constants
private const int BLOCK_LEN = 8;
private const int FRAME_LEN = 60;
private const string FRAME_BEGIN = "-----BEGIN MYSECRET-----";
private const string FRAME_END = "-----END MYSECRET-----";
private const string FRAME_STUB = "-----BEGIN MYSECRET";
public static int CrSysVersion()
{
return General.Version();
}
public static string MySecretEncryptV4(string strPlain, string strPassword)
{
// INPUT: plaintext string, password
// OUTPUT: string of MySecret v4 base64-encoded ciphertext (with framing and CR-LFs)
const int hdrlen = 4;
const int crclen = 4;
const int zhlen = 10;
const int zval = 0x05;
const int ivlen = 12;
const int rblock_len = 8;
if (string.IsNullOrEmpty(strPlain)) {
Debug.WriteLine("ERROR: nothing to encrypt!");
return string.Empty;
}
Debug.WriteLine("PLAINTEXT: [" + strPlain + "]");
// CONVERT input string to byte array
byte[] abPlain = Encoding.GetEncoding("UTF-8").GetBytes(strPlain);
int nPlain = abPlain.Length;
Debug.WriteLine("Plaintext length = " + nPlain + " bytes");
// COMPUTE THE CRC-32 CHECKSUM of the original plaintext
uint nCrc32 = (uint)Crc.Data(abPlain);
Debug.WriteLine("CRC-32 = " + nCrc32.ToString("X"));
// COMPRESS using ZLIB_Deflate function
byte[] abCompr = Zlib.Deflate(abPlain);
if (abCompr == null || abCompr.Length <= 0) {
Debug.WriteLine("ERROR: compression failed.");
return string.Empty;
}
int cmplen = abCompr.Length;
Debug.WriteLine("Compressed length = " + cmplen + " bytes");
// CREATE A PADDING STRING OF COMPLETELY RANDOM BYTES [8-71] bytes long
int k = Rng.Number(0, 7);
int r = Rng.Number(0, 7);
int padlen = (k + 1) * rblock_len + r;
Debug.WriteLine("Padding string = " + padlen + " bytes = 0x" + padlen.ToString("X"));
byte[] abPad = Rng.NonceBytes(padlen);
// COMPOSE the encryption block
int blklen = zhlen + cmplen + crclen + padlen;
byte[] abBlock = new byte[blklen];
abBlock[0] = 0x5A; // 'Z'
abBlock[1] = zval;
int iOffset = 2;
// Add CLEN (4 bytes, big-endian)
byte[] abNumber = EncodeInt4((uint)cmplen);
Array.Copy(abNumber, 0, abBlock, iOffset, 4);
iOffset += 4;
// Add ULEN (4 bytes, big-endian)
abNumber = EncodeInt4((uint)nPlain);
Array.Copy(abNumber, 0, abBlock, iOffset, 4);
iOffset += 4;
// Add compressed data
Array.Copy(abCompr, 0, abBlock, iOffset, cmplen);
iOffset += cmplen;
Wipe.Data(abCompr);
// Add CRC-32 (4 bytes)
abNumber = EncodeInt4(nCrc32);
Array.Copy(abNumber, 0, abBlock, iOffset, crclen);
iOffset += crclen;
Wipe.Data(abNumber);
// Add padding
Array.Copy(abPad, 0, abBlock, iOffset, padlen);
Debug.WriteLine("BLK=" + Cnv.ToHex(abBlock));
Wipe.Data(abPad);
// GENERATE a random initialization vector (12-byte nonce)
byte[] abInitVec = Rng.NonceBytes(ivlen);
Debug.WriteLine("IV=" + Cnv.ToHex(abInitVec));
// CREATE the 256-bit key using stretching with the IV as salt
byte[] abKey = MakeStretchedKeyV4(strPassword, abInitVec);
Debug.WriteLine("KEY=" + Cnv.ToHex(abKey));
// ENCRYPT THE BLOCK using CHACHA20-POLY1305
// NB the output is 16 bytes longer than the input (blklen+taglen)
abBlock = Aead.EncryptWithTag(abBlock, abKey, abInitVec, Aead.Algorithm.Chacha20_Poly1305);
Wipe.Data(abKey);
if (abBlock.Length == 0) {
Debug.WriteLine("ERROR: encryption operation failed!");
return string.Empty;
}
Debug.WriteLine("ENC=" + Cnv.ToHex(abBlock));
// ADD THE MAIN HEADER to the ciphertext block
byte[] abEncode = new byte[hdrlen + ivlen + abBlock.Length];
abEncode[0] = 0x4D; // "M"
abEncode[1] = 0x59; // "Y"
abEncode[2] = 0xFB; // v4
abEncode[3] = 0x00;
iOffset = hdrlen;
Array.Copy(abInitVec, 0, abEncode, iOffset, ivlen);
iOffset += ivlen;
Array.Copy(abBlock, 0, abEncode, iOffset, abBlock.Length);
Debug.WriteLine("TOB64=" + Cnv.ToHex(abEncode));
// ENCODE TO BASE 64
string strBase64 = Convert.ToBase64String(abEncode);
// ADD FRAMING AND LINE-BREAKS every 60 chars
string strOutput = FRAME_BEGIN + Environment.NewLine;
int nChars = strBase64.Length;
iOffset = 0;
while (nChars > FRAME_LEN) {
strOutput += strBase64.Substring(iOffset, FRAME_LEN) + Environment.NewLine;
nChars -= FRAME_LEN;
iOffset += FRAME_LEN;
}
// Append final line, if any
if (nChars > 0) {
strOutput += strBase64.Substring(iOffset, nChars) + Environment.NewLine;
}
strOutput += FRAME_END + Environment.NewLine;
return strOutput;
}
public static string MySecretDecryptV4(byte[] abEncode, string strPassword)
{
// INPUT: password, Encoded byte array data already checked for v4 signature
// OUTPUT: decrypted plaintext string or empty string on error
const int hdrlen = 4;
const int zhlen = 10;
const int zval = 0x05;
const int ivlen = 12;
/*
|<-zhlen------------->|<--cmplen---------->|crclen|<-padlen>|
+-----+-------+-------+--------------------+------+---------+
|ZS(2)|CLEN(4)|ULEN(4)| Compressed data... |CRC(4)|PAD(8-71)|
+-----+-------+-------+--------------------+------+---------+
|<----------------------(encrypt this)--------------------->|<-taglen>|
+------+--------+-----------------------------------------------------------+---------+
|SIG(4)| IV(12) | Ciphertext... | TAG(16) |
+------+--------+-----------------------------------------------------------+---------+
|hdrlen|<-ivlen>|<------------blklen------------------------------------------------->|
|<--encodlen------------------------------------------------------------------------->|
*/
int encodlen = abEncode.Length;
Debug.WriteLine("Encoded data = " + encodlen + " bytes");
int offset = hdrlen;
// Copy the 12-byte nonce (IV)
byte[] abInitVec = new byte[ivlen];
Array.Copy(abEncode, offset, abInitVec, 0, ivlen);
Debug.WriteLine("IV=" + Cnv.ToHex(abInitVec));
// RE-CREATE THE KEY
byte[] abKey = MakeStretchedKeyV4(strPassword, abInitVec);
Debug.WriteLine("KEY=" + Cnv.ToHex(abKey));
// Copy the decryption block *including* the tag
offset += ivlen;
int blklen = encodlen - offset;
byte[] abBlock = new byte[blklen];
Array.Copy(abEncode, offset, abBlock, 0, blklen);
// DECRYPT the entire block including the TAG - this will fail if the TAG is invalid
abBlock = Aead.DecryptWithTag(abBlock, abKey, abInitVec, Aead.Algorithm.Chacha20_Poly1305);
Wipe.Data(abKey);
if (abBlock.Length == 0) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// PARSE the v4 block: expecting 'Z' and 0x05
if (abBlock[0] != 0x5A || abBlock[1] != zval) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// EXTRACT lengths from big-endian-encoded values
offset = 2;
uint cmplen = DecodeInt4(abBlock[offset], abBlock[offset + 1], abBlock[offset + 2], abBlock[offset + 3]);
offset = 6;
uint ptlen = DecodeInt4(abBlock[offset], abBlock[offset + 1], abBlock[offset + 2], abBlock[offset + 3]);
Debug.WriteLine("Compressed length=" + cmplen + ", Uncompressed length=" + ptlen);
// CHECK for reasonableness
if (cmplen >= int.MaxValue || ptlen >= int.MaxValue || cmplen > blklen) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// EXTRACT the 4-byte CRC-32 value
offset = zhlen + (int)cmplen;
uint crc_chk = DecodeInt4(abBlock[offset], abBlock[offset + 1], abBlock[offset + 2], abBlock[offset + 3]);
Debug.WriteLine("CRC-32 value found = " + crc_chk.ToString("X"));
// DECOMPRESS/INFLATE the plaintext
byte[] abCompr = new byte[cmplen];
Array.Copy(abBlock, zhlen, abCompr, 0, cmplen);
byte[] abPlain = Zlib.Inflate(abCompr);
if (abPlain == null || abPlain.Length < ptlen) {
Debug.WriteLine("ERROR: Decryption error (inflate failed).");
return string.Empty;
}
// COMPUTE the CRC-32 checksum for the recovered plaintext
uint crc32 = (uint)Crc.Data(abPlain);
Debug.WriteLine("CRC-32 = " + crc32.ToString("X"));
// VERIFY that the checksums match
if (crc32 != crc_chk) {
Debug.WriteLine("ERROR: Decryption error (CRC checksum failed).");
return string.Empty;
}
// DECODE the byte array to an output string
return Encoding.GetEncoding("UTF-8").GetString(abPlain);
}
public static string MySecretDecrypt(string strInput, string strPassword)
{
// INPUT: password, string of MySecret v3 or v4 base64-encoded ciphertext
// OUTPUT: decrypted plaintext string or empty string on error
if (string.IsNullOrEmpty(strInput)) {
Debug.WriteLine("ERROR: nothing to decrypt!");
return string.Empty;
}
Debug.WriteLine("Input = " + strInput.Length + " bytes");
// REMOVE FRAMING, get base64 data
int nBeg = strInput.IndexOf(FRAME_STUB);
if (nBeg < 0) {
Debug.WriteLine("ERROR: Not valid MySecret data!");
return string.Empty;
}
nBeg = nBeg + FRAME_STUB.Length;
nBeg = strInput.IndexOf("-", nBeg);
while (nBeg > 0 && nBeg < strInput.Length && strInput[nBeg] == '-') {
nBeg++;
}
if (nBeg >= strInput.Length) {
Debug.WriteLine("ERROR: Not valid MySecret data!");
return string.Empty;
}
int nEnd = strInput.IndexOf(FRAME_END, nBeg);
if (nEnd <= 0 || nEnd <= nBeg) {
Debug.WriteLine("ERROR: Not valid MySecret data!");
return string.Empty;
}
string strBase64 = strInput.Substring(nBeg, nEnd - nBeg);
Debug.WriteLine("Base64=" + strBase64);
// DECODE BASE64 to byte array
byte[] abEncode = Cnv.FromBase64(strBase64);
int nEncode = abEncode.Length;
Debug.WriteLine("Encoded data = " + nEncode + " bytes");
// Check signature
if (nEncode < 15 || abEncode[0] != 0x4D || abEncode[1] != 0x59 || abEncode[3] != 0x00) {
Debug.WriteLine("ERROR: Not MySecret data.");
return string.Empty;
}
if (abEncode[2] == 0xFB) {
Debug.WriteLine("Found MYSECRET signature for version 4");
return MySecretDecryptV4(abEncode, strPassword);
}
else if (abEncode[2] != 0xFC) {
Debug.WriteLine("ERROR: Sorry, we only decrypt versions 3 or 4.");
return string.Empty;
}
// We have v3 data
Debug.WriteLine("Found MYSECRET signature for version 3");
// Copy the 8-byte IV
byte[] abInitVec = new byte[BLOCK_LEN];
Array.Copy(abEncode, 4, abInitVec, 0, BLOCK_LEN);
Debug.WriteLine("IV=" + Cnv.ToHex(abInitVec));
// RE-CREATE THE KEY
byte[] abKey = MakeStretchedKeyV3(strPassword, abInitVec, BLOCK_LEN);
Debug.WriteLine("KEY=" + Cnv.ToHex(abKey));
// Copy the decryption block
int iOffset = BLOCK_LEN + 4;
int nBlock = nEncode - iOffset;
byte[] abBlock = new byte[nBlock];
Array.Copy(abEncode, iOffset, abBlock, 0, nBlock);
// DECRYPT the entire block
abBlock = Blowfish.Decrypt(abBlock, abKey, Mode.CBC, abInitVec);
Wipe.Data(abKey);
if (abBlock.Length == 0) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// PARSE the v3 block
if (abBlock[0] != 0x5A || abBlock[1] != 0x04) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// EXTRACT lengths from big-endian-encoded values
iOffset = 2;
UInt32 nCompr = DecodeInt4(abBlock[iOffset], abBlock[iOffset + 1], abBlock[iOffset + 2], abBlock[iOffset + 3]);
iOffset = 6;
UInt32 nPlain = DecodeInt4(abBlock[iOffset], abBlock[iOffset + 1], abBlock[iOffset + 2], abBlock[iOffset + 3]);
Debug.WriteLine("Compressed length=" + nCompr + ", Uncompressed length=" + nPlain);
// CHECK for reasonableness
if (nCompr < 0 || nPlain < 0 || nCompr > nBlock) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// EXTRACT length of padding string
int nPad = abBlock[nBlock - 1];
Debug.WriteLine("Padding string is " + nPad + " bytes");
// CONFIRM all lengths now match
if (nBlock != 10 + nCompr + 3 + nPad) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
// CHECK GUARD BYTES
iOffset = nBlock - nPad;
for (int i = 0; i < 8; i++) {
if (abBlock[iOffset + i] != (byte)nPad) {
Debug.WriteLine("ERROR: Decryption error.");
return string.Empty;
}
}
// EXTRACT the 3-byte CRC-24 value
iOffset = nBlock - nPad - 3;
long nCrcChk = DecodeInt4(0x00, abBlock[iOffset], abBlock[iOffset + 1], abBlock[iOffset + 2]);
Debug.WriteLine("CRC-24 value found = " + nCrcChk.ToString("X"));
// DECOMPRESS the plaintext
byte[] abCompr = new byte[nCompr];
Array.Copy(abBlock, 10, abCompr, 0, nCompr);
byte[] abPlain = Zlib.Inflate(abCompr);
if (abPlain == null || abPlain.Length < nPlain) {
Debug.WriteLine("ERROR: Decryption error (inflate failed).");
return string.Empty;
}
// COMPUTE the CRC-24 checksum for the recovered plaintext
long nCrc24 = CRC24_Bytes(abPlain);
Debug.WriteLine("CRC-24 = " + nCrc24.ToString("X"));
// VERIFY that the checksums match
if (nCrc24 != nCrcChk) {
Debug.WriteLine("ERROR: Decryption error (CRC checksum failed).");
return string.Empty;
}
// DECODE the byte array to an output string
return Encoding.GetEncoding("UTF-8").GetString(abPlain);
}
public static string MySecretEncryptV3(string strPlain, string strPassword)
{
// INPUT: plaintext string, password
// OUTPUT: string of MySecret v3 base64-encoded ciphertext (with framing and CR-LFs)
if (string.IsNullOrEmpty(strPlain)) {
Debug.WriteLine("ERROR: nothing to encrypt!");
return string.Empty;
}
Debug.WriteLine("PLAINTEXT: [" + strPlain + "]");
// CONVERT input string to byte array
byte[] abPlain = Encoding.GetEncoding("UTF-8").GetBytes(strPlain);
int nPlain = abPlain.Length;
Debug.WriteLine("Plaintext length = " + nPlain + " bytes");
// COMPUTE THE CRC-24 CHECKSUM of the original plaintext
uint nCrc24 = CRC24_Bytes(abPlain);
Debug.WriteLine("CRC-24 = " + nCrc24.ToString("X"));
// COMPRESS using ZLIB_Deflate function
byte[] abCompr = Zlib.Deflate(abPlain);
if (abCompr == null || abCompr.Length <= 0) {
Debug.WriteLine("ERROR: compression failed.");
return string.Empty;
}
int nCompr = abCompr.Length;
Debug.WriteLine("Compressed length = " + nCompr + " bytes");
// CREATE A PADDING STRING
int nPad = BLOCK_LEN - (10 + nCompr + 3) % BLOCK_LEN;
int k = Rng.Number(0, 7);
Debug.WriteLine("Random blocks = " + k);
nPad = nPad + (k + 1) * BLOCK_LEN;
Debug.WriteLine("Padding string = " + nPad + " bytes = 0x" + nPad.ToString("X"));
byte[] abPad = Rng.NonceBytes(nPad);
// Set value of bytes in guard and final blocks equal to NPAD
for (int i = 0; i < 8; i++) {
abPad[i] = (byte)nPad;
}
for (int i = ((k + 1) * BLOCK_LEN); i < nPad; i++) {
abPad[i] = (byte)nPad;
}
// COMPOSE the encryption block
int nBlock = 10 + nCompr + 3 + nPad;
Debug.WriteLine("Encryption block = " + nBlock + " bytes = " + (nBlock / BLOCK_LEN) + " blocks");
byte[] abBlock = new byte[nBlock];
abBlock[0] = 0x5A; // 'Z'
abBlock[1] = 0x04;
int iOffset = 2;
// Add CLEN (4 bytes, big-endian)
byte[] abNumber = EncodeInt4((uint)nCompr);
Array.Copy(abNumber, 0, abBlock, iOffset, 4);
iOffset += 4;
// Add ULEN (4 bytes, big-endian)
abNumber = EncodeInt4((uint)nPlain);
Array.Copy(abNumber, 0, abBlock, iOffset, 4);
iOffset += 4;
// Add compressed data
Array.Copy(abCompr, 0, abBlock, iOffset, nCompr);
iOffset += nCompr;
Wipe.Data(abCompr);
// Add CRC-24 (3 bytes)
abNumber = EncodeInt4(nCrc24);
Array.Copy(abNumber, 1, abBlock, iOffset, 3);
iOffset += 3;
Wipe.Data(abNumber);
// Add padding
Array.Copy(abPad, 0, abBlock, iOffset, nPad);
Wipe.Data(abPad);
// GENERATE a random 8-byte initialization vector
byte[] abInitVec = Rng.NonceBytes(BLOCK_LEN);
Debug.WriteLine("IV (hex)=" + Cnv.ToHex(abInitVec));
// CREATE the 128-bit key using stretching with the IV as salt
byte[] abKey = MakeStretchedKeyV3(strPassword, abInitVec, BLOCK_LEN);
Debug.WriteLine("KEY (hex)=" + Cnv.ToHex(abKey));
// ENCRYPT THE BLOCK using Blowfish in CBC mode
abBlock = Blowfish.Encrypt(abBlock, abKey, Mode.CBC, abInitVec);
Wipe.Data(abKey);
if (abBlock.Length == 0) {
Debug.WriteLine("ERROR: encryption operation failed!");
return string.Empty;
}
// ADD THE MAIN HEADER to the ciphertext block
byte[] abEncode = new byte[4 + BLOCK_LEN + nBlock];
abEncode[0] = 0x4D; // "M"
abEncode[1] = 0x59; // "Y"
abEncode[2] = 0xFC; // v3
abEncode[3] = 0x00;
iOffset = 4;
Array.Copy(abInitVec, 0, abEncode, iOffset, BLOCK_LEN);
iOffset += BLOCK_LEN;
Array.Copy(abBlock, 0, abEncode, iOffset, nBlock);
int nEncode = 4 + BLOCK_LEN + nBlock;
// ENCODE TO BASE 64
string strBase64 = Convert.ToBase64String(abEncode);
// ADD FRAMING AND LINE-BREAKS every 60 chars
string strOutput = FRAME_BEGIN + Environment.NewLine;
int nChars = strBase64.Length;
iOffset = 0;
while (nChars > FRAME_LEN) {
strOutput += strBase64.Substring(iOffset, FRAME_LEN) + Environment.NewLine;
nChars -= FRAME_LEN;
iOffset += FRAME_LEN;
}
// Append final line, if any
if (nChars > 0) {
strOutput += strBase64.Substring(iOffset, nChars) + Environment.NewLine;
}
strOutput += FRAME_END + Environment.NewLine;
return strOutput;
}
// ******************
// INTERNAL FUNCTIONS
// ******************
/// <summary>
/// Make stretched key for v3 (using MD5)
/// </summary>
/// <param name="strPassword"></param>
/// <param name="abSalt"></param>
/// <returns>16-byte key</returns>
private static byte[] MakeStretchedKeyV3(string strPassword, byte[] abSalt, int nSalt)
{
const int nKey = 16; // 128-bit key
const int stretch_count = 1024;
byte[] abPassword = Encoding.GetEncoding("UTF-8").GetBytes(strPassword);
int nPassword = abPassword.Length;
// X(1) = MD5(p || s)
byte[] abTemp = new byte[nPassword + nSalt];
Array.Copy(abPassword, 0, abTemp, 0, nPassword);
Array.Copy(abSalt, 0, abTemp, nPassword, nSalt);
byte[] abDigest = Md5.BytesHash(abTemp);
// For i = 2 to STRETCH_COUNT, set X(i) = MD5(X(i-1) || p || s)
abTemp = new byte[abDigest.Length + nPassword + nSalt];
for (int iCount = 2; iCount <= stretch_count; iCount++) {
int iOffset = 0;
Array.Copy(abDigest, 0, abTemp, iOffset, abDigest.Length);
iOffset += abDigest.Length;
Array.Copy(abPassword, 0, abTemp, iOffset, nPassword);
iOffset += nPassword;
Array.Copy(abSalt, 0, abTemp, iOffset, nSalt);
abDigest = Md5.BytesHash(abTemp);
}
byte[] abKey = new byte[nKey];
Array.Copy(abDigest, 0, abKey, 0, nKey);
return abKey;
}
/// <summary>
/// Compute a four-byte encoding of the integer i, most significant byte first
/// </summary>
/// <param name="iInput">Integer to be encoded</param>
/// <returns>Byte array of 4 bytes</returns>
private static byte[] EncodeInt4(uint iInput)
{
byte[] encoded = new byte[4];
for (int i = 3; i >= 0; i--) {
encoded[i] = (byte)(iInput & 0xFF);
iInput >>= 8;
}
return encoded;
}
// Interpret a 4-byte input and decode to a big-endian 32-bit unsigned integer
public static uint DecodeInt4(byte b0, byte b1, byte b2, byte b3)
{
return (uint)((b0 << 24) | (b1 << 16) | (b2 << 8) | b3);
}
/// <summary>
/// Make stretched key for v4 (using SHA-256)
/// </summary>
/// <param name="strPassword"></param>
/// <param name="abSalt"></param>
/// <returns>32-byte k</returns>
private static byte[] MakeStretchedKeyV4(string strPassword, byte[] abSalt)
{
const int keylen = 32; // 256-bit key
const int stretch_count = 2048;
Hash oHash = Hash.Instance();
uint counter;
byte[] ctrbytes;
byte[] digest;
byte[] abPassword = Encoding.GetEncoding("UTF-8").GetBytes(strPassword);
// X(1) = H(p || s || INT(1))
counter = 1;
ctrbytes = EncodeInt4(counter);
oHash.Init(HashAlgorithm.Sha256);
oHash.AddData(abPassword);
oHash.AddData(abSalt);
oHash.AddData(ctrbytes);
digest = oHash.Final();
// For i = 2 to STRETCH_COUNT_V4, set
// X(i) = H(X(i-1) || p || s || INT(i))
for (counter = 2; counter <= stretch_count; counter++) {
ctrbytes = EncodeInt4(counter);
oHash.Init(HashAlgorithm.Sha256);
oHash.AddData(digest);
oHash.AddData(abPassword);
oHash.AddData(abSalt);
oHash.AddData(ctrbytes);
digest = oHash.Final();
}
byte[] abKey = new byte[keylen];
Array.Copy(digest, 0, abKey, 0, keylen);
// Clean up
Wipe.Data(digest);
Wipe.Data(abPassword);
return abKey;
}
// CRC-24 Implementation (for v3)
public static uint CRC24_Bytes(byte[] abMessage)
{
const uint CRC24_INIT = 0xB704CE;
const uint CRC24_POLY = 0x1864CFB;
uint ulCRC = CRC24_INIT;
foreach (byte b in abMessage) {
ulCRC = ulCRC ^ ((uint)b << 16);
for (int j = 0; j < 8; j++) {
ulCRC = ulCRC << 1;
if ((ulCRC & 0x1000000) != 0)
ulCRC = ulCRC ^ CRC24_POLY;
}
}
return ulCRC & 0xFFFFFF;
}
}
}