예제 #1
0
파일: SCEDA.cs 프로젝트: Aspie96/SmallChat
        private static byte[] ScedaFunc(byte[] input, byte[] key, byte[] initializationVector, bool decrypting)
        {
            byte[] retVal = new byte[input.Length];

            byte[] blockKey = new byte[49];
            Array.Copy(key, 0, blockKey, 0, 16);
            Array.Copy(initializationVector, 0, blockKey, 16, 8);
            Array.Copy(initializationVector, 0, blockKey, 24, 8);
            Array.Copy(initializationVector, 0, blockKey, 32, 8);
            Array.Copy(initializationVector, 0, blockKey, 40, 8);
            blockKey[48] = 0;

            for (int i = 0; i < input.Length / 16; i++)
            {
                byte[] hashedBlockKey = SCEDA.Digest(blockKey);
                for (int j = 0; j < 16; j++)
                {
                    retVal[i * 16 + j] = (byte)(input[i * 16 + j] ^ hashedBlockKey[j]);
                }

                if (decrypting)
                {
                    Array.Copy(input, i * 16, blockKey, 16, 16);
                    Array.Copy(retVal, i * 16, blockKey, 32, 16);
                }
                else
                {
                    Array.Copy(retVal, i * 16, blockKey, 16, 16);
                    Array.Copy(input, i * 16, blockKey, 32, 16);
                }
                blockKey[32]++;
            }

            return(retVal);
        }
예제 #2
0
파일: SCEDA.cs 프로젝트: Aspie96/SmallChat
        /// <summary>Decrypts a message encrypted with SCEDA.</summary>
        /// <param name="input">The binary representation of the encrypted message.</param>
        /// <param name="key">The key used to encrypt the message (it must be 16 bytes long).</param>
        /// <param name="initializationVector">The initialization vector used to encrypt the message (it must be 8 bytes long).</param>
        /// <returns>The binary uncrypted message.</returns>
        /// <exception cref="ScedaException">Thrown when the length of the key or the initialization vector is wrong.</exception>
        /// <exception cref="ScedaDecryptingException">
        /// Thrown when the message cannot be decrypted (usually because the key or the initialization vector is wrong).
        /// Please notice: it might not always be possible to detect when the key or the initialization vector are wrong and if they are but no exception is thrown then a wrong message is returned.
        /// </exception>
        public static byte[] Decrypt(byte[] input, byte[] key, byte[] initializationVector)
        {
            byte[] retVal = SCEDA.ScedaFunc(input, key, initializationVector, true);

            if (key.Length != 16 || initializationVector.Length != 8)
            {
                throw new ScedaException("The key must be 16 bytes long and the initialization vector must be 8 bytes long!");
            }
            if ((input.Length % 16) != 0)
            {
                throw new ScedaDecryptingException("The length of a message encrypted with SCEDA must always be a multiple of 16 bytes!");
            }
            for (int i = 0; i < input.Length / 2; i++)
            {
                byte temp = retVal[i];
                retVal[i] = retVal[input.Length - i - 1];
                retVal[input.Length - i - 1] = temp;
            }
            int index  = 0;
            int length = 0;

            for (int i = 0; i < 7; i++)
            {
                length *= 256;
                length += retVal[index++];
            }
            if (length > input.Length - 16)
            {
                throw new ScedaDecryptingException();
            }
            Array.Copy(SCEDA.ScedaFunc(retVal.Skip(7).ToArray(), key, retVal.Skip(((length + 15) / 16) * 16 + 7).ToArray(), true), 0, retVal, 0, length);

            return(retVal.Take(length).ToArray());
        }
예제 #3
0
파일: SCEDA.cs 프로젝트: Aspie96/SmallChat
        /// <summary>Encrypts a message using SCEDA.</summary>
        /// <param name="input">The binary representation of the message to encrypt.</param>
        /// <param name="key">The key to be used. It must be 16 bytes long.</param>
        /// <param name="initializationVector">The initialization vector to be used (it must be provided and should not always be the same, but it is not required to be a secret). It must be 8 bytes long.</param>
        /// <returns>The binary encrypted message.</returns>
        public static byte[] Encrypt(byte[] input, byte[] key, byte[] initializationVector)
        {
            byte[] retVal = new byte[((input.Length + 31) / 16) * 16];

            int length = ((input.Length + 15) / 16) * 16;
            int temp   = input.Length;
            int index  = 6;

            for (int i = 0; i < 7; i++)
            {
                retVal[index--] = (byte)(temp % 256);
                temp           /= 256;
            }
            index += 8;
            Array.Copy(input, 0, retVal, index, input.Length);
            index += input.Length;
            for (int i = 0; i < length - input.Length + 9; i++)
            {
                retVal[index++] = (byte)SCEDA.r.Next(255);
            }
            index = 7;
            Array.Copy(SCEDA.ScedaFunc(retVal.Skip(index).ToArray(), key, retVal.Skip(index + length).ToArray(), false), 0, retVal, index, ((input.Length + 15) / 16) * 16);
            length += 16;
            for (int i = 0; i < length / 2; i++)
            {
                temp      = retVal[i];
                retVal[i] = retVal[length - i - 1];
                retVal[length - i - 1] = (byte)temp;
            }
            retVal = SCEDA.ScedaFunc(retVal, key, initializationVector, false);

            return(retVal);
        }
