/// <summary> /// Checks the first 512 bytes for the Android magic sequence /// </summary> /// <param name="path"></param> /// <param name="foundPos">The byte where the magic sequence was found.</param> /// <returns></returns> private static bool AndroidMagicFound(string path, out int foundPos) { using (var fs = new FileStream(path, FileMode.Open)) { //fs.Seek(0, SeekOrigin.Begin); for (var i = 0; i <= 512; i++) { foundPos = i; //fs.Seek(i, SeekOrigin.Begin); var asdf = new Byte[BootImgHeader.BootMagicSize]; fs.Read(asdf, i, BootImgHeader.BootMagicSize); if (asdf.SequenceEqual(BootImgHeader.BootMagic)) { Console.WriteLine("Android boot magic found"); return true; } } foundPos = 0; return false; } }
public static bool CompareByteArrays(Byte[] a, Byte[] b) { // gleiche Länge? if (a.Length == b.Length) { return a.SequenceEqual(b); } else return false; }
public void Each_Byte_Each_Scheme() { for(var numShares = 2; numShares < 256; numShares++) { for(var threshold = 2; threshold <= numShares; threshold++) { for(var theByte = 0; theByte < 256; theByte++) { var secret = new Byte[1] { (byte)theByte }; var shares = _handler.Split(secret, threshold, numShares); foreach(var permutation in GetAllPermutations(shares, threshold)) { var restoredSecret = _handler.Restore(permutation); Assert.IsTrue(secret.SequenceEqual(restoredSecret)); } } } } }
public void EncryptionDecriptionTest() { var testVector = Utils.GetTestVector(40); var transform = new RC4CryptoTransform(testVector.Key); var inputBuffer = testVector.Data; var outputBuffer = new Byte[inputBuffer.Length]; var encrypted = transform.TransformBlock(inputBuffer, 0, inputBuffer.Length, outputBuffer, 0); Assert.AreEqual(encrypted, inputBuffer.Length); var decryptedData = new Byte[inputBuffer.Length]; var transform2 = new RC4CryptoTransform(testVector.Key); transform2.TransformBlock(outputBuffer, 0, outputBuffer.Length, decryptedData, 0); Assert.IsTrue(decryptedData.SequenceEqual(inputBuffer)); }
/// <summary> /// Given the first few bytes of content, decide what the FileCategory /// should be, based on what's in the Content.<br/> /// This should be called before deciding how to set the content. /// </summary> /// <param name="firstBytes">At least the first four bytes of the file read in binary form - can be longer if you wish</param> /// <returns>The type that should be used to store this file.</returns> public static FileCategory IdentifyCategory(byte[] firstBytes) { var firstFour = new Byte[4]; int atMostFour = Math.Min(4, firstBytes.Length); Array.Copy(firstBytes, 0, firstFour, 0, atMostFour); var returnCat = (atMostFour < 4) ? FileCategory.TOOSHORT : FileCategory.OTHER; // default if none of the conditions pass if (firstFour.SequenceEqual(CompiledObject.MagicId)) { returnCat = FileCategory.KSM; } else { bool isAscii = firstFour.All(b => b == (byte)'\n' || b == (byte)'\t' || b == (byte)'\r' || (b >= (byte)32 && b <= (byte)127)); if (isAscii) returnCat = FileCategory.ASCII; } return returnCat; // There is not currently an explicit test for KERBOSRIPT versus other types of ASCII. // At current, any time you want to test for is Kerboscript, make sure to test for is ASCII too, // since nothing causes a file to become type kerboscript yet. }
public void Test_Bytes() { Byte[] value = new Byte[] { 0x1, 0x2, 0x3, 0x4, 0x5 }; InformationElement infoElement = new InformationElement( InformationElement.ElementId.VendorSpecific, value); Byte[] ieArray = infoElement.Bytes; Assert.AreEqual(7, ieArray.Length); Assert.AreEqual((Byte)InformationElement.ElementId.VendorSpecific, ieArray[0]); Assert.AreEqual(5, ieArray[1]); Byte[] actualValue = new Byte[5]; Array.Copy(ieArray, 2, actualValue, 0, 5); Assert.IsTrue(value.SequenceEqual(actualValue)); }
/// <summary> /// Destructor. /// </summary> /* ~ADS1298device() { ; } */ /// <summary> /// In order to initialize the device we must have a valid class guid and device path name. /// Use FindDevice from UsbDevice to look up connected devices. /// </summary> /// /// <param name="devicePath"> Unique device path. </param> /// /// <returns> True if successful. </returns> internal override Boolean InitializeDevice(String devPath = null) { Byte[] configBuffer = new Byte[Marshal.SizeOf(regConfig)]; deviceConfigured = false; processingData = true; // Check for a valid device path. if (devPath != null) DevicePath = devPath; else if ((DevicePath == null) && (devPath == null)) return false; // Check if this devices exists. DeviceFound = usbDev.CheckDevice(DeviceClassGuid, ref devInfo.devicePath); if (DeviceFound) { // Pass the devices path name & get the device handle. DeviceAttached = winUsbDev.GetDeviceHandle(this.DevicePath); if (DeviceAttached) { // Initialize this device DeviceAttached = winUsbDev.InitializeDevice(); if (DeviceAttached) { // Lets get the descriptor so we can read the product & vendor id. DeviceAttached = winUsbDev.GetUsbDeviceDescriptor(); VendorID = winUsbDev.usbDevDescriptor.idVendor; ProductID = winUsbDev.usbDevDescriptor.idProduct; // Flush the pipes. winUsbDev.FlushPipe(PIPE_COMMAND_IN); winUsbDev.FlushPipe(PIPE_COMMAND_OUT); winUsbDev.FlushPipe(PIPE_DATA_IN); // Read configuration ReadConfiguration(); while (!deviceConfigured) { // Let's do a double check here, save the current config & re-read it from the device configBuffer = StructureToByteArray(ref regConfig); ReadConfiguration(); if (configBuffer.SequenceEqual(StructureToByteArray(ref regConfig))) deviceConfigured = true; } DeviceName = winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iProduct); if (String.IsNullOrEmpty(winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iProduct))) { DeviceName = String.Concat(DeviceName, String.Concat(Guid.NewGuid().ToString().Replace("-", "").Substring(1, 4))); // Append random numbers } else DeviceName = String.Concat(DeviceName, " ", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iSerialNumber)); SampleLength = SAMPLELENGTH; ResolutionBits = RESOLUTION; InputDifferantialVoltagePositive = INPUT_DIFFERANTIAL_VOLTAGE_POSITIVE; InputDifferantialVoltageNegative = INPUT_DIFFERANTIAL_VOLTAGE_NEGATIVE; EPdeviceType = this.ToString().Substring(this.ToString().LastIndexOf(".") + 1); } } else winUsbDev.CloseDeviceHandle(); } return (DeviceFound && DeviceAttached && deviceConfigured); }
private void breakSAV() { int[] offset = new int[2]; byte[] empty = new Byte[232]; byte[] emptyekx = new Byte[232]; byte[] ekxdata = new Byte[232]; byte[] pkx = new Byte[232]; byte[] slotsKey = new byte[0]; byte[] save1Save = break1; #region Finding the User Specific Data: Using Valid to keep track of progress... // Do Break. Let's first do some sanity checking to find out the 2 offsets we're dumping from. // Loop through save file to find int fo = savefile.Length / 2 + 0x20000; // Initial Offset, can tweak later. int success = 0; string result = ""; for (int d = 0; d < 2; d++) { // Do this twice to get both box offsets. for (int i = fo; i < 0xEE000; i++) { int err = 0; // Start at findoffset and see if it matches pattern if ((break1[i + 4] == break2[i + 4]) && (break1[i + 4 + 232] == break2[i + 4 + 232])) { // Sanity Placeholders are the same for (int j = 0; j < 4; j++) if (break1[i + j] == break2[i + j]) err++; if (err < 4) { // Keystream ^ PID doesn't match entirely. Keep checking. for (int j = 8; j < 232; j++) if (break1[i + j] == break2[i + j]) err++; if (err < 20) { // Tolerable amount of difference between offsets. We have a result. offset[d] = i; break; } } } } fo = offset[d] + 232 * 30; // Fast forward out of this box to find the next. } // Now that we have our two box offsets... // Check to see if we actually have them. if ((offset[0] == 0) || (offset[1] == 0)) { // We have a problem. Don't continue. result = "Unable to Find Box.\n"; } else { // Let's go deeper. We have the two box offsets. // Chunk up the base streams. byte[,] estream1 = new Byte[30, 232]; byte[,] estream2 = new Byte[30, 232]; // Stuff 'em. for (int i = 0; i < 30; i++) // Times we're iterating { for (int j = 0; j < 232; j++) // Stuff the Data { estream1[i, j] = break1[offset[0] + 232 * i + j]; estream2[i, j] = break2[offset[1] + 232 * i + j]; } } // Okay, now that we have the encrypted streams, formulate our EKX. string nick = eggnames[1]; // Stuff in the nickname to our blank EKX. byte[] nicknamebytes = Encoding.Unicode.GetBytes(nick); Array.Resize(ref nicknamebytes, 24); Array.Copy(nicknamebytes, 0, empty, 0x40, nicknamebytes.Length); // Encrypt the Empty PKX to EKX. Array.Copy(empty, emptyekx, 232); emptyekx = encryptArray(emptyekx); // Not gonna bother with the checksum, as this empty file is temporary. // Sweet. Now we just have to find the E0-E3 values. Let's get our polluted streams from each. // Save file 1 has empty box 1. Save file 2 has empty box 2. byte[,] pstream1 = new Byte[30, 232]; // Polluted Keystream 1 byte[,] pstream2 = new Byte[30, 232]; // Polluted Keystream 2 for (int i = 0; i < 30; i++) // Times we're iterating { for (int j = 0; j < 232; j++) // Stuff the Data { pstream1[i, j] = (byte)(estream1[i, j] ^ emptyekx[j]); pstream2[i, j] = (byte)(estream2[i, j] ^ emptyekx[j]); } } // Cool. So we have a fairly decent keystream to roll with. We now need to find what the E0-E3 region is. // 0x00000000 Encryption Constant has the D block last. // We need to make sure our Supplied Encryption Constant Pokemon have the D block somewhere else (Pref in 1 or 3). // First, let's get out our polluted EKX's. byte[,] polekx = new Byte[6, 232]; for (int i = 0; i < 6; i++) for (int j = 0; j < 232; j++) // Save file 1 has them in the second box. XOR them out with the Box2 Polluted Stream polekx[i, j] = (byte)(break1[offset[1] + 232 * i + j] ^ pstream2[i, j]); uint[] encryptionconstants = new uint[6]; // Array for all 6 Encryption Constants. int valid = 0; for (int i = 0; i < 6; i++) { encryptionconstants[i] = (uint)polekx[i, 0]; encryptionconstants[i] += (uint)polekx[i, 1] * 0x100; encryptionconstants[i] += (uint)polekx[i, 2] * 0x10000; encryptionconstants[i] += (uint)polekx[i, 3] * 0x1000000; // EC Obtained. Check to see if Block D is not last. if (getDloc(encryptionconstants[i]) != 3) { valid++; // Find the Origin/Region data. byte[] encryptedekx = new Byte[232]; byte[] decryptedpkx = new Byte[232]; for (int z = 0; z < 232; z++) encryptedekx[z] = polekx[i, z]; decryptedpkx = decryptArray(encryptedekx); // finalize data // Okay, now that we have the encrypted streams, formulate our EKX. nick = eggnames[decryptedpkx[0xE3] - 1]; // Stuff in the nickname to our blank EKX. nicknamebytes = Encoding.Unicode.GetBytes(nick); Array.Resize(ref nicknamebytes, 24); Array.Copy(nicknamebytes, 0, empty, 0x40, nicknamebytes.Length); // Dump it into our Blank EKX. We have won! empty[0xE0] = decryptedpkx[0xE0]; empty[0xE1] = decryptedpkx[0xE1]; empty[0xE2] = decryptedpkx[0xE2]; empty[0xE3] = decryptedpkx[0xE3]; break; } } #endregion if (valid == 0) // We didn't get any valid EC's where D was not in last. Tell the user to try again with different specimens. result = "The 6 supplied Pokemon are not suitable. \nRip new saves with 6 different ones that originated from your save file.\n"; else { #region Fix up our Empty File // We can continue to get our actual keystream. // Let's calculate the actual checksum of our empty pkx. uint chk = 0; for (int i = 8; i < 232; i += 2) // Loop through the entire PKX chk += BitConverter.ToUInt16(empty, i); // Apply New Checksum Array.Copy(BitConverter.GetBytes(chk), 0, empty, 06, 2); // Okay. So we're now fixed with the proper blank PKX. Encrypt it! Array.Copy(empty, emptyekx, 232); emptyekx = encryptArray(emptyekx); Array.Resize(ref emptyekx, 232); // ensure it's 232 bytes. // Empty EKX obtained. Time to set up our key file. savkey = new Byte[0xB4AD4]; // Copy over 0x10-0x1F (Save Encryption Unused Data so we can track data). Array.Copy(break1, 0x10, savkey, 0, 0x10); // Include empty data savkey[0x10] = empty[0xE0]; savkey[0x11] = empty[0xE1]; savkey[0x12] = empty[0xE2]; savkey[0x13] = empty[0xE3]; // Copy over the scan offsets. Array.Copy(BitConverter.GetBytes(offset[0]), 0, savkey, 0x1C, 4); for (int i = 0; i < 30; i++) // Times we're iterating { for (int j = 0; j < 232; j++) // Stuff the Data temporarily... { savkey[0x100 + i * 232 + j] = (byte)(estream1[i, j] ^ emptyekx[j]); savkey[0x100 + (30 * 232) + i * 232 + j] = (byte)(estream2[i, j] ^ emptyekx[j]); } } #endregion // Let's extract some of the information now for when we set the Keystream filename. #region Keystream Naming byte[] data1 = new Byte[232]; byte[] data2 = new Byte[232]; for (int i = 0; i < 232; i++) { data1[i] = (byte)(savkey[0x100 + i] ^ break1[offset[0] + i]); data2[i] = (byte)(savkey[0x100 + i] ^ break2[offset[0] + i]); } byte[] data1a = new Byte[232]; byte[] data2a = new Byte[232]; Array.Copy(data1, data1a, 232); Array.Copy(data2, data2a, 232); byte[] pkx1 = decryptArray(data1); byte[] pkx2 = decryptArray(data2); ushort chk1 = 0; ushort chk2 = 0; for (int i = 8; i < 232; i += 2) { chk1 += BitConverter.ToUInt16(pkx1, i); chk2 += BitConverter.ToUInt16(pkx2, i); } if (verifyCHK(pkx1) && Convert.ToBoolean(BitConverter.ToUInt16(pkx1, 8))) { // Save 1 has the box1 data pkx = pkx1; success = 1; } else if (verifyCHK(pkx2) && Convert.ToBoolean(BitConverter.ToUInt16(pkx2, 8))) { // Save 2 has the box1 data pkx = pkx2; success = 1; } else { // Data isn't decrypting right... for (int i = 0; i < 232; i++) { data1a[i] ^= empty[i]; data2a[i] ^= empty[i]; } pkx1 = decryptArray(data1a); pkx2 = decryptArray(data2a); if (verifyCHK(pkx1) && Convert.ToBoolean(BitConverter.ToUInt16(pkx1, 8))) { // Save 1 has the box1 data pkx = pkx1; success = 1; } else if (verifyCHK(pkx2) && Convert.ToBoolean(BitConverter.ToUInt16(pkx2, 8))) { // Save 2 has the box1 data pkx = pkx2; success = 1; } else { // Sigh... } } #endregion } } if (success == 1) { byte[] diff1 = new byte[31*30*232]; byte[] diff2 = new byte[31*30*232]; for(uint i = 0; i < 31*30*232; ++i) { diff1[i] = (byte)(break1[offset[0] + i] ^ break1[offset[0] + i - 0x7F000]); } for(uint i = 0; i < 31*30*232; ++i) { diff2[i] = (byte)(break2[offset[0] + i] ^ break2[offset[0] + i - 0x7F000]); } if (diff1.SequenceEqual(diff2)) { bool break3is1 = true; for(uint i = (uint)offset[0]; i<offset[0] + 31*30*232; ++i) { if(!(break2[i] == break3[i])) { break3is1 = false; break; } } if (break3is1) save1Save = break3; slotsKey = diff1; } else success = 0; } if (success == 1) { // Markup the save to know that boxes 1 & 2 are dumpable. savkey[0x20] = 3; // 00000011 (boxes 1 & 2) // Clear the keystream file... for (int i = 0; i < 31; i++) { Array.Copy(zerobox, 0, savkey, 0x00100 + i * (232 * 30), 232 * 30); Array.Copy(zerobox, 0, savkey, 0x40000 + i * (232 * 30), 232 * 30); } // Copy the key for the slot selector Array.Copy(save1Save, 0x168, savkey, 0x80000, 4); // Copy the key for the other save slot Array.Copy(slotsKey, 0, savkey, 0x80004, 232*30*31); // Since we don't know if the user put them in in the wrong order, let's just markup our keystream with data. byte[] data1 = new Byte[232]; byte[] data2 = new Byte[232]; for (int i = 0; i < 31; i++) { for (int j = 0; j < 30; j++) { Array.Copy(break1, offset[0] + i * (232 * 30) + j * 232, data1, 0, 232); Array.Copy(break2, offset[0] + i * (232 * 30) + j * 232, data2, 0, 232); if (data1.SequenceEqual(data2)) { // Just copy data1 into the key file. Array.Copy(data1, 0, savkey, 0x00100 + i * (232 * 30) + j * 232, 232); } else { // Copy both datas into their keystream spots. Array.Copy(data1, 0, savkey, 0x00100 + i * (232 * 30) + j * 232, 232); Array.Copy(data2, 0, savkey, 0x40000 + i * (232 * 30) + j * 232, 232); } } } // Save file diff is done, now we're essentially done. Save the keystream. // Success result = "Keystreams were successfully bruteforced!\n\n"; result += "Save your keystream now..."; MessageBox.Show(result); // From our PKX data, fetch some details to name our key file... string ot = TrimFromZero(Encoding.Unicode.GetString(pkx, 0xB0, 24)); ushort tid = BitConverter.ToUInt16(pkx, 0xC); ushort sid = BitConverter.ToUInt16(pkx, 0xE); ushort tsv = (ushort)((tid ^ sid) >> 4); SaveFileDialog sfd = new SaveFileDialog(); string ID = sfd.InitialDirectory; sfd.InitialDirectory = Path.Combine(path_exe, "data"); sfd.RestoreDirectory = true; sfd.FileName = CleanFileName(String.Format("SAV Key - {0} - ({1}.{2}) - TSV {3}.bin", ot, tid.ToString("00000"), sid.ToString("00000"), tsv.ToString("0000"))); sfd.Filter = "Save Key|*.bin"; if (sfd.ShowDialog() == DialogResult.OK) File.WriteAllBytes(sfd.FileName, savkey); else MessageBox.Show("Chose not to save keystream.", "Alert"); sfd.InitialDirectory = ID; sfd.RestoreDirectory = true; } else // Failed MessageBox.Show(result + "Keystreams were NOT bruteforced!\n\nStart over and try again :("); }
// File Dumping // SAV private byte[] fetchpkx(byte[] input, byte[] keystream, int pkxoffset, int key1off, int key2off, byte[] blank) { // Auto updates the keystream when it dumps important data! ghost = true; byte[] ekx = new Byte[232]; byte[] key1 = new Byte[232]; Array.Copy(keystream, key1off, key1, 0, 232); byte[] key2 = new Byte[232]; Array.Copy(keystream, key2off, key2, 0, 232); byte[] encrypteddata = new Byte[232]; Array.Copy(input, pkxoffset, encrypteddata, 0, 232); byte[] zeros = new Byte[232]; byte[] ezeros = encryptArray(zeros); Array.Resize(ref ezeros, 0xE8); if (zeros.SequenceEqual(key1) && zeros.SequenceEqual(key2)) return null; else if (zeros.SequenceEqual(key1)) { // Key2 is confirmed to dump the data. ekx = xortwos(key2, encrypteddata); ghost = false; } else if (zeros.SequenceEqual(key2)) { // Haven't dumped from this slot yet. if (key1.SequenceEqual(encrypteddata)) { // Slot hasn't changed. return null; } else { // Try and decrypt the data... ekx = xortwos(key1, encrypteddata); if (verifyCHK(decryptArray(ekx))) { // Data has been dumped! // Fill keystream data with our log. Array.Copy(encrypteddata, 0, keystream, key2off, 232); } else { // Try xoring with the empty data. if (verifyCHK(decryptArray(xortwos(ekx, blank)))) { ekx = xortwos(ekx, blank); Array.Copy(xortwos(encrypteddata, blank), 0, keystream, key2off, 232); } else if (verifyCHK(decryptArray(xortwos(ekx, ezeros)))) { ekx = xortwos(ekx, ezeros); Array.Copy(xortwos(encrypteddata, ezeros), 0, keystream, key2off, 232); } else return null; // Not a failed decryption; we just haven't seen new data here yet. } } } else { // We've dumped data at least once. if (key1.SequenceEqual(encrypteddata) || key1.SequenceEqual(xortwos(encrypteddata,blank)) || key1.SequenceEqual(xortwos(encrypteddata,ezeros))) { // Data is back to break state, but we can still dump with the other key. ekx = xortwos(key2, encrypteddata); if (!verifyCHK(decryptArray(ekx))) { if (verifyCHK(decryptArray(xortwos(ekx, blank)))) { ekx = xortwos(ekx, blank); Array.Copy(xortwos(key2, blank), 0, keystream, key2off, 232); } else if (verifyCHK(decryptArray(xortwos(ekx, ezeros)))) { // Key1 decrypts our data after we remove encrypted zeros. // Copy Key1 to Key2, then zero out Key1. ekx = xortwos(ekx, ezeros); Array.Copy(xortwos(key2, ezeros), 0, keystream, key2off, 232); } else return null; // Decryption Error } } else if (key2.SequenceEqual(encrypteddata) || key2.SequenceEqual(xortwos(encrypteddata, blank)) || key2.SequenceEqual(xortwos(encrypteddata, ezeros))) { // Data is changed only once to a dumpable, but we can still dump with the other key. ekx = xortwos(key1, encrypteddata); if (!verifyCHK(decryptArray(ekx))) { if (verifyCHK(decryptArray(xortwos(ekx, blank)))) { ekx = xortwos(ekx, blank); Array.Copy(xortwos(key1, blank), 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(ekx, ezeros)))) { ekx = xortwos(ekx, ezeros); Array.Copy(xortwos(key1, ezeros), 0, keystream, key1off, 232); } else return null; // Decryption Error } } else { // Data has been observed to change twice! We can get our exact keystream now! // Either Key1 or Key2 or Save is empty. Whichever one decrypts properly is the empty data. // Oh boy... here we go... ghost = false; bool keydata1, keydata2 = false; byte[] data1 = xortwos(encrypteddata, key1); byte[] data2 = xortwos(encrypteddata, key2); keydata1 = (verifyCHK(decryptArray(data1)) || verifyCHK(decryptArray(xortwos(data1, ezeros))) || verifyCHK(decryptArray(xortwos(data1, blank))) ); keydata2 = (verifyCHK(decryptArray(data2)) || verifyCHK(decryptArray(xortwos(data2, ezeros))) || verifyCHK(decryptArray(xortwos(data2, blank))) ); if (!keydata1 && !keydata2) return null; // All 3 are occupied. if (keydata1 && keydata2) { // Save file is currently empty... // Copy key data from save file if it decrypts with Key1 data properly. if (verifyCHK(decryptArray(data1))) { // No modifications necessary. ekx = data1; Array.Copy(encrypteddata, 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(data1, ezeros)))) { ekx = ezeros; Array.Copy(xortwos(encrypteddata,ezeros), 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(data1, blank)))) { ekx = ezeros; Array.Copy(xortwos(encrypteddata, blank), 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else return null; // unreachable } else if (keydata1) // Key 1 data is empty { if (verifyCHK(decryptArray(data1))) { ekx = data1; Array.Copy(key1, 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(data1, ezeros)))) { ekx = xortwos(data1, ezeros); Array.Copy(xortwos(key1, ezeros), 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(data1, blank)))) { ekx = xortwos(data1, blank); Array.Copy(xortwos(key1, blank), 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else return null; // unreachable } else if (keydata2) { if (verifyCHK(decryptArray(data2))) { ekx = data2; Array.Copy(key2, 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(data2, ezeros)))) { ekx = xortwos(data2, ezeros); Array.Copy(xortwos(key2, ezeros), 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else if (verifyCHK(decryptArray(xortwos(data2, blank)))) { ekx = xortwos(data2, blank); Array.Copy(xortwos(key2, blank), 0, keystream, key2off, 232); Array.Copy(zeros, 0, keystream, key1off, 232); } else return null; // unreachable } } } byte[] pkx = decryptArray(ekx); if (verifyCHK(pkx)) { slots++; return pkx; } else return null; // Slot Decryption error?! }