public static ArrayLease <byte> DecryptBytes(ArraySegment <byte> ciphertext, ArraySegment <byte> key, out int count) { // Blowfish processes things in blocks of 8, so // it doesn't make sense to have a non-multiple // of 8 length ciphertext (TODO: right?) if ((ciphertext.Count & 7) != 0) // ciphertext.Count % 8 != 0 { // TODO: Have a Strings.resx file for this // Does project.json support that? / What benefits will that yield? throw new ArgumentException( message: "The length of the ciphertext needs to be divisible by 8.", paramName: nameof(ciphertext)); } // Since there's guaranteed to be no leftover, // the count is just ciphertext.Count count = ciphertext.Count; var engine = new BlowfishEngine(); var keyParameter = new KeyParameter(key.Array, key.Offset, key.Count); engine.Init(forEncryption: false, parameters: keyParameter); var lease = ArrayPool <byte> .Shared.Lease(count); try { var encryptBuffer = ciphertext.Array; var decryptBuffer = lease.Array; for (int i = 0; i < count; i += 8) { engine.ProcessBlock(encryptBuffer, ciphertext.Offset + i, decryptBuffer, i); } } catch { lease.Dispose(); throw; } return(lease); }
static byte[] decrypt(byte[] byteArray, BlowfishEngine bf) { int blockSize = 8; List <byte> decrypted = new List <byte>(); for (int i = 0; i < byteArray.Length; i = i + blockSize) { byte[] blockBytes = new byte[blockSize]; byte[] outBytes = new byte[blockSize]; for (int j = 0; j < blockSize; j++) { blockBytes[j] = byteArray[i + j]; } bf.ProcessBlock(blockBytes, 0, outBytes, 0); decrypted.AddRange(outBytes); } unpad(decrypted); return(decrypted.ToArray()); }
/// <summary> /// Encrypted the data. /// </summary> /// <param name="data">The data to encrypted.</param> /// <param name="passphrase">The passphrase key used to mask the data.</param> /// <returns>The encrypted data.</returns> public byte[] Encrypt(byte[] data, string passphrase) { // Create the key parameters. byte[] key = Encoding.Default.GetBytes(passphrase); Key.Crypto.Parameters.KeyParameter keyParameter = new KeyParameter(key); // Initialise the cryptography engine. Key.Crypto.Engines.BlowfishEngine blowfish = new BlowfishEngine(); blowfish.Init(true, keyParameter); int dataLength = data.Length; int blockSize = blowfish.GetBlockSize(); int modBlockSize = dataLength % blockSize; int blockCount = dataLength / blockSize; // If there is a remained then add en extra block count. if ((modBlockSize) > 0) { // Add one extra block. blockCount++; } // Encrypted data store. byte[] encryptedData = new byte[blockCount * blockSize]; byte[] decryptedData = new byte[blockCount * blockSize]; // Copy the decrypted data. for (int j = 0; j < dataLength; j++) { // Assign the data. decryptedData[j] = data[j]; } // For each block size in the the data. for (int i = 0; i < blockCount; i++) { // Encrypt the block. blowfish.ProcessBlock(decryptedData, (i * blockSize), encryptedData, (i * blockSize)); } // Return the encrypted data. return(encryptedData); }
private void decrypt(byte[] value, BlowfishEngine bf) { int blockSize = bf.GetBlockSize(); byte[] vector = new byte[blockSize]; for (int i = 0; i < blockSize; i++) { vector[i] = 0; } for (int i = 0; i < value.Length; i += blockSize) { byte[] tmp = new byte[blockSize]; bf.ProcessBlock(vector, 0, tmp, 0); int chunk = Math.Min(blockSize, value.Length - i); for (int j = 0; j < chunk; j++) { vector[j] = value[i + j]; value[(i + j)] = (byte)(value[(i + j)] ^ tmp[j]); } ; } ; }
private static byte[] ProcessData(byte[] data, byte[] key, bool forEncryption) { byte[] input = data; bool paddingRequired = data.Length % BlockSize > 0; if (paddingRequired) { input = new byte[data.Length + BlockSize - data.Length % BlockSize]; Buffer.BlockCopy(data, 0, input, 0, data.Length); } byte[] output = new byte[input.Length]; BlowfishEngine engine = new BlowfishEngine(); engine.Init(forEncryption, key); int offset = 0; while (offset < input.Length) { engine.ProcessBlock(input, offset, output, offset); offset += BlockSize; } if (paddingRequired) { byte[] unpaddedOutput = new byte[data.Length]; Buffer.BlockCopy(output, 0, unpaddedOutput, 0, unpaddedOutput.Length); return(unpaddedOutput); } return(output); }
public static ArrayLease <byte> EncryptBytes(ArraySegment <byte> plaintext, ArraySegment <byte> key, out int count) { // Blowfish encrypts 8 bytes at a time int leftover = plaintext.Count & 7; count = (plaintext.Count + 7) & ~7; // branchless version of: n - (n % 8) + 8 // if there's leftover we'll need another extra 8 bytes to hold the input // note that this should not be part of the outputted array, // so store it in a new variable int capacity = count + ((leftover + 7) & ~7); Debug.Assert(leftover == 0 ^ capacity != plaintext.Count); var engine = new BlowfishEngine(); var keyParameter = new KeyParameter(key.Array, key.Offset, key.Count); engine.Init(forEncryption: true, parameters: keyParameter); var lease = ArrayPool <byte> .Shared.Lease(capacity); try { int i = plaintext.Offset; int j = 0; byte[] input = plaintext.Array; byte[] output = lease.Array; // Process each block of bytes while (i + 7 < plaintext.Count) { engine.ProcessBlock(input, i, output, j); i += 8; j += 8; } Debug.Assert( i + leftover == plaintext.Count && leftover >= 0 && leftover < 8); if (leftover != 0) { // Handle the leftover input bytes Debug.Assert( count > plaintext.Count && (count % 8) == 0 && capacity == count + 8); // Copy over the remaining input data to the end of the output array int inputIndex = i, outputIndex = j + 8; while (inputIndex < plaintext.Count) { output[outputIndex++] = input[inputIndex++]; } // Since this is a rented array, clear any extraneous data at the end // Use a regular while loop, since it's less than 8 bytes Debug.Assert( outputIndex <= capacity && capacity - outputIndex < 8); while (outputIndex < capacity) { output[outputIndex++] = 0; } engine.ProcessBlock(output, j + 8, output, j); } } catch { lease.Dispose(); throw; } return(lease); }