/// <param name="ack1SdIsReady">
        /// =true for SD in ACK2
        /// =false for SD in ACK1 (since the SessionDescription is not initialized yet)
        /// </param>
        internal byte[] Encrypt(ICryptoLibrary cryptoLibrary, InviteRequestPacket req, InviteAck1Packet ack1, InviteSession session,
                                bool ack1SdIsReady
                                )
        {
            BinaryProcedures.CreateBinaryWriter(out var ms, out var w);
            w.Write(Flags);
            UserCertificate.Encode(w, false);
            BinaryProcedures.EncodeIPEndPoint(w, DirectChannelEndPoint);
            NatBehaviour.Encode(w);
            DirectChannelToken32.Encode(w);
            w.Write((byte)SessionType);
            UserCertificateSignature.Encode(w);
            var bytesInLastBlock = (int)ms.Position % CryptoLibraries.AesBlockSize;

            if (bytesInLastBlock != 0)
            {
                var bytesRemainingTillFullAesBlock = CryptoLibraries.AesBlockSize - bytesInLastBlock;
                w.Write(cryptoLibrary.GetRandomBytes(bytesRemainingTillFullAesBlock));
            }
            var plainTextSdData = ms.ToArray();
            var encryptedSdData = new byte[plainTextSdData.Length];

            #region key, iv
            BinaryProcedures.CreateBinaryWriter(out var ms2, out var w2);
            req.GetSharedSignedFields(w2);
            ack1.GetSharedSignedFields(w2, ack1SdIsReady);
            var iv = cryptoLibrary.GetHashSHA256(ms2.ToArray()).Take(16).ToArray();
            ms2.Write(session.SharedInviteAckDhSecret, 0, session.SharedInviteAckDhSecret.Length);
            var aesKey = cryptoLibrary.GetHashSHA256(ms2.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp
            #endregion

            cryptoLibrary.ProcessAesCbcBlocks(true, aesKey, iv, plainTextSdData, encryptedSdData);

            return(encryptedSdData);
        }
Exemple #2
0
        internal void DeriveKeys(ICryptoLibrary cryptoLibrary, byte[] sharedPingPongHmacKey, MessageStartPacket messageStart,
                                 byte[] directChannelSharedDhSecret)
        {
            if (Status != MessageSessionStatusCode.created)
            {
                throw new InvalidOperationException();
            }

            BinaryProcedures.CreateBinaryWriter(out var msE, out var wE);
            messageStart.GetSignedFieldsForMessageHMAC(wE, false);
            wE.Write(sharedPingPongHmacKey);
            _iv = cryptoLibrary.GetHashSHA256(msE.ToArray()).Take(16).ToArray();
            wE.Write(directChannelSharedDhSecret);
            _aesKey = cryptoLibrary.GetHashSHA256(msE.ToArray());

            Status = MessageSessionStatusCode.inProgress;
        }
        /// <param name="receivedFromUser">comes from local contact book. is null if it is contact invitation</param>
        internal static InviteSessionDescription Decrypt_Verify(ICryptoLibrary cryptoLibrary, byte[] encryptedSdData,
                                                                InviteRequestPacket req,
                                                                InviteAck1Packet ack1,
                                                                bool ack1SdIsReady,
                                                                InviteSession session,
                                                                UserId receivedFromUserNullable,
                                                                DateTime localTimeNowUtc
                                                                )
        {
            #region key, iv
            BinaryProcedures.CreateBinaryWriter(out var ms2, out var w2);
            req.GetSharedSignedFields(w2);
            ack1.GetSharedSignedFields(w2, ack1SdIsReady);
            var iv = cryptoLibrary.GetHashSHA256(ms2.ToArray()).Take(16).ToArray();
            ms2.Write(session.SharedInviteAckDhSecret, 0, session.SharedInviteAckDhSecret.Length);
            var aesKey = cryptoLibrary.GetHashSHA256(ms2.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp
            #endregion

            // decrypt
            var plainTextSdData = new byte[encryptedSdData.Length];
            cryptoLibrary.ProcessAesCbcBlocks(false, aesKey, iv, encryptedSdData, plainTextSdData);

            var r      = new InviteSessionDescription();
            var reader = BinaryProcedures.CreateBinaryReader(plainTextSdData, 0);
            r.Flags = reader.ReadByte();
            if ((r.Flags & FlagsMask_MustBeZero) != 0)
            {
                throw new NotImplementedException();
            }
            r.UserCertificate          = UserCertificate.Decode_AssertIsValidNow(reader, cryptoLibrary, receivedFromUserNullable, localTimeNowUtc);
            r.DirectChannelEndPoint    = BinaryProcedures.DecodeIPEndPoint(reader);
            r.NatBehaviour             = NatBehaviourModel.Decode(reader);
            r.DirectChannelToken32     = DirectChannelToken32.Decode(reader);
            r.SessionType              = (SessionType)reader.ReadByte();
            r.UserCertificateSignature = UserCertificateSignature.DecodeAndVerify(reader, cryptoLibrary,
                                                                                  w =>
            {
                req.GetSharedSignedFields(w);
                ack1.GetSharedSignedFields(w, ack1SdIsReady);
                r.WriteSignedFields(w);
            },
                                                                                  r.UserCertificate);
            return(r);
        }
Exemple #4
0
        void GetIVandKeys(int id, EncryptedFieldIds fieldId, out byte[] iv, out byte[] aesKey, out byte[] hmacKey)
        {
            BinaryProcedures.CreateBinaryWriter(out var ms, out var w);
            w.Write(id);
            w.Write((byte)fieldId);

            var sha256result = _cryptoLibrary.GetHashSHA256(ms.ToArray());
            var preKey       = _keyProvider.HsmOperation(sha256result);

            _cryptoLibrary.DeriveKeysRFC5869_32bytes(preKey, sha256result, out aesKey, out hmacKey);
            iv = sha256result.Take(16).ToArray();
        }
Exemple #5
0
        double _distance_sumSqr; // 32 bytes of reg. public key: split into 16 dimensions of 2 bytes //   euclidean distance
        public unsafe RegistrationIdDistance(ICryptoLibrary cryptoLibrary, RegistrationId rpk1, RegistrationId rpk2, int numberOfDimensions)
        {
            if (rpk1.CachedEd25519publicKeySha256 == null)
            {
                rpk1.CachedEd25519publicKeySha256 = cryptoLibrary.GetHashSHA256(rpk1.Ed25519publicKey);
            }
            var rpk1_ed25519publicKey_sha256 = rpk1.CachedEd25519publicKeySha256;

            if (rpk2.CachedEd25519publicKeySha256 == null)
            {
                rpk2.CachedEd25519publicKeySha256 = cryptoLibrary.GetHashSHA256(rpk2.Ed25519publicKey);
            }
            var rpk2_ed25519publicKey_sha256 = rpk2.CachedEd25519publicKeySha256;

            if (rpk1_ed25519publicKey_sha256.Length != rpk2_ed25519publicKey_sha256.Length)
            {
                throw new ArgumentException();
            }
            _distance_sumSqr = 0;

            if (numberOfDimensions == 16)
            {
                fixed(byte *rpk1a = rpk1_ed25519publicKey_sha256, rpk2a = rpk2_ed25519publicKey_sha256)
                {
                    ushort *rpk1aPtr = (ushort *)rpk1a, rpk2aPtr = (ushort *)rpk2a;
                    int     l = rpk1_ed25519publicKey_sha256.Length / 2;

                    for (int i = 0; i < l; i++, rpk1aPtr++, rpk2aPtr++)
                    {
                        var d_i = VectorComponentRoutine(*rpk1aPtr, *rpk2aPtr);
                        _distance_sumSqr += d_i * d_i;
                    }
                }
            }
            else if (numberOfDimensions == 8)
            {
                fixed(byte *rpk1a = rpk1_ed25519publicKey_sha256, rpk2a = rpk2_ed25519publicKey_sha256)
                {
                    uint *rpk1aPtr = (uint *)rpk1a, rpk2aPtr = (uint *)rpk2a;
                    int   l = rpk1_ed25519publicKey_sha256.Length / 4;

                    for (int i = 0; i < l; i++, rpk1aPtr++, rpk2aPtr++)
                    {
                        var d_i = VectorComponentRoutine(*rpk1aPtr, *rpk2aPtr);
                        _distance_sumSqr += d_i * d_i;
                    }
                }
            }
            else if (numberOfDimensions == 4)
            {
                fixed(byte *rpk1a = rpk1_ed25519publicKey_sha256, rpk2a = rpk2_ed25519publicKey_sha256)
                {
                    ulong *rpk1aPtr = (ulong *)rpk1a, rpk2aPtr = (ulong *)rpk2a;
                    int    l = rpk1_ed25519publicKey_sha256.Length / 8;

                    for (int i = 0; i < l; i++, rpk1aPtr++, rpk2aPtr++)
                    {
                        var d_i = VectorComponentRoutine(*rpk1aPtr, *rpk2aPtr);
                        _distance_sumSqr += d_i * d_i;
                    }
                }
            }
            else if (numberOfDimensions == 2)
            {
                GetVectorValues_2(rpk1_ed25519publicKey_sha256, out var v1_0, out var v1_1);
                GetVectorValues_2(rpk2_ed25519publicKey_sha256, out var v2_0, out var v2_1);

                var d_0 = VectorComponentRoutine(v1_0, v2_0);
                var d_1 = VectorComponentRoutine(v1_1, v2_1);
                _distance_sumSqr += d_0 * d_0;
                _distance_sumSqr += d_1 * d_1;
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Exemple #6
0
        public static unsafe double[] GetVectorValues(ICryptoLibrary cryptoLibrary, RegistrationId rid, int numberOfDimensions)
        {
            var r = new double[numberOfDimensions];

            if (rid.CachedEd25519publicKeySha256 == null)
            {
                rid.CachedEd25519publicKeySha256 = cryptoLibrary.GetHashSHA256(rid.Ed25519publicKey);
            }
            var rid_ed25519publicKey_sha256 = rid.CachedEd25519publicKeySha256;

            if (numberOfDimensions == 16)
            {
                fixed(byte *rpk1a = rid_ed25519publicKey_sha256)
                {
                    ushort *rpk1aPtr = (ushort *)rpk1a;
                    int     l        = rid_ed25519publicKey_sha256.Length / 2;

                    for (int i = 0; i < l; i++, rpk1aPtr++)
                    {
                        r[i] = (double)(*rpk1aPtr) / UInt16.MaxValue;
                    }
                }
            }
            else if (numberOfDimensions == 8)
            {
                fixed(byte *rpk1a = rid_ed25519publicKey_sha256)
                {
                    uint *rpk1aPtr = (uint *)rpk1a;
                    int   l        = rid_ed25519publicKey_sha256.Length / 4;

                    for (int i = 0; i < l; i++, rpk1aPtr++)
                    {
                        r[i] = (double)(*rpk1aPtr) / UInt32.MaxValue;
                    }
                }
            }
            else if (numberOfDimensions == 4)
            {
                fixed(byte *rpk1a = rid_ed25519publicKey_sha256)
                {
                    ulong *rpk1aPtr = (ulong *)rpk1a;
                    int    l        = rid_ed25519publicKey_sha256.Length / 8;

                    for (int i = 0; i < l; i++, rpk1aPtr++)
                    {
                        r[i] = (double)(*rpk1aPtr) / ulong.MaxValue;
                    }
                }
            }
            else if (numberOfDimensions == 2)
            {
                GetVectorValues_2(rid_ed25519publicKey_sha256, out var v0, out var v1);
                r[0] = v0;
                r[1] = v1;
            }
            else
            {
                throw new NotImplementedException();
            }

            return(r);
        }
Exemple #7
0
        bool PassStatelessPoWfilter(ICcpRemoteEndpoint clientEndpoint, ClientHelloPacket0 packet)// packets processor thread // sends responses
        {
            switch (packet.StatelessProofOfWorkType)
            {
            case StatelessProofOfWorkType._2019_06:
                // verify size of PoW data
                if (packet.StatelessProofOfWorkData.Length < 12 || packet.StatelessProofOfWorkData.Length > 64)
                {
                    throw new CcpBadPacketException();
                }

                // verify datetime ("period")
                // return err code if time is wrong, with correct server's UTC time
                uint receivedTimeSec32;

                unsafe
                {
                    fixed(byte *statelessProofOfWorkDataPtr = packet.StatelessProofOfWorkData)
                    {
                        fixed(byte *addressBytesPtr = clientEndpoint.AddressBytes)
                        {
                            receivedTimeSec32 = *((uint *)statelessProofOfWorkDataPtr);
                            if (addressBytesPtr[0] != statelessProofOfWorkDataPtr[4] ||
                                addressBytesPtr[1] != statelessProofOfWorkDataPtr[5] ||
                                addressBytesPtr[2] != statelessProofOfWorkDataPtr[6] ||
                                addressBytesPtr[3] != statelessProofOfWorkDataPtr[7]
                                )
                            {
                                if (_config.RespondErrors)
                                {
                                    RespondToHello0(clientEndpoint, ServerHello0Status.ErrorBadStatelessProofOfWork_BadSourceIp, packet.Cnonce0);
                                }
                                return(false);
                            }
                        }
                    }
                }


                var localTimeSec32 = TimeSec32UTC;
                var diffSec        = Math.Abs((int)unchecked (localTimeSec32 - receivedTimeSec32));
                if (diffSec > _config.StatelessPoW_MaxClockDifferenceS)
                {
                    // respond with error "try again with valid clock" - legitimate user has to get valid clock from some time server and synchronize itself with the server
                    if (_config.RespondErrors)
                    {
                        RespondToHello0(clientEndpoint, ServerHello0Status.ErrorBadStatelessProofOfWork_BadClock, packet.Cnonce0);
                    }
                    return(false);
                }

                var hash = _cryptoLibrary.GetHashSHA256(packet.OriginalPacketPayload);
                // calculate hash, considering entire packet data (including stateless PoW result)
                // verify hash result
                if (!StatelessPowHashIsOK(hash))
                {
                    HandleBadStatelessPowPacket(clientEndpoint);
                    // no response
                    return(false);
                }

                // check if hash is unique
                var dataIsUnique = _recentUniquePowData.TryInputData(hash, localTimeSec32);

                if (dataIsUnique)
                {
                    return(true);
                }
                else
                {
                    // respond with error "try again with unique PoW data"
                    if (_config.RespondErrors)
                    {
                        RespondToHello0(clientEndpoint, ServerHello0Status.ErrorTryAgainRightNowWithThisServer, packet.Cnonce0);
                    }
                    return(false);
                }

            default:
                throw new CcpBadPacketException();
            }
        }