예제 #4
0
        /// <summary>Encrypts this PDU and provides its binary representation.</summary>
        /// <param name="key">The encryption key to be used.</param>
        /// <returns>The binary representation of the PDU to be sent through the network.</returns>
        public byte[] ToBinary(byte[] key)
        {
            if (key.Length != 16)
            {
                throw new ScedaException("A SCEDA key must be 16 bytes long.");
            }
            string type;

            switch (this.Type)
            {
            case SCPduType.Hello:
                type = "HLO";
                break;

            case SCPduType.Welcome:
                type = "ACK";
                break;

            case SCPduType.Leave:
                type = "LEV";
                break;

            case SCPduType.Message:
                type = "MSG";
                break;

            case SCPduType.MalformedPduNotification:
                type = "BAD";
                break;

            case SCPduType.NicknameConflictNotification:
                type = "CNF";
                break;

            default:
                type = "";
                break;
            }
            byte[] iv = SCEDA.GenerateIV();
            return((new byte[] { 0, 1 }).Concat(Encoding.ASCII.GetBytes(this.ChatID + '\0')).Concat(iv).Concat(SCEDA.Encrypt(Encoding.ASCII.GetBytes(type).Concat(Encoding.ASCII.GetBytes(this.Encoding.BodyName + '\0')).Concat(this.Payload).ToArray(), key, iv)).ToArray());
        }
예제 #5
0
파일: SCEDA.cs 프로젝트: Aspie96/SmallChat
        /// <summary>Applies the ScedaDigest hashing algorithm.</summary>
        /// <param name="input">The array to be hashed.</param>
        /// <returns>The result of the ScedaDigest algorithm (16 bytes long).</returns>
        public static byte[] Digest(byte[] input)
        {
            byte[] retVal = new byte[16];

            int blockC = (input.Length + 17) / 16;

            byte[] buffer = new byte[blockC * 16];
            Array.Copy(input, buffer, input.Length);
            buffer[input.Length]     = (byte)((input.Length / 256) % 256);
            buffer[input.Length + 1] = (byte)(input.Length % 256);
            for (int i = input.Length + 2; i < blockC * 16; i++)
            {
                buffer[i] = 170;
            }
            for (int i = 0; i < blockC; i++)
            {
                Array.Copy(SCEDA.DigestFunc(buffer.Skip(i * 16).Take(16).ToArray()), 0, buffer, i * 16, 16);
            }
            Array.Copy(buffer, retVal, 16);
            byte[] temp1 = new byte[16];
            byte[] temp2 = new byte[16];
            for (int i = 1; i < blockC; i++)
            {
                Array.Copy(retVal, temp1, 8);
                Array.Copy(buffer, 16 * i, temp1, 8, 8);
                Array.Copy(buffer, 16 * i + 8, temp2, 0, 8);
                Array.Copy(retVal, 8, temp2, 8, 8);
                temp1 = SCEDA.DigestFunc(temp1);
                temp2 = SCEDA.DigestFunc(temp2);
                for (int j = 0; j < 16; j++)
                {
                    retVal[j] = (byte)(temp1[j] ^ temp2[j]);
                }
            }

            return(retVal);
        }
예제 #6
0
        /// <summary>This factory method decrypt a binary PDU and convert it into an instance of the <see cref="SCPdu"/> structure.</summary>
        /// <param name="pdu">The binary content of the PDU.</param>
        /// <param name="key">The encryption key used for encrypting the content of the PDU.</param>
        /// <returns>The parsed PDU.</returns>
        /// <exception cref="MalformedPduException">Thrown when the PDU is broken or the given encryption key is wrong.</exception>
        public static SCPdu FromBinary(byte[] pdu, byte[] key)
        {
            SCPdu retVal = new SCPdu();

            if (key.Length != 16)
            {
                throw new ScedaException("A SCEDA key must be 16 bytes long.");
            }
            if (pdu.Length < 12)
            {
                throw new MalformedPduException("The PDU is too short.");
            }
            if (pdu[0] != 0 || pdu[1] != 1)
            {
                throw new MalformedPduException("Unknown ScedaDigest version.");
            }
            try
            {
                retVal.ChatID = Encoding.ASCII.GetString(pdu.Skip(2).TakeWhile(item => item != 0).ToArray());
                int    displacement = retVal.ChatID.Length + 3;
                byte[] iv           = pdu.Skip(displacement).Take(8).ToArray();
                displacement += 8;
                byte[] msg = SCEDA.Decrypt(pdu.Skip(displacement).ToArray(), key, iv);
                displacement = 0;
                string type = Encoding.ASCII.GetString(msg.Take(3).ToArray());
                displacement += 3;
                switch (type)
                {
                case "HLO":
                    retVal.Type = SCPduType.Hello;
                    break;

                case "ACK":
                    retVal.Type = SCPduType.Welcome;
                    break;

                case "LEV":
                    retVal.Type = SCPduType.Leave;
                    break;

                case "MSG":
                    retVal.Type = SCPduType.Message;
                    break;

                case "BAD":
                    retVal.Type = SCPduType.MalformedPduNotification;
                    break;

                case "CNF":
                    retVal.Type = SCPduType.NicknameConflictNotification;
                    break;

                default:
                    throw new Exception("PDU Type not known.");
                }
                string encoding = Encoding.ASCII.GetString(msg.Skip(displacement).TakeWhile(item => item != 0).ToArray());
                retVal.Encoding = Encoding.GetEncoding(encoding);
                displacement   += encoding.Length + 1;
                retVal.Payload  = msg.Skip(displacement).ToArray();
                if ((retVal.Type == SCPduType.Hello || retVal.Type == SCPduType.Welcome) && retVal.Payload.Length == 0)
                {
                    throw new Exception("Hello and Welcome PDUs must have a non-empty payload.");
                }
            }
            catch (Exception e)
            {
                throw new MalformedPduException(e);
            }
            return(retVal);
        }