Created
June 24, 2019 10:35
-
-
Save kronoc/c669eb8cceece1ea7f7ce3f964c511ee to your computer and use it in GitHub Desktop.
meteotime decoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Cipher=[0]101111[0]00 0xBC 10101101 0xAD 01101001 0x69 11101001 0xE9 10010011 0x93 | |
flip = 00111101 0x3D 10110101 0xB5 10010110 0x96 10010111 0x97 11001001 0xC9 | |
<-- This is Meteotime DES cypher | |
Key = 01000000 0x40 00000000 0x00 00001100 0xC0 00100100 0x24 01001000 0x48 | |
Key flip = 00010010 0x12 00100100 0x24 00110000 0x30 00000000 0x00 00000010 0x02 | |
<-- This is Meteotime DES key | |
http://arduino-projects4u.com/meteotime/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
namespace MeteoCoder | |
{ | |
/// <summary> | |
/// Enthält alle Funktionen zum Verschlüsseln und Entschlüsseln der via DCF77 übertragenen Wetterdaten. | |
/// Quelle: meteocrypt_working.c | |
/// </summary> | |
public class DeEnCoder | |
{ | |
#region Deklarationen, Secrets, Sboxes, etc. | |
/// <summary> | |
/// Container zum Konvertieren zwischen 4 Bytes und Uint. | |
/// </summary> | |
[StructLayout(LayoutKind.Explicit)] | |
private struct ByteUInt | |
{ | |
[FieldOffset(0)] | |
public byte Byte0; | |
[FieldOffset(1)] | |
public byte Byte1; | |
[FieldOffset(2)] | |
public byte Byte2; | |
[FieldOffset(3)] | |
public byte Byte3; | |
[FieldOffset(0)] | |
public uint FullUint; | |
} | |
/// <summary> | |
/// Container zum schnellen Zusammenfassen und Trennen von Key und Cipher. | |
/// </summary> | |
[StructLayout(LayoutKind.Explicit)] | |
unsafe private struct CipherKeyContainer | |
{ | |
[FieldOffset(0)] | |
public fixed byte AllBytes[10];// = new Byte[10]; | |
[FieldOffset(0)] | |
public fixed byte CipherBytes[5];// = new Byte[5]; | |
[FieldOffset(5)] | |
public fixed byte KeyBytes[5];// = new Byte[5]; | |
} | |
/// <summary> | |
/// bit pattern for 0D,0E from 0B-0D | |
/// </summary> | |
private uint[] mUintArrBitPattern12 = new uint[12]{ | |
0x80000, //0b10000000000000000000, /* 0D.3 */\ | |
0x00010, //0b00000000000000010000, /* 0B.4 */\ | |
0x00008, //0b00000000000000001000, /* 0B.3 */\ | |
0x00100, //0b00000000000100000000, /* 0C.0 */\ | |
0x00080, //0b00000000000010000000, /* 0B.7 */\ | |
0x01000, //0b00000001000000000000, /* 0C.4 */\ | |
0x00800, //0b00000000100000000000, /* 0C.3 */\ | |
0x10000, //0b00010000000000000000, /* 0D.0 */\ | |
0x08000, //0b00001000000000000000, /* 0C.7 */\ | |
0x00001, //0b00000000000000000001, /* 0B.0 */\ | |
0x00000, //0b00000000000000000000, /* xxxx */\ | |
0x00000 //0b00000000000000000000 /* xxxx */\ | |
}; | |
/// <summary> | |
/// 12-15 from 16-19 (time) | |
/// </summary> | |
private uint[] mUintArrBitPattern30_1 = new uint[30] { | |
0x00000200, //0b00000000000000000000001000000000, /* 17.1 */\ | |
0x00000020, //0b00000000000000000000000000100000, /* 16.5 */\ | |
0x02000000, //0b00000010000000000000000000000000, /* 19.1 */\ | |
0x00000000, //0b00000000000000000000000000000000, /* 1A.3 */\ | |
0x00000000, //0b00000000000000000000000000000000, /* 1A.5 */\ | |
0x00000080, //0b00000000000000000000000010000000, /* 16.7 */\ | |
0x40000000, //0b01000000000000000000000000000000, /* 19.6 */\ | |
0x01000000, //0b00000001000000000000000000000000, /* 19.0 */\ | |
0x04000000, //0b00000100000000000000000000000000, /* 19.2 */\ | |
0x00000000, //0b00000000000000000000000000000000, /* 1A.4 */\ | |
0x00010000, //0b00000000000000010000000000000000, /* 18.0 */\ | |
0x00000000, //0b00000000000000000000000000000000, /* 1A.2 */\ | |
0x00400000, //0b00000000010000000000000000000000, /* 18.6 */\ | |
0x00000010, //0b00000000000000000000000000010000, /* 16.4 */\ | |
0x00200000, //0b00000000001000000000000000000000, /* 18.5 */\ | |
0x00080000, //0b00000000000010000000000000000000, /* 18.3 */\ | |
0x00004000, //0b00000000000000000100000000000000, /* 17.6 */\ | |
0x00000000, //0b00000000000000000000000000000000, /* 1A.6 */\ | |
0x00020000, //0b00000000000000100000000000000000, /* 18.1 */\ | |
0x00100000, //0b00000000000100000000000000000000, /* 18.4 */\ | |
0x00008000, //0b00000000000000001000000000000000, /* 17.7 */\ | |
0x00000040, //0b00000000000000000000000001000000, /* 16.6 */\ | |
0x00001000, //0b00000000000000000001000000000000, /* 17.4 */\ | |
0x00000400, //0b00000000000000000000010000000000, /* 17.2 */\ | |
0x00000001, //0b00000000000000000000000000000001, /* 16.0 */\ | |
0x80000000, //0b10000000000000000000000000000000, /* 19.7 */\ | |
0x00000008, //0b00000000000000000000000000001000, /* 16.3 */\ | |
0x00000002, //0b00000000000000000000000000000010, /* 16.1 */\ | |
0x00040000, //0b00000000000001000000000000000000, /* 18.2 */\ | |
0x10000000 //0b00010000000000000000000000000000, /* 19.4 */\ | |
}; | |
/// <summary> | |
/// bit pattern for 12-15 from 1A (time2) | |
/// </summary> | |
private uint[] mUintArrBitPattern30_2 = new uint[30] { | |
0x00, //0b00000000, /* 17.1 */\ | |
0x00, //0b00000000, /* 16.5 */\ | |
0x00, //0b00000000, /* 19.1 */\ | |
0x08, //0b00001000, /* 1A.3 */\ | |
0x20, //0b00100000, /* 1A.5 */\ | |
0x00, //0b00000000, /* 16.7 */\ | |
0x00, //0b00000000, /* 19.6 */\ | |
0x00, //0b00000000, /* 19.0 */\ | |
0x00, //0b00000000, /* 19.2 */\ | |
0x10, //0b00010000, /* 1A.4 */\ | |
0x00, //0b00000000, /* 18.0 */\ | |
0x04, //0b00000100, /* 1A.2 */\ | |
0x00, //0b00000000, /* 18.6 */\ | |
0x00, //0b00000000, /* 16.4 */\ | |
0x00, //0b00000000, /* 18.5 */\ | |
0x00, //0b00000000, /* 18.3 */\ | |
0x00, //0b00000000, /* 17.6 */\ | |
0x40, //0b01000000, /* 1A.6 */\ | |
0x00, //0b00000000, /* 18.1 */\ | |
0x00, //0b00000000, /* 18.4 */\ | |
0x00, //0b00000000, /* 17.7 */\ | |
0x00, //0b00000000, /* 16.6 */\ | |
0x00, //0b00000000, /* 17.4 */\ | |
0x00, //0b00000000, /* 17.2 */\ | |
0x00, //0b00000000, /* 16.0 */\ | |
0x00, //0b00000000, /* 19.7 */\ | |
0x00, //0b00000000, /* 16.3 */\ | |
0x00, //0b00000000, /* 16.1 */\ | |
0x00, //0b00000000, /* 18.2 */\ | |
0x00 //0b00000000, /* 19.4 */\ | |
}; | |
/// <summary> | |
/// 12-14 from 1C-1E (result from F) | |
/// </summary> | |
private uint[] mUintArrBitPattern20 = new uint[20] { | |
0x000004, //0b000000000000000000000100, /* 1C.2 */\ | |
0x002000, //0b000000000010000000000000, /* 1E.5 */\ | |
0x008000, //0b000000001000000000000000, /* 1E.7 */\ | |
0x400000, //0b010000000000000000000000, /* 1D.6 */\ | |
0x000100, //0b000000000000000100000000, /* 1E.0 */\ | |
0x100000, //0b000100000000000000000000, /* 1D.4 */\ | |
0x000400, //0b000000000000010000000000, /* 1E.2 */\ | |
0x800000, //0b100000000000000000000000, /* 1D.7 */\ | |
0x040000, //0b000001000000000000000000, /* 1D.2 */\ | |
0x020000, //0b000000100000000000000000, /* 1D.1 */\ | |
0x000008, //0b000000000000000000001000, /* 1C.3 */\ | |
0x000200, //0b000000000000001000000000, /* 1E.1 */\ | |
0x004000, //0b000000000100000000000000, /* 1E.6 */\ | |
0x000002, //0b000000000000000000000010, /* 1C.1 */\ | |
0x001000, //0b000000000001000000000000, /* 1E.4 */\ | |
0x080000, //0b000010000000000000000000, /* 1D.3 */\ | |
0x000800, //0b000000000000100000000000, /* 1E.3 */\ | |
0x200000, //0b001000000000000000000000, /* 1D.5 */\ | |
0x010000, //0b000000010000000000000000, /* 1D.0 */\ | |
0x000001 //0b000000000000000000000001 /* 1C.0 */\ | |
}; | |
/// <summary> | |
/// bit pattern for 12-15 from 16-19 (1/3) | |
/// </summary> | |
private byte[] mByteArrLookupTable1C_1 = new byte[] { | |
0xBB, 0x0E, 0x22, 0xC5, 0x73, 0xDF, 0xF7, 0x6D, 0x90, 0xE9, 0xA1, 0x38, 0x1C, 0x84, 0x4A, 0x56, | |
0x64, 0x8D, 0x28, 0x0B, 0xD1, 0xBA, 0x93, 0x52, 0x1C, 0xC5, 0xA7, 0xF0, 0xE9, 0x7F, 0x36, 0x4E, | |
0xC1, 0x77, 0x3D, 0xB3, 0xAA, 0xE0, 0x0C, 0x6F, 0x14, 0x88, 0xF6, 0x2B, 0xD2, 0x99, 0x5E, 0x45, | |
0x1F, 0x70, 0x96, 0xD3, 0xB3, 0x0B, 0xFC, 0xEE, 0x81, 0x42, 0xCA, 0x34, 0xA5, 0x58, 0x29, 0x67 | |
}; | |
/// <summary> | |
/// bit pattern for 12-15 from 16-19 (2/3) | |
/// </summary> | |
private byte[] mByteArrLookupTable1C_2 = new byte[] { | |
0xAB, 0x3D, 0xFC, 0x74, 0x65, 0xE6, 0x0E, 0x4F, 0x97, 0x11, 0xD8, 0x59, 0x83, 0xC2, 0xBA, 0x20, | |
0xC5, 0x1B, 0xD2, 0x58, 0x49, 0x37, 0x01, 0x7D, 0x93, 0xFA, 0xE0, 0x2F, 0x66, 0xB4, 0xAC, 0x8E, | |
0xB7, 0xCC, 0x43, 0xFF, 0x58, 0x66, 0xEB, 0x35, 0x82, 0x2A, 0x99, 0xDD, 0x00, 0x71, 0x14, 0xAE, | |
0x4E, 0xB1, 0xF7, 0x70, 0x18, 0x52, 0xAA, 0x9F, 0xD5, 0x6B, 0xCC, 0x3D, 0x04, 0x83, 0xE9, 0x26 | |
}; | |
/// <summary> | |
/// bit pattern for 12-15 from 16-19 (3/3) | |
/// </summary> | |
private byte[] mByteArrLookupTable1C_3 = new byte[] { | |
0x0A, 0x02, 0x00, 0x0F, 0x06, 0x07, 0x0D, 0x08, 0x03, 0x0C, 0x0B, 0x05, 0x09, 0x01, 0x04, 0x0E, | |
0x02, 0x09, 0x05, 0x0D, 0x0C, 0x0E, 0x0F, 0x08, 0x06, 0x07, 0x0B, 0x01, 0x00, 0x0A, 0x04, 0x03, | |
0x08, 0x00, 0x0D, 0x0F, 0x01, 0x0C, 0x03, 0x06, 0x0B, 0x04, 0x09, 0x05, 0x0A, 0x07, 0x02, 0x0E, | |
0x03, 0x0D, 0x00, 0x0C, 0x09, 0x06, 0x0F, 0x0B, 0x01, 0x0E, 0x08, 0x0A, 0x02, 0x07, 0x04, 0x05 | |
}; | |
/// <summary> | |
/// Container, wich contains all former global vars | |
/// </summary> | |
private struct DataContainer | |
{ | |
/// <summary> | |
/// Registers R12 to R15 | |
/// </summary> | |
public ByteUInt mByteUint1;// = new ByteUInt(); | |
/// <summary> | |
/// Registers R08 to R0A | |
/// </summary> | |
public ByteUInt mByteUint2;// = new ByteUInt(); | |
/// <summary> | |
/// Registers R0B to R0E | |
/// </summary> | |
public ByteUInt mByteUint3;// = new ByteUInt(); | |
/// <summary> | |
/// Registers R1C to R1E | |
/// </summary> | |
public ByteUInt mByteUint4;// = new ByteUInt(); | |
public byte mByteUpperTime2;//, mByteR1B; | |
public uint mUintLowerTime; | |
} | |
#endregion | |
#region Public Methoden | |
/// <summary> | |
/// Entschlüsselt einen Datensatz. | |
/// </summary> | |
/// <param name="encodedDataset">Verschlüsselte Wetterdaten in binärer Form.</param> | |
/// <returns>Gibt die entschlüsselten Wetterdaten in binärer Form (untere 22 Bit + 2 Bit Status) zurück.</returns> | |
unsafe public uint DecodeDataset(byte[] encodedDataset) | |
{ | |
CipherKeyContainer dataCiperKey = new CipherKeyContainer(); | |
for (int i = 0; i < 10; i++) | |
if (i < encodedDataset.Length) | |
dataCiperKey.AllBytes[i] = encodedDataset[i]; | |
else | |
dataCiperKey.AllBytes[i] = 0; | |
byte[] plain; | |
plain = Decrypt(dataCiperKey.CipherBytes, dataCiperKey.KeyBytes); | |
return GetMeteoFromPlain(plain); | |
} | |
/// <summary> | |
/// Entschlüsselt einen Datensatz. | |
/// </summary> | |
/// <param name="encodedDataset">Verschlüsselte Wetterdaten in Form eines Strings (Big-Endian).</param> | |
/// <returns>Gibt die entschlüsselten Wetterdaten in Form eines Strings (Big-Endian) zurück.</returns> | |
public string DecodeDataset(string encodedDataset) | |
{ | |
int uiBitCnt, uiCnt; | |
byte ucTemp = 0; | |
byte[] dataCiperKey = new byte[10]; | |
uint meteoResult; | |
encodedDataset = encodedDataset.PadRight(82, '0'); | |
uiBitCnt = 0; | |
for (uiCnt = 1; uiCnt < 82; uiCnt++) | |
{ | |
if (uiCnt != 7) | |
{ | |
ucTemp = (byte)(ucTemp >> 1); | |
if (encodedDataset[uiCnt] == '1') | |
ucTemp |= 0x80; | |
uiBitCnt++; | |
if ((uiBitCnt & 7) == 0) | |
dataCiperKey[(uiBitCnt >> 3) - 1] = ucTemp; | |
} | |
} | |
meteoResult = DecodeDataset(dataCiperKey); | |
char[] result = Convert.ToString(meteoResult, 2).PadLeft(24, '0').ToCharArray(); | |
Array.Reverse(result); | |
return new string(result); | |
} | |
/// <summary> | |
/// Verschlüsselt einen Datensatz | |
/// </summary> | |
/// <param name="plain">Wetterdaten in binärer Form (untere 22 Bit werden beachtet).</param> | |
/// <param name="key">Schlüssel in binärer Form (üblicherweise Zeitinformationen).</param> | |
/// <returns>Gibt die verschlüsselten Wetterdaten inkl. des Schlüssels in binärer Form zurück.</returns> | |
unsafe public byte[] EncodeDataset(uint plain, byte[] key) | |
{ | |
byte[] result; // = new byte[10]; | |
CipherKeyContainer InOut = new CipherKeyContainer(); | |
for (int i = 0; i < 5; i++) | |
if (i < key.Length) | |
InOut.KeyBytes[i] = key[i]; | |
else | |
InOut.KeyBytes[i] = 0; | |
byte[] plainToEncrypt = GetPlainFromMeteo(plain & 0x003FFFFF); //nur 22 Bit | |
for (int i = 0; i < 5; i++) | |
InOut.CipherBytes[i] = plainToEncrypt[i]; | |
result = Encrypt(InOut.CipherBytes, InOut.KeyBytes); | |
for (int i = 0; i < 5; i++) | |
InOut.CipherBytes[i] = result[i]; | |
result = new byte[10]; | |
for (int i = 0; i < 10; i++) | |
result[i] = InOut.AllBytes[i]; | |
return result; | |
} | |
/// <summary> | |
/// Verschlüsselt einen Datensatz | |
/// </summary> | |
/// <param name="plain">Wetterdaten in Form eines Strings (Big-Endian).</param> | |
/// <param name="key">Schlüssel in Form eines Strings (Big-Endian, üblicherweise Zeitinformationen).</param> | |
/// <returns>Gibt die verschlüsselten Wetterdaten inkl. des Schlüssels in Form eines Strings zurück.</returns> | |
unsafe public string EncodeDataset(string plain, string key) | |
{ | |
byte[] resultBytes; | |
key = key.PadRight(40, '0'); //If plain and key too small | |
plain = plain.PadRight(22, '0'); | |
CipherKeyContainer resultContainer = new CipherKeyContainer(); | |
byte[] keyBytes = new byte[5]; | |
char[] plainCharArr = plain.Substring(0, 22).ToCharArray(); | |
Array.Reverse(plainCharArr); //Convert from Big Endian to Little Endian | |
uint plainData = Convert.ToUInt32(new string(plainCharArr), 2); | |
int uiBitCnt, uiCnt; | |
byte ucTemp = 0; | |
uiBitCnt = 0; | |
for (uiCnt = 0; uiCnt < 40; uiCnt++) | |
{ | |
ucTemp = (byte)(ucTemp >> 1); | |
if (key[uiCnt] == '1') | |
ucTemp |= 0x80; | |
uiBitCnt++; | |
if ((uiBitCnt & 7) == 0) | |
keyBytes[(uiBitCnt >> 3) - 1] = ucTemp; | |
} | |
resultBytes = EncodeDataset(plainData, keyBytes); | |
for (int i = 0; i < 5; i++) | |
{ | |
resultContainer.CipherBytes[i] = resultBytes[i]; | |
resultContainer.KeyBytes[i] = keyBytes[i]; | |
} | |
return CodedBinToString(resultContainer.CipherBytes, resultContainer.KeyBytes); | |
} | |
#endregion | |
#region Private Methoden | |
/// <summary> | |
/// Fügt Binärdaten (verschlüsselte Daten und Schnlüssel) in einem String zusammen. | |
/// </summary> | |
/// <param name="cipher">Zeiger auf eine Sequenz von Bytes, welche die verschlüsselten Bytes enthält.</param> | |
/// <param name="key">Zeiger auf eine Sequenz von Bytes, welche die Schlüssel-Bytes enthält.</param> | |
/// <returns>Gibt einen String zurück, in der ein Zeichen ein Bit der Eingangsdaten repräsentiert.</returns> | |
unsafe private string CodedBinToString(byte* cipher, byte* key) | |
{ | |
char[] result = new char[82]; | |
uint bitCount; | |
byte tmp = 0; | |
bitCount = 1; | |
result[0] = '0'; | |
for (int i = 0; i < 40; i++) | |
{ | |
if ((i & 7) == 0) | |
tmp = *(cipher++); | |
if (bitCount == 7) | |
result[bitCount++] = '0'; | |
if ((tmp & 1) != 0) | |
result[bitCount++] = '1'; | |
else | |
result[bitCount++] = '0'; | |
tmp >>= 1; | |
} | |
for (int i = 0; i < 40; i++) | |
{ | |
if (!((i & 7) >= 1)) | |
tmp = *(key++); | |
if ((tmp & 1) >= 1) | |
result[bitCount++] = '1'; | |
else | |
result[bitCount++] = '0'; | |
tmp >>= 1; | |
} | |
return new string(result); | |
} | |
/// <summary> | |
/// Ermittelt Wetterdaten aus den entschlüsselten Bytes und prüft auf Korrektheit. | |
/// </summary> | |
/// <param name="PlainBytes">Array mit den entschlüsselte Bytes.</param> | |
/// <returns>Gibt die aus dem Klartextbytes ermittelten Wetterdaten zurück</returns> | |
private uint GetMeteoFromPlain(byte[] PlainBytes) | |
{ | |
uint result; | |
uint checkSum; | |
checkSum = PlainBytes[2] & 0x0Fu; | |
checkSum <<= 8; | |
checkSum |= PlainBytes[1]; | |
checkSum <<= 4; | |
checkSum |= (uint)(PlainBytes[0] >> 4); | |
result = PlainBytes[0] & 0x0Fu | 0x10u; | |
result <<= 8; | |
result |= PlainBytes[4]; | |
result <<= 8; | |
result |= PlainBytes[3]; | |
result <<= 4; | |
result |= (uint)(PlainBytes[2] >> 4); | |
if (checkSum != 0x2501) | |
result = 0x200001; | |
else | |
{ | |
result &= 0x3FFFFF; | |
result |= 0x400000; | |
} | |
return result; | |
} | |
/// <summary> | |
/// Ermittelt den Klartext aus den Wetterdaten, welcher zur Verschlüsselung benötigt wird. | |
/// </summary> | |
/// <param name="meteo">Wetterdaten in binärer Form.</param> | |
/// <returns>Gibt die zu verschlüsselnden Klartextbytes zurück.</returns> | |
unsafe private byte[] GetPlainFromMeteo(uint meteo) | |
{ | |
byte[] result = new byte[5]; | |
meteo <<= 4; | |
result[1] = 0x50; | |
result[2] = (byte)((meteo & 0xF0) | 0x02); | |
meteo >>= 8; | |
result[3] = (byte)(meteo & 0xFF); | |
meteo >>= 8; | |
result[4] = (byte)(meteo & 0xFF); | |
meteo >>= 8; | |
result[0] = (byte)(meteo & 0x0F | 0x10); | |
return result; | |
} | |
unsafe private void CopyTimeToByteUint(byte* data, byte* key, ref DataContainer container) | |
{ | |
for (int i = 0; i < 4; i++) | |
{ | |
container.mUintLowerTime <<= 8; | |
container.mUintLowerTime |= key[3 - i]; | |
} | |
container.mByteUpperTime2 = key[4]; | |
// copy R | |
container.mByteUint3.Byte0 = data[2]; | |
container.mByteUint3.Byte1 = data[3]; | |
container.mByteUint3.Byte2 = data[4]; | |
container.mByteUint3.FullUint >>= 4; | |
// copy L | |
container.mByteUint2.Byte0 = data[0]; | |
container.mByteUint2.Byte1 = data[1]; | |
container.mByteUint2.Byte2 = (byte)(data[2] & 0x0F); | |
} | |
private void ShiftTimeRight(int round, ref DataContainer container) | |
{ | |
int count; | |
byte tmp; | |
if ((round == 16) || (round == 8) || (round == 7) || (round == 3)) | |
count = 2; | |
else | |
count = 1; | |
while (count-- != 0) | |
{ | |
tmp = 0; | |
if ((container.mUintLowerTime & 0x00100000) != 0) // save time bit 20 | |
tmp = 1; | |
container.mUintLowerTime &= 0xFFEFFFFF; | |
if ((container.mUintLowerTime & 1) != 0) | |
container.mUintLowerTime |= 0x00100000; // copy time bit 0 to time bit 19 | |
container.mUintLowerTime >>= 1; // time >>= 1 | |
if ((container.mByteUpperTime2 & 1) != 0) | |
container.mUintLowerTime |= 0x80000000; | |
container.mByteUpperTime2 >>= 1; | |
if (tmp != 0) | |
container.mByteUpperTime2 |= 0x80; // insert time bit 20 to time bit 39 | |
} | |
} | |
private void ShiftTimeLeft(int round, ref DataContainer container) | |
{ | |
int count; | |
byte tmp; | |
if ((round == 16) || (round == 8) || (round == 7) || (round == 3)) | |
count = 2; | |
else | |
count = 1; | |
while (count-- != 0) | |
{ | |
tmp = 0; | |
if ((container.mByteUpperTime2 & 0x80) != 0) | |
tmp = 1; | |
container.mByteUpperTime2 <<= 1; | |
if ((container.mUintLowerTime & 0x80000000) != 0) | |
container.mByteUpperTime2 |= 1; | |
container.mUintLowerTime <<= 1; | |
if ((container.mUintLowerTime & 0x00100000) != 0) | |
container.mUintLowerTime |= 1; | |
container.mUintLowerTime &= 0xFFEFFFFF; | |
if (tmp != 0) | |
container.mUintLowerTime |= 0x00100000; | |
} | |
} | |
private void ExpandR(ref DataContainer container) | |
{ | |
uint tmp; | |
container.mByteUint3.FullUint &= 0x000FFFFF; // clear 0D(4-7),0E | |
tmp = 0x00100000; // and set bits form 0B-0D(0-3) | |
for (int i = 0; i < 12; i++) | |
{ | |
if ((container.mByteUint3.FullUint & mUintArrBitPattern12[i]) != 0) | |
container.mByteUint3.FullUint |= tmp; | |
tmp <<= 1; | |
} | |
} | |
private void ExpandL(ref DataContainer container) | |
{ | |
uint tmp; | |
container.mByteUint2.FullUint &= 0x000FFFFF; // clear 0D(4-7),0E | |
tmp = 0x00100000; // and set bits form 0B-0D(0-3) | |
for (int i = 0; i < 12; i++) | |
{ | |
if ((container.mByteUint2.FullUint & mUintArrBitPattern12[i]) != 0) | |
container.mByteUint2.FullUint |= tmp; | |
tmp <<= 1; | |
} | |
} | |
private void CompressKey(ref DataContainer container) | |
{ | |
uint tmp; | |
container.mByteUint1.FullUint = 0; // clear 12-15 | |
tmp = 0x00000001; // and set bits from 16-1A (time) | |
for (int i = 0; i < 30; i++) | |
{ | |
if ((container.mUintLowerTime & mUintArrBitPattern30_1[i]) != 0 || (container.mByteUpperTime2 & mUintArrBitPattern30_2[i]) != 0) | |
container.mByteUint1.FullUint |= tmp; | |
tmp <<= 1; | |
} | |
} | |
private void DoSbox(ref DataContainer container) | |
{ | |
byte tmp, helper; //mByteR1B; | |
helper = container.mByteUint1.Byte3; // R1B = R15; | |
container.mByteUint1.Byte3 = container.mByteUint1.Byte2; // R15 = R14 | |
// INNER LOOP | |
for (int i = 5; i > 0; i--) | |
{ | |
if ((i & 1) == 0) // round 4,2 | |
{ | |
tmp = (byte)(container.mByteUint1.Byte0 >> 4); // swap R12 | |
tmp |= (byte)((container.mByteUint1.Byte0 & 0x0f) << 4); | |
container.mByteUint1.Byte0 = tmp; | |
} | |
container.mByteUint1.Byte3 &= 0xF0; // set R1C | |
tmp = (byte)((container.mByteUint1.Byte0 & 0x0F) | container.mByteUint1.Byte3); | |
if ((i & 4) != 0) | |
tmp = mByteArrLookupTable1C_1[(tmp & 0x3F)]; | |
if ((i & 2) != 0) | |
tmp = mByteArrLookupTable1C_2[(tmp & 0x3F)]; | |
else if (i == 1) | |
tmp = mByteArrLookupTable1C_3[(tmp & 0x3F)]; | |
if ((i & 1) != 0) | |
container.mByteUint4.Byte0 = (byte)(tmp & 0x0F); | |
else | |
container.mByteUint4.Byte0 |= (byte)(tmp & 0xF0); | |
if ((i & 1) == 0) // copy 14->13->12, 1C->1E->1D | |
{ | |
tmp = container.mByteUint1.Byte3; | |
container.mByteUint1.FullUint >>= 8; | |
container.mByteUint1.Byte3 = tmp; | |
container.mByteUint4.FullUint <<= 8; | |
} | |
container.mByteUint1.Byte3 >>= 1; // rotate R1B>R15 twice | |
if ((helper & 1) != 0) | |
container.mByteUint1.Byte3 |= 0x80; | |
helper >>= 1; | |
container.mByteUint1.Byte3 >>= 1; | |
if ((helper & 1) != 0) | |
container.mByteUint1.Byte3 |= 0x80; | |
helper >>= 1; | |
} // end of inner loop | |
} | |
private void DoPbox(ref DataContainer container) | |
{ | |
uint tmp; | |
container.mByteUint1.FullUint = 0xFF000000; // clear 12-14 | |
tmp = 0x00000001; // and set bits from 1C-1E (result from F) | |
for (int i = 0; i < 20; i++) | |
{ | |
if ((container.mByteUint4.FullUint & mUintArrBitPattern20[i]) != 0) | |
container.mByteUint1.FullUint |= tmp; | |
tmp <<= 1; | |
} | |
} | |
/// <summary> | |
/// DECRYPTION | |
/// </summary> | |
/// <param name="cipher"></param> | |
/// <param name="key"></param> | |
/// <returns></returns> | |
unsafe private byte[] Decrypt(byte* cipher, byte* key) | |
{ | |
DataContainer container = new DataContainer(); | |
//uint ulTemp; | |
//uiCnt, uiILCnt, , uiOL2Cnt, uiBitCnt | |
//byte ucOL2Pat, ucTemp; | |
byte[] plain = new byte[5]; | |
CopyTimeToByteUint(cipher, key, ref container); | |
// OUTER LOOP 1 | |
for (int i = 16; i > 0; i--) | |
{ | |
ShiftTimeRight(i, ref container); | |
ExpandR(ref container); | |
CompressKey(ref container); | |
// expR XOR compr.Key | |
container.mByteUint1.FullUint ^= container.mByteUint3.FullUint; // 12-15 XOR 0B-0E | |
container.mByteUint3.Byte2 &= 0x0F; // clear 0D(4-7) | |
DoSbox(ref container); | |
DoPbox(ref container); | |
// L XOR P-Boxed Round-Key (L') | |
container.mByteUint1.FullUint ^= container.mByteUint2.FullUint; | |
// L = R | |
container.mByteUint2.FullUint = container.mByteUint3.FullUint & 0x00FFFFFF; | |
// R = L' | |
container.mByteUint3.FullUint = container.mByteUint1.FullUint & 0x00FFFFFF; | |
} // end of outer loop 1 | |
container.mByteUint3.FullUint <<= 4; | |
container.mByteUint2.Byte2 &= 0x0F; | |
container.mByteUint2.Byte2 |= (byte)(container.mByteUint3.Byte0 & 0xF0); | |
//R0B0C0D0E.byte.R0D |= (R08090A.byte.R08 & 0xF0); | |
plain[0] = container.mByteUint2.Byte0; | |
plain[1] = container.mByteUint2.Byte1; | |
plain[2] = container.mByteUint2.Byte2; | |
plain[3] = container.mByteUint3.Byte1; | |
plain[4] = container.mByteUint3.Byte2; | |
return plain; | |
} | |
/// <summary> | |
/// ENCRYPTION | |
/// </summary> | |
/// <param name="plain"></param> | |
/// <param name="key"></param> | |
/// <returns></returns> | |
unsafe private byte[] Encrypt(byte* plain, byte* key) | |
{ | |
byte[] cipher = new byte[5]; | |
DataContainer container = new DataContainer(); | |
//uint ulTemp; | |
//uiCnt, uiILCnt, , uiOL2Cnt, uiBitCnt | |
//byte ucOL2Pat, ucTemp; | |
CopyTimeToByteUint(plain, key, ref container); | |
// OUTER LOOP 1 | |
for (int i = 1; i < 17; i++) | |
{ | |
ExpandL(ref container); | |
CompressKey(ref container); | |
// expR XOR compr.Key | |
container.mByteUint1.FullUint ^= container.mByteUint2.FullUint; // L' XOR compr.Key | |
container.mByteUint3.Byte2 &= 0x0F; // clear 0D(4-7) | |
DoSbox(ref container); | |
DoPbox(ref container); | |
// L XOR P-Boxed Round-Key (L') | |
container.mByteUint1.FullUint ^= container.mByteUint3.FullUint; | |
// L = R | |
container.mByteUint3.FullUint = container.mByteUint2.FullUint & 0x00FFFFFF; | |
// R = L' | |
container.mByteUint2.FullUint = container.mByteUint1.FullUint & 0x00FFFFFF; | |
ShiftTimeLeft(i, ref container); | |
} // end of outer loop 1 | |
container.mByteUint3.FullUint <<= 4; | |
container.mByteUint2.Byte2 &= 0x0F; | |
container.mByteUint2.Byte2 |= (byte)(container.mByteUint3.Byte0 & 0xF0); | |
//R0B0C0D0E.byte.R0D |= (R08090A.byte.R08 & 0xF0); | |
cipher[0] = container.mByteUint2.Byte0; | |
cipher[1] = container.mByteUint2.Byte1; | |
cipher[2] = container.mByteUint2.Byte2; | |
cipher[3] = container.mByteUint3.Byte1; | |
cipher[4] = container.mByteUint3.Byte2; | |
/* | |
R08090A.ulFull <<= 4; | |
R0B0C0D0E.byte.R0D |= (R08090A.byte.R08 & 0xF0); | |
pucCipher[0] = R0B0C0D0E.byte.R0B; | |
pucCipher[1] = R0B0C0D0E.byte.R0C; | |
pucCipher[2] = R0B0C0D0E.byte.R0D; | |
pucCipher[3] = R08090A.byte.R09; | |
pucCipher[4] = R08090A.byte.R0A; | |
*/ | |
return cipher; | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment