<commit_before>﻿// Copyright (c) 2013-2015 <NAME>
// See the file COPYING for license details.

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;

namespace x2.Transforms
{
    /// <summary>
    /// A simple example of BufferTransform that performs block encryption and
    /// decryption based on the keys exchanged by an asymmetric algorithm.
    /// </summary>
    /// <remarks>
    /// Illustration purpose only. Do NOT use this as is in production.
    /// </remarks>
    public class BlockCipher : IBufferTransform
    {
        private const int blockSize = 128;
        private const int keySize = 128;
        private const int rsaKeySize = 512;

        private SymmetricAlgorithm encryptionAlgorithm;
        private SymmetricAlgorithm decryptionAlgorithm;

        private byte[] encryptionKey;
        private byte[] decryptionKey;

        private byte[] encryptionIV;
        private byte[] decryptionIV;

        private int BlockSizeInBytes { get { return (blockSize >> 3); } }
        private int KeySizeInBytes { get { return (keySize >> 3); } }

        public int HandshakeBlockLength { get { return (rsaKeySize >> 3); } }

        public BlockCipher()
        {
            encryptionAlgorithm = new AesCryptoServiceProvider();
            encryptionAlgorithm.BlockSize = blockSize;
            encryptionAlgorithm.KeySize = keySize;
            encryptionAlgorithm.Mode = CipherMode.CBC;
            encryptionAlgorithm.Padding = PaddingMode.PKCS7;

            decryptionAlgorithm = new AesCryptoServiceProvider();
            decryptionAlgorithm.BlockSize = blockSize;
            decryptionAlgorithm.KeySize = keySize;
            decryptionAlgorithm.Mode = CipherMode.CBC;
            decryptionAlgorithm.Padding = PaddingMode.PKCS7;
        }

        public object Clone()
        {
            return new BlockCipher();
        }

        public void Dispose()
        {
            encryptionAlgorithm.Clear();
            decryptionAlgorithm.Clear();
        }

        public byte[] InitializeHandshake()
        {
            var challenge = new byte[KeySizeInBytes + BlockSizeInBytes];
            var rng = new RNGCryptoServiceProvider();
            rng.GetBytes(challenge);

            encryptionKey = challenge.SubArray(0, KeySizeInBytes);
            encryptionIV = challenge.SubArray(KeySizeInBytes, BlockSizeInBytes);

            using (var rsa = new RSACryptoServiceProvider(rsaKeySize))
            {
                rsa.FromXmlString(rsaPeerPublicKey);
                return rsa.Encrypt(challenge, false);
            }
        }

        public byte[] Handshake(byte[] challenge)
        {
            using (var rsa = new RSACryptoServiceProvider(rsaKeySize))
            {
                rsa.FromXmlString(rsaMyPrivateKey);
                byte[] decrypted = rsa.Decrypt(challenge, false);

                decryptionKey = decrypted.SubArray(0, KeySizeInBytes);
                decryptionIV = decrypted.SubArray(KeySizeInBytes, BlockSizeInBytes);

                return rsa.SignData(decrypted, new SHA1CryptoServiceProvider());
            }
        }

        public bool FinalizeHandshake(byte[] response)
        {
            using (var rsa = new RSACryptoServiceProvider(rsaKeySize))
            {
                rsa.FromXmlString(rsaPeerPublicKey);
                byte[] expected = encryptionKey.Concat(encryptionIV);
                return rsa.VerifyData(expected, new SHA1CryptoServiceProvider(), response);
            }
        }

