public static String Encode(String content, Boolean force) { StringBuilder builder = new StringBuilder(); StringBuilder temp = new StringBuilder(); StringBuilder temp2 = new StringBuilder(); content = (force) ? Utf8.Encode(content) : content; int i = content.Length % 3; if (i > 0) { while (i++ < 3) { content += "0"; temp.Append("="); } } i = 0; while (i < content.Length) { uint a = content[i]; uint b = content[i + 1]; uint c = content[i + 2]; uint d = ((a << 16) | (b << 8) | c); uint e = (d >> 18) & 0x3F; uint f = (d >> 12) & 0x3F; uint g = (d >> 6) & 0x3F; uint h = d & 0x3F; temp2.Append(new String(new Char[] { Base64.Code[(int)e], Base64.Code[(int)f], Base64.Code[(int)g], Base64.Code[(int)h] })); i += 3; } builder.Append(temp2.ToString().Substring(0, temp2.Length - temp.Length)); builder.Append(temp); return(builder.ToString()); }
public static String Encrypt(String plainText, String password, KeyType keyType) { int blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES int bits = (int)keyType; plainText = Utf8.Encode(plainText); password = Utf8.Encode(password); // use AES itself to encrypt password to get cipher key (using plain password as source for key // expansion) - gives us well encrypted key int bytes = bits / 8; // no bytes in key int[] pwBytes = new int[bytes]; for (int i = 0; i < bytes; i++) { pwBytes[i] = password[i]; } int[] temp = Cipher(pwBytes, KeyExpansion(pwBytes)); // gives us 16-byte key int[] key = new int[temp.Length + bytes - 16]; // expand key to 16/24/32 bytes long // expand key to 16/24/32 bytes long for (int i = 0; i < temp.Length; i++) { key[i] = temp[i]; } for (int i = temp.Length; i < (temp.Length + bytes - 16); i++) { key[i] = temp[i - temp.Length]; } // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes, // block counter in 2nd 8 bytes int[] counterBlock = new int[16]; int nonce = (int)(DateTime.Now - new DateTime(1970, 1, 1)).TotalMilliseconds; // timestamp: milliseconds since 1-Jan-1970 int nonceSec = (int)Math.Floor((double)nonce / (double)1000); int nonceMs = nonce % 1000; // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes for (int i = 0; i < 4; i++) { counterBlock[i] = (nonceSec >> i * 8) & 0xFF; } for (int i = 0; i < 4; i++) { counterBlock[i + 4] = nonceMs & 0xFF; } // and convert it to a string to go on the front of the ciphertext String ctrTxt = String.Empty; for (int i = 0; i < 8; i++) { ctrTxt += (Char)counterBlock[i]; } // generate key schedule - an expansion of the key into distinct Key Rounds for each round int[,] keySchedule = KeyExpansion(key); int blockCount = (int)Math.Ceiling((double)plainText.Length / (double)blockSize); String[] cipherTxt = new String[blockCount]; // ciphertext as array of strings for (int i = 0; i < blockCount; i++) { // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB) for (int j = 0; j < 4; j++) { counterBlock[15 - j] = (i >> j * 8) & 0xFF; } for (int j = 0; j < 4; j++) { //counterBlock[15 - c - 4] = (b / 0x100000000 >>> c * 8); counterBlock[15 - j - 4] = 0; } int[] cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block -- // block size is reduced on final block int blockLength = i < (blockCount - 1) ? blockSize : (plainText.Length - i * blockSize); Char[] cipherChar = new Char[blockLength]; for (int j = 0; j < blockLength; j++) { // -- xor plaintext with ciphered counter char-by-char -- cipherChar[j] = (Char)(cipherCntr[j] ^ plainText[i * blockSize + j]); } // ciphertxt[b] = cipherChar.join(''); cipherTxt[i] = new String(cipherChar); } StringBuilder builder = new StringBuilder(); builder.Append(ctrTxt); foreach (var str in cipherTxt) { builder.Append(str); } return(Base64.Encode(builder.ToString(), false)); }
public static String Decrypt(String cipherText, String password, KeyType keyType) { int blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES int bits = (int)keyType; cipherText = Base64.Decode(cipherText, false); password = Utf8.Encode(password); // use AES to encrypt password (mirroring encrypt routine) int bytes = bits / 8; // no bytes in key int[] pwBytes = new int[bytes]; for (int i = 0; i < bytes; i++) { pwBytes[i] = password[i]; } int[] temp = Cipher(pwBytes, KeyExpansion(pwBytes)); int[] key = new int[temp.Length + bytes - 16]; // expand key to 16/24/32 bytes long for (int i = 0; i < temp.Length; i++) { key[i] = temp[i]; } for (int i = temp.Length; i < (temp.Length + bytes - 16); i++) { key[i] = temp[i - temp.Length]; } // recover nonce from 1st 8 bytes of ciphertext int[] counterBlock = new int[16]; String ctrTxt = cipherText.Substring(0, 8); for (int i = 0; i < 8; i++) { counterBlock[i] = ctrTxt[i]; } // generate key schedule int[,] keySchedule = KeyExpansion(key); // separate ciphertext into blocks (skipping past initial 8 bytes) int blocks = (int)Math.Ceiling((double)(cipherText.Length - 8) / (double)blockSize); String[] ct = new String[blocks]; for (int i = 0; i < blocks; i++) { //ct[i] = cipherText.Substring(8 + i * blockSize, blockSize); ct[i] = cipherText.Substring(8 + i * blockSize, Math.Min(cipherText.Length - 8 - i * blockSize, blockSize)); } String[] ciphertextArr = ct; // ciphertext is now array of block-length strings // plaintext will get generated block-by-block into array of block-length strings String[] plaintxt = new String[ciphertextArr.Length]; for (int i = 0; i < blocks; i++) { // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) for (int j = 0; j < 4; j++) { counterBlock[15 - j] = (i >> (j * 8)) & 0xFF; } for (int j = 0; j < 4; j++) { //counterBlock[15 - j - 4] = (((b + 1) / 0x100000000 - 1) >>> c * 8) & 0xff; counterBlock[15 - j - 4] = 0; } int[] cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block Char[] plaintxtByte = new Char[ciphertextArr[i].Length]; for (int j = 0; j < ciphertextArr[i].Length; j++) { // -- xor plaintxt with ciphered counter byte-by-byte -- plaintxtByte[j] = (Char)(cipherCntr[j] ^ ciphertextArr[i][j]); //plaintxtByte[j] = String.fromCharCode(plaintxtByte[j]); } //plaintxt[i] = plaintxtByte.join(''); plaintxt[i] = new String(plaintxtByte); } // join array of blocks into single plaintext string //var plaintext : String = plaintxt.join(''); //plaintext = Utf8.decode(plaintext); // decode from UTF8 back to Unicode multi-byte chars StringBuilder builder = new StringBuilder(); foreach (var str in plaintxt) { builder.Append(str); } return(Utf8.Decode(builder.ToString())); }