/// <summary>
        /// Encrypts and packs the packet for sending down the wire.
        /// </summary>
        /// <returns>The packet.</returns>
        /// <param name="sk">Local (sender) secret key.</param>
        /// <param name="pk">Remote (recipent) public key</param>
        public byte[] EncryptPacket(byte[] sk, byte[] pk)
        {
            byte[] header = this.PackHeader();
            //seq + ack + id + payload
            MemoryStream rpcRaw = new MemoryStream();

            if (this.HasRPC)
            {
                if (this.RPCs.Count > 0)
                {
                    rpcRaw.WriteByte((byte)RPCType.RPCStart);
                    foreach (IHasSerializationTag rpc in this.RPCs)
                    {
                        byte[] curRpcBytes = rpc.Serialize();
                        rpcRaw.WriteByte(rpc.SerializationTag);
                        rpcRaw.Write(curRpcBytes, 0, curRpcBytes.Length);
                    }
                    rpcRaw.WriteByte((byte)RPCType.RPCEnd);
                }
            }
            rpcRaw.Close();

            byte[] rpcBytes    = rpcRaw.ToArray();
            int    totalLength = 4 + 4 + 4;

            if (rpcBytes.Length > 0)
            {
                totalLength += rpcBytes.Length;
            }
            totalLength++;
            totalLength += this.Payload.Length;
            byte[] encryptedPart = new byte[totalLength];
            uint   index         = 0;

            PackingHelpers.PackUint32(Seq, encryptedPart, ref index);
            PackingHelpers.PackUint32(Ack, encryptedPart, ref index);
            PackingHelpers.PackUint32(CID, encryptedPart, ref index);
            if (rpcBytes.Length > 0)
            {
                Array.Copy(rpcBytes, 0, encryptedPart, index, rpcBytes.Length);
                index += (uint)rpcBytes.Length;
            }
            //start message flag.
            encryptedPart[index] = START_PAYLOAD_FLAG;
            ++index;
            Array.Copy(this.Payload, 0, encryptedPart, index, this.Payload.Length);
            byte[] ciphered = PublicKeyBox.Create(encryptedPart, this.Nonce, sk, pk);
            this.CipherText = ciphered;
            byte[] ret = new byte[header.Length + ciphered.Length];
            Array.Copy(header, ret, header.Length);
            Array.Copy(ciphered, 0, ret, header.Length, ciphered.Length);
            this.rawBytes = ret;
            return(ret);
        }
Example #2
0
        /// <summary>
        /// Packs the header. The total GenericPacket size is the size of the GenericPacket
        /// including the data that is going to be packed. The returning byte
        /// array will be of the size totalPacketSize + header overhead
        /// </summary>
        /// <returns>The header.</returns>
        /// <param name="totalPacketSize">Total GenericPacket size.</param>
        public byte[] PackHeader()
        {
            UInt32 packetOverhead = MIN_PACKET_HEADER_SIZE;

            if (this.hasEPK)
            {
                packetOverhead += 32;
            }
            if (this.hasPuzzle)
            {
                packetOverhead += 148;
            }
            byte[] data = new byte[packetOverhead];
            //constant start of message part
            UInt32 curIndex = 0;
            UInt64 tmpTID   = this.TID;

            if (this.hasEPK)
            {
                tmpTID |= Common.PUBLIC_KEY_FLAG;
            }
            if (this.hasPuzzle)
            {
                tmpTID |= Common.PUZZLE_FLAG;
            }
            PackingHelpers.PackUint64(tmpTID, data, ref curIndex);
            //curIndex += 1;
            //pack the nonce
            Array.Copy(this.Nonce, 0, data, curIndex, 24);
            curIndex += 24;
            //TODO: Add flags to the GenericPacket header
            if (this.hasEPK)
            {
                //this.TID = this.TID |= PUBLIC_KEY_FLAG;
                Array.Copy(this.EuphemeralPublicKey, 0, data,
                           curIndex, this.EuphemeralPublicKey.Length);
                curIndex += (UInt16)this.EuphemeralPublicKey.Length;
            }

            if (this.hasPuzzle)
            {
                //this.TID = this.TID |= PUZZLE_FLAG;
                Array.Copy(this.PuzzleOrSolution, 0, data, curIndex, this.PuzzleOrSolution.Length);
                curIndex += (UInt32)this.PuzzleOrSolution.Length;
            }

            /*if (this.RPCs.Count > 0)
             * {
             *  byte[] bytes = rpcRaw.ToArray();
             *  Array.Copy(bytes, 0, data, curIndex, bytes.Length);
             * }*/
            return(data);
        }