        public int Transform(Buffer buffer, int length)
        {
            Log.Trace("BlockCipher.Transform: input length {0}", length);

            using (var encryptor = encryptionAlgorithm.CreateEncryptor(encryptionKey, encryptionIV))
            using (var ms = new MemoryStream(length + BlockSizeInBytes))
            using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
#if UNITY_WORKAROUND<commit_msg>BlockCipher: workaround for mono threading issue<commit_after>﻿// Copyright (c) 2013-2015 <NAME>
// See the file COPYING for license details.

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;

namespace x2.Transforms
{
    /// <summary>
    /// A simple example of BufferTransform that performs block encryption and
    /// decryption based on the keys exchanged by an asymmetric algorithm.
    /// </summary>
    /// <remarks>
    /// Illustration purpose only. Do NOT use this as is in production.
    /// </remarks>
    public class BlockCipher : IBufferTransform
    {
        private const int blockSize = 128;
        private const int keySize = 128;
        private const int rsaKeySize = 512;

        private SymmetricAlgorithm encryptionAlgorithm;
        private SymmetricAlgorithm decryptionAlgorithm;

        private byte[] encryptionKey;
        private byte[] decryptionKey;

        private byte[] encryptionIV;
        private byte[] decryptionIV;

        private int BlockSizeInBytes { get { return (blockSize >> 3); } }
        private int KeySizeInBytes { get { return (keySize >> 3); } }

        public int HandshakeBlockLength { get { return (rsaKeySize >> 3); } }

        public BlockCipher()
        {
            encryptionAlgorithm = new AesCryptoServiceProvider();
            encryptionAlgorithm.BlockSize = blockSize;
            encryptionAlgorithm.KeySize = keySize;
            encryptionAlgorithm.Mode = CipherMode.CBC;
            encryptionAlgorithm.Padding = PaddingMode.PKCS7;

            decryptionAlgorithm = new AesCryptoServiceProvider();
            decryptionAlgorithm.BlockSize = blockSize;
            decryptionAlgorithm.KeySize = keySize;
            decryptionAlgorithm.Mode = CipherMode.CBC;
            decryptionAlgorithm.Padding = PaddingMode.PKCS7;
        }

        public object Clone()
        {
            return new BlockCipher();
        }

        public void Dispose()
        {
            encryptionAlgorithm.Clear();
            decryptionAlgorithm.Clear();
        }

        public byte[] InitializeHandshake()
        {
            var challenge = new byte[KeySizeInBytes + BlockSizeInBytes];
            var rng = new RNGCryptoServiceProvider();
            rng.GetBytes(challenge);

            encryptionKey = challenge.SubArray(0, KeySizeInBytes);
            encryptionIV = challenge.SubArray(KeySizeInBytes, BlockSizeInBytes);

            using (var rsa = new RSACryptoServiceProvider(rsaKeySize))
            {
                rsa.FromXmlString(rsaPeerPublicKey);
                return rsa.Encrypt(challenge, false);
            }
        }

        public byte[] Handshake(byte[] challenge)
        {
            using (var rsa = new RSACryptoServiceProvider(rsaKeySize))
            {
                rsa.FromXmlString(rsaMyPrivateKey);
                byte[] decrypted = rsa.Decrypt(challenge, false);

                decryptionKey = decrypted.SubArray(0, KeySizeInBytes);
                decryptionIV = decrypted.SubArray(KeySizeInBytes, BlockSizeInBytes);

                // If we're free from old mono of such as Unity3D,
                // we can simply sign the decrypted data to prove ourselves.
                //return rsa.SignData(decrypted, new SHA1CryptoServiceProvider());
                
                // But if not, replay the data decrypted with our private key.
                rsa.FromXmlString(rsaPeerPublicKey);
                return rsa.Encrypt(decrypted, false);
            }
        }

        public bool FinalizeHandshake(byte[] response)
        {
            using (var rsa = new RSACryptoServiceProvider(rsaKeySize))
            {
                byte[] expected = encryptionKey.Concat(encryptionIV);
                
                // If we're free from old mono of such as Unity3D,
                // we can simply verify the peer signature.
                //rsa.FromXmlString(rsaPeerPublicKey);
                //return rsa.VerifyData(expected, new SHA1CryptoServiceProvider(), response);
                
                // But if not, verify the replayed data.
                rsa.FromXmlString(rsaMyPrivateKey);
                byte[] actual = rsa.Decrypt(response, false);
                return actual.EqualsExtended(expected);
            }
        }

        public int Transform(Buffer buffer, int length)
        {
            Log.Trace("BlockCipher.Transform: input length {0}", length);

            using (var encryptor = encryptionAlgorithm.CreateEncryptor(encryptionKey, encryptionIV))
            using (var ms = new MemoryStream(length + BlockSizeInBytes))
            using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
#if UNITY_WORKAROUND
{'fraction_non_alphanumeric': 0.08148824469299247, 'fraction_numerical': 0.0066194932663775395, 'mean_word_length': 2.0931874338157432, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '749144', 'n_tokens_mistral': 2305, 'n_tokens_neox': 2178, 'n_words': 572}