public static String Decode(String content, Boolean force) { StringBuilder builder = new StringBuilder(); content = force ? Utf8.Decode(content) : content; int i = 0; List <String> strings = new List <String>(content.Length); while (i < content.Length) { uint a = (uint)Base64.Code.IndexOf(content[i]); uint b = (uint)Base64.Code.IndexOf(content[i + 1]); uint c = (uint)Base64.Code.IndexOf(content[i + 2]); uint d = (uint)Base64.Code.IndexOf(content[i + 3]); uint e = ((a << 18) | (b << 12) | (c << 6) | d); uint f = ((e >> 16) & 0xFF); uint g = ((e >> 8) & 0xFF); uint h = (e & 0xFF); strings.Add(new String(new Char[] { (Char)f, (Char)g, (Char)h })); if (d == 64) { strings[i / 4] = new String(new Char[] { (Char)f, (Char)g }); } if (c == 64) { strings[i / 4] = new String(new Char[] { (Char)f }); } i += 4; } foreach (var str in strings) { builder.Append(str); } return((force) ? Utf8.Decode(builder.ToString()) : builder.ToString()); }
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())); }