Example #3
0
        /// <summary>
        /// Unpacks the header.
        /// </summary>
        /// <returns>The header.</returns>
        /// <param name="data">Data.</param>
        /// <param name="serverKey">Server key.</param>
        /// <param name="refOffset">Reference offset.</param>
        public static GenericPacket UnpackPacket(byte[] data)
        {
            UInt64 tidWithFlags, tid;

            tidWithFlags = tid = 0;
            byte[] nonce = new byte[24];
            //todo: clean up the GenericPacket classes to allow us to do this without
            UInt32 seq, ack, cid;

            seq = ack = cid = 0;
            byte[] epk = null, puzzle = null;
            bool   hasPK, hasPuzzle;
            uint   curIndex = 0;

            PackingHelpers.UnpackUint64(ref tidWithFlags, data, ref curIndex);
            //curIndex += 1;
            tid       = tidWithFlags & ~Common.TID_FLAGS;
            hasPK     = (tidWithFlags & Common.PUBLIC_KEY_FLAG) == Common.PUBLIC_KEY_FLAG;
            hasPuzzle = (tidWithFlags & Common.PUZZLE_FLAG) == Common.PUZZLE_FLAG;

            //PackingHelpers.UnpackUint64 (ref nonce, data, ref curIndex);
            Array.Copy(data, curIndex, nonce, 0, nonce.Length);
            curIndex += (uint)(nonce.Length);

            if (hasPK)
            {
                epk = new byte[EPK_SIZE];
                Array.Copy(data, curIndex, epk, 0, EPK_SIZE);
                curIndex += (EPK_SIZE + 1);
            }

            if (hasPuzzle)
            {
                puzzle = new byte[PUZZLE_SOLUTIONS_SIZE];
                Array.Copy(data, curIndex, puzzle, 0, PUZZLE_SOLUTIONS_SIZE);
                curIndex += PUZZLE_SOLUTIONS_SIZE + 1;
            }

            //The remainder of the GenericPacket is encrypted. If there is an E_PK present
            //then this is likely a abstractTunnel open GenericPacket. Unlock it with the server key
            if (hasPK && data.Length > curIndex)
            {
                //byte[] cipherPart = new byte[data.Length - curIndex];
                //byte[] decrypted = Sodium.PublicKeyBox.OpenDetached (cipherPart, nonce, epk, secretKey);
                //copy in the checksum
                //byte[] rawMessage = new byte[decrypted.Length - CHECKSUM_SIZE];
                //Array.Copy (decrypted, rawMessage, 0, rawMessage.Length);
                //here we have to create an OpenPacket
                //todo: is this strictly nessecary?
                byte[] cipherPart = new byte[data.Length - curIndex];
                Array.Copy(data, curIndex, cipherPart, 0, cipherPart.Length);
                if (!hasPuzzle)
                {
                    OpenTunnelPacket packet = new OpenTunnelPacket(tid, seq, cid, ack, epk, cipherPart);
                    packet.Nonce = nonce;
                    return(packet);
                }
                return(new OpenTunnelPacket(tid, seq, cid, ack, epk, cipherPart, puzzle));
            }
            else
            {
                EncryptedPacket packet = new EncryptedPacket(tid, cid, ack);
                packet.Seq   = seq;
                packet.Nonce = nonce;
                byte[] cipherPart = new byte[data.Length - curIndex];
                Array.Copy(data, curIndex, cipherPart, 0, cipherPart.Length);
                packet.CipherText = cipherPart;
                return(packet);
            }
        }
Example #4
0
        /// <summary>
        /// Unpacks the header from the local binary representation
        /// </summary>
        public virtual uint UnpackHeader()
        {
            UInt64 tidWithFlags, tid;

            tidWithFlags = tid = 0;
            byte[] nonce = new byte[24];
            //todo: clean up the GenericPacket classes to allow us to do this without
            UInt32 seq, ack;

            seq = ack = 0;
            byte[] epk = null, puzzle = null;
            bool   hasPK, hasPuzzle;
            uint   curIndex = 0;

            byte[] data = this.rawBytes;

            PackingHelpers.UnpackUint64(ref tidWithFlags, data, ref curIndex);
            //curIndex += 1;
            tid       = tidWithFlags & ~Common.TID_FLAGS;
            hasPK     = (tidWithFlags & Common.PUBLIC_KEY_FLAG) != 0;
            hasPuzzle = (tidWithFlags & Common.PUZZLE_FLAG) != 0;

            this.TID   = tid;
            this.Seq   = seq;
            this.Ack   = ack;
            this.Nonce = nonce;

            //PackingHelpers.UnpackUint64 (ref nonce, data, ref curIndex);
            Array.Copy(data, curIndex, nonce, 0, nonce.Length);
            curIndex += (uint)(nonce.Length);

            if (hasPK)
            {
                epk = new byte[EPK_SIZE];
                Array.Copy(data, curIndex, epk, 0, EPK_SIZE);
                curIndex += EPK_SIZE;
                this.EuphemeralPublicKey = epk;
            }

            if (hasPuzzle)
            {
                puzzle = new byte[PUZZLE_SOLUTIONS_SIZE];
                Array.Copy(data, curIndex, puzzle, 0, PUZZLE_SOLUTIONS_SIZE);
                curIndex += PUZZLE_SOLUTIONS_SIZE;
                this.PuzzleOrSolution = puzzle;
            }

            //The remainder of the GenericPacket is encrypted. If there is an E_PK present
            //then this is likely a abstractTunnel open GenericPacket. Unlock it with the server key

            /*if(hasPK && data.Length > curIndex){
             *  //byte[] cipherPart = new byte[data.Length - curIndex];
             *  //byte[] decrypted = Sodium.PublicKeyBox.OpenDetached (cipherPart, nonce, epk, secretKey);
             *  //copy in the checksum
             *  //byte[] rawMessage = new byte[decrypted.Length - CHECKSUM_SIZE];
             *  //Array.Copy (decrypted, rawMessage, 0, rawMessage.Length);
             *  //here we have to create an OpenPacket
             *  byte[] cipherPart = new byte[data.Length - curIndex];
             *  Array.Copy (data, curIndex, cipherPart, 0, cipherPart.Length);
             *  if (!hasPuzzle) {
             *      OpenTunnelPacket GenericPacket = new OpenTunnelPacket (tid, seq, id, ack, epk, cipherPart);
             *      GenericPacket.Nonce = nonce;
             *
             *  }
             * }else{*/
            //EncryptedPacket GenericPacket = new EncryptedPacket(tid, id, ack);
            //GenericPacket.Seq = seq;
            //GenericPacket.Nonce = nonce;

            //GenericPacket.CipherText = cipherPart;
            return(curIndex);
            //}
        }
        public bool DecryptPacket(byte[] sk, byte[] pk)
        {
            byte[] decrypt;
            try
            {
                decrypt = Sodium.PublicKeyBox.Open(this.CipherText, this.Nonce, sk, pk);
            }
            catch (CryptographicException ex)
            {
                Debug.Fail(ex.StackTrace);
                return(false);
            }
            catch (Exception ex)
            {
                Debug.Fail(ex.StackTrace);
                return(false);
            }
            MemoryStream ms = new MemoryStream(decrypt);

            UInt32 seq = 0;
            UInt32 ack = 0;
            UInt32 cid = 0;

            PackingHelpers.UnpackUint32(ref seq, ms);
            PackingHelpers.UnpackUint32(ref ack, ms);
            PackingHelpers.UnpackUint32(ref cid, ms);
            this.Seq = seq;
            this.Ack = ack;
            this.CID = cid;
            int flag = ms.ReadByte();

            Debug.Assert((flag == (int)RPCType.RPCStart || flag == (int)START_PAYLOAD_FLAG));
            if (flag == (int)RPCType.RPCStart)
            {
                //deserialize the RPC
                this.RPCs = new ArrayList <IHasSerializationTag>();
                byte serializationTag;
                while ((serializationTag = (byte)ms.ReadByte()) != (byte)RPCType.RPCEnd)
                {
                    IHasSerializationTag rpc = null;
                    switch ((RPCType)serializationTag)
                    {
                    case RPCType.AnonymousPipe:
                        rpc = RPCBase <CreateAnonymousPipe> .Unpack(ms);

                        break;

                    case RPCType.AuthenticatedPipe:
                        rpc = RPCBase <CreateAuthenticatedPipe> .Unpack(ms);

                        break;

                    case RPCType.ClosePipe:
                        rpc = RPCBase <ClosePipeRPC> .Unpack(ms);

                        break;

                    case RPCType.AckPipe:
                        rpc = RPCBase <AckPipe> .Unpack(ms);

                        break;

                    case RPCType.RefusePipe:
                        rpc = RPCBase <RefusePipe> .Unpack(ms);

                        break;

                    case RPCType.RequestCertificate:
                        rpc = RPCBase <RequestCertificate> .Unpack(ms);

                        break;

                    case RPCType.GiveCertificate:
                        rpc = RPCBase <GiveCertificate> .Unpack(ms);

                        break;

                    case RPCType.Ok:
                        rpc = RPCBase <OkRPC> .Unpack(ms);

                        break;

                    case RPCType.NextTID:
                        rpc = RPCBase <NextTID> .Unpack(ms);

                        break;

                    case RPCType.RekeyNow:
                        rpc = RPCBase <RekeyNow> .Unpack(ms);

                        break;

                    case RPCType.PosePuzzle:
                        rpc = RPCBase <PosePuzzle> .Unpack(ms);

                        break;

                    case RPCType.PuzzleSolution:
                        //RPCBase<>.Unpack(ms);
                        //major todo
                        break;

                    case RPCType.WindowResize:
                        rpc = RPCBase <ResizeWindow> .Unpack(ms);

                        break;

                    default:
                        //todo we should error out but simply drop packets
                        throw new ArgumentOutOfRangeException();
                    }
                    this.RPCs.Add(rpc);
                }
                flag = ms.ReadByte();
            }

            if (flag == START_PAYLOAD_FLAG)
            {
                int    index   = (int)ms.Position;
                byte[] payload = new byte[decrypt.Length - index];
                Array.Copy(decrypt, index, payload, 0, payload.Length);
                this.Payload = payload;
            }
            else
            {
                this.Payload = new byte[0];
            }
            return(true);
        }