Exemple #1
0
        public TLSEnvelope TLSServerEncryptRequest(byte[] clearPacket, string recipientId)
        {
            byte[] authSecret = GetAuthSecret(recipientId);

            DynamicSecret dynamicSecret = GetDynamicSecretForEncryption(recipientId);

            Debug.WriteLine($"{this.ServerId}: TLSEncrypt: DynamicPublicKeyID: {dynamicSecret.DynamicPublicKeyId}, PrivateKeyHint: {dynamicSecret.PrivateKeyHint}.");

            // Concatenate = 'TLSAuthMode.Combined'
            byte[] symmetricKeyMaterial64 = ByteArrays.Concatenate(dynamicSecret.DynamicSharedSecret, authSecret);

            var lro        = new LongRunningOperation(progress => { }, () => { });
            var clearBytes = new Clearbytes(clearPacket);
            var sha512PW64 = new KeyMaterial64(symmetricKeyMaterial64);
            var method     = new RoundsExponent(0xff);

            var encryptResponse = this.ixdsCryptoService.BinaryEncrypt(clearBytes, sha512PW64, method, lro.Context);

            if (!encryptResponse.IsSuccess)
            {
                throw new Exception(encryptResponse.Error);
            }

            var encodeResponse = this.ixdsCryptoService.BinaryEncodeXDSSec(encryptResponse.Result, lro.Context);

            if (!encodeResponse.IsSuccess)
            {
                throw new Exception(encodeResponse.Error);
            }

            var tlsEnvelope = new TLSEnvelope(dynamicSecret.PrivateKeyHint, dynamicSecret.DynamicPublicKeyId, dynamicSecret.DynamicPublicKey, encodeResponse.Result);

            return(tlsEnvelope);
        }
Exemple #2
0
        public static byte[] Serialize(this TLSEnvelope tlsEnvelope)
        {
            if (tlsEnvelope.TotalLength != TLSEnvelope.HeaderLength + tlsEnvelope.EncipheredPayload.Length)
            {
                throw new InvalidOperationException("Actual payload lenght does not match Length field.");
            }

            int serializedLength = TLSEnvelope.HeaderLength + tlsEnvelope.EncipheredPayload.Length;
            var serialized       = new byte[serializedLength];

            serialized[0] = TLSEnvelope.Version;
            serialized[1] = TLSEnvelope.MessageType;

            byte[] lenghtBytes = BitConverter.GetBytes(serializedLength);
            serialized[2] = lenghtBytes[0];
            serialized[3] = lenghtBytes[1];
            serialized[4] = lenghtBytes[2];
            serialized[5] = lenghtBytes[3];

            byte[] keyHint = BitConverter.GetBytes(tlsEnvelope.PrivateKeyHint);
            serialized[6 + 4]  = keyHint[0];
            serialized[7 + 4]  = keyHint[1];
            serialized[8 + 4]  = keyHint[2];
            serialized[9 + 4]  = keyHint[3];
            serialized[10 + 4] = keyHint[4];
            serialized[11 + 4] = keyHint[5];
            serialized[12 + 4] = keyHint[6];
            serialized[13 + 4] = keyHint[7];

            byte[] dynamicPublicKeyId = BitConverter.GetBytes(tlsEnvelope.DynamicPublicKeyId);
            serialized[14 + 4] = dynamicPublicKeyId[0];
            serialized[15 + 4] = dynamicPublicKeyId[1];
            serialized[16 + 4] = dynamicPublicKeyId[2];
            serialized[17 + 4] = dynamicPublicKeyId[3];
            serialized[18 + 4] = dynamicPublicKeyId[4];
            serialized[19 + 4] = dynamicPublicKeyId[5];
            serialized[20 + 4] = dynamicPublicKeyId[6];
            serialized[21 + 4] = dynamicPublicKeyId[7];

            Buffer.BlockCopy(tlsEnvelope.DynamicPublicKey, 0, serialized, 22 + 4, 32);

            Buffer.BlockCopy(tlsEnvelope.EncipheredPayload, 0, serialized, TLSEnvelope.HeaderLength, tlsEnvelope.EncipheredPayload.Length);

            var crc32 = Crc32.Compute(serialized);

            byte[] crc32Bytes = BitConverter.GetBytes(crc32);
            serialized[6] = crc32Bytes[0];
            serialized[7] = crc32Bytes[1];
            serialized[8] = crc32Bytes[2];
            serialized[9] = crc32Bytes[3];
            return(serialized);
        }
Exemple #3
0
        public TLSEnvelope TLSServerEncryptRequestAnonymous(byte[] clearPacket, byte[] dynamicPublicKey, long dynamicPublicKeyID)
        {
            byte[] authSecret = new byte[32]; // we cannot create an authSecret based on the client's public key when we don't know who the client is.

            // we use the dynamicPublicKey and the server private key.
            var dynamicSharedSecret = this.ixdsCryptoService.CalculateAndHashSharedSecret(this._serverPrivateKey, dynamicPublicKey);

            // the hint to the clients privk for pubkey he sent
            long privateKeyHint = dynamicPublicKeyID;

            // and now we create a dynamic public key, just to fit the protocol, but not intended for use.
            var random          = this.ixdsCryptoService.GetRandom(32).Result.X;
            var throwAwayPubKey = this.ixdsCryptoService.GenerateCurve25519KeyPairExact(random).Result.PublicKey;
            // and a fake id
            long fakeDynamicPublicKeyID = 9999; // use a realistic value, not 9999!

            Debug.WriteLine($"{this.ServerId}: TLSServerEncryptRequestAnonymous: FakeDynamicPublicKeyID: {fakeDynamicPublicKeyID}, PrivateKeyHint: {privateKeyHint}.");

            // Concatenate = 'TLSAuthMode.Dynamic' - THIS is anothe case!
            byte[] symmetricKeyMaterial64 = ByteArrays.Concatenate(dynamicSharedSecret, authSecret);

            // same as normally
            var lro        = new LongRunningOperation(progress => { }, () => { });
            var clearBytes = new Clearbytes(clearPacket);
            var sha512PW64 = new KeyMaterial64(symmetricKeyMaterial64);
            var method     = new RoundsExponent(0xff);

            var encryptResponse = this.ixdsCryptoService.BinaryEncrypt(clearBytes, sha512PW64, method, lro.Context);

            if (!encryptResponse.IsSuccess)
            {
                throw new Exception(encryptResponse.Error);
            }

            var encodeResponse = this.ixdsCryptoService.BinaryEncodeXDSSec(encryptResponse.Result, lro.Context);

            if (!encodeResponse.IsSuccess)
            {
                throw new Exception(encodeResponse.Error);
            }

            var tlsEnvelope = new TLSEnvelope(privateKeyHint, fakeDynamicPublicKeyID, throwAwayPubKey, encodeResponse.Result);

            return(tlsEnvelope);
        }
Exemple #4
0
        public TLSRequest TLSServerDecryptRequest(TLSEnvelope tlsEnvelope)
        {
            Guard.NotNull(tlsEnvelope);
            var ar = new TLSRequest();

            byte[] serverPrivateKey;             // static or dynamic
            if (tlsEnvelope.PrivateKeyHint == 0) // The client has used server's static public key to encrypt...
            {
                serverPrivateKey = this._serverPrivateKey;
            }
            // ... so we simple use the servers static private key
            else // tlsEnvelope.PrivateKeyHint is the number the server generated earlier
            {
                serverPrivateKey = GetServerDynamicPrivateKeyForUserByPrivateKeyHint(tlsEnvelope.PrivateKeyHint);
            }
            if (serverPrivateKey == null)
            {
                // we lost our dynamic private key b/c of a disk failure and we don't know who sent us what :-(
                return(null);
            }

            byte[] dynamicSharedSecret = this.ixdsCryptoService.CalculateAndHashSharedSecret(serverPrivateKey, tlsEnvelope.DynamicPublicKey);

            Debug.WriteLine($"{this.ServerId}: TLSDecrypt:  PrivateKeyHint: {tlsEnvelope.PrivateKeyHint}");

            // 'TLSAuthMode.Separate'
            byte[] symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, new byte[32]); // no auth, we dont know who the user is
            // End 'TLSAuthMode.Separate'

            var lro             = new LongRunningOperation(progress => { }, () => { });
            var cipherV2        = XDSSecFormatter.DissectXDSSecBytes(tlsEnvelope.EncipheredPayload, lro.Context);
            var decryptResponse = this.ixdsCryptoService.BinaryDecrypt(cipherV2, new KeyMaterial64(symmetricKeyMaterial), lro.Context);

            if (!decryptResponse.IsSuccess)
            {
                throw new Exception(decryptResponse.Error);
            }

            byte[] tlsDecryptedRequest = decryptResponse.Result.GetBytes();

            // 'TLSAuthMode.Separate'
            var authSecretFromMessage = new byte[32];

            Buffer.BlockCopy(tlsDecryptedRequest, 0, authSecretFromMessage, 0, authSecretFromMessage.Length);

            // must be set even if the user is not authenticated for the case where a new identity is published right now.
            ar.UserId = Encoding.UTF8.GetString(tlsDecryptedRequest, 32, 10);
            // try authenticate
            var authSecret = GetAuthSecret(ar.UserId);

            if (authSecret != null)
            {
                if (ByteArrays.AreAllBytesEqual(authSecretFromMessage, authSecret))
                {
                    ar.IsAuthenticated = true;
                }
            }
            else
            {
                ar.IsAuthenticated = false;
            }

            var requestData = new byte[tlsDecryptedRequest.Length - 32 - 10];

            Buffer.BlockCopy(tlsDecryptedRequest, 32 + 10, requestData, 0, requestData.Length);
            ar.CommandData = requestData;
            // End 'TLSAuthMode.Separate'

            if (ar.IsAuthenticated)
            {
                SaveIncomingDynamicPublicKey(ar.UserId, tlsEnvelope.DynamicPublicKey, tlsEnvelope.DynamicPublicKeyId);
            }

            return(ar);
        }
        public async Task <TLSRequest> DecryptRequest(TLSEnvelope tlsEnvelope)
        {
            Guard.NotNull(tlsEnvelope);
            await this._publicMemberLock.WaitAsync();

            try
            {
                var ar = new TLSRequest();

                byte[] clientDynamicPrivateKey;
                this._server.DynamicPrivateDecryptionKeys.TryGetValue(tlsEnvelope.PrivateKeyHint, out clientDynamicPrivateKey);
                if (clientDynamicPrivateKey == null)
                {
                    throw new Exception(
                              "This should rarely happen. It means, the server has hinted me to private Key I no longer have.");
                }

                RemovePreviousKeys(tlsEnvelope.PrivateKeyHint);

                var dynamicSharedSecret = this.ixdsCryptoService.CalculateAndHashSharedSecret(clientDynamicPrivateKey,
                                                                                              tlsEnvelope.DynamicPublicKey);
                Debug.WriteLine($"{this.MyId}: TLSDecrypt:  PrivateKeyHint: {tlsEnvelope.PrivateKeyHint}");

                // TLSAuthMode Combined
                byte[] authSecretBytes      = this._server.AuthSecret;
                var    symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, authSecretBytes);
                // End TLSAuthMode Combined

                // TODO: make LRO optional!
                var lro             = new LongRunningOperation(progress => { }, () => { });
                var cipherV2        = XDSSecFormatter.DissectXDSSecBytes(tlsEnvelope.EncipheredPayload, lro.Context);
                var decryptResponse = this.ixdsCryptoService.BinaryDecrypt(cipherV2,
                                                                           new KeyMaterial64(symmetricKeyMaterial), lro.Context);
                var isIncomingKeyUnusable = false;
                if (!decryptResponse.IsSuccess)
                {
                    // has the server just lost the dynamic keys?
                    this._server.DynamicPrivateDecryptionKeys.TryGetValue(tlsEnvelope.PrivateKeyHint,
                                                                          out clientDynamicPrivateKey);
                    if (clientDynamicPrivateKey == null)
                    {
                        throw new Exception(
                                  "This should rarely happen. It means, the server has hinted me to private Key I no longer have.");
                    }
                    dynamicSharedSecret = this.ixdsCryptoService.CalculateAndHashSharedSecret(clientDynamicPrivateKey,
                                                                                              this._server.StaticPublicKey);
                    authSecretBytes      = new byte[32];
                    symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, authSecretBytes);
                    var decryptResponse2 = this.ixdsCryptoService.BinaryDecrypt(cipherV2,
                                                                                new KeyMaterial64(symmetricKeyMaterial), lro.Context);
                    if (!decryptResponse2.IsSuccess)
                    {
                        throw new Exception("Decryption failed in all ways!");
                    }
                    decryptResponse = decryptResponse2;
                    Debug.WriteLine("Decryption succeded in Anonymous mode.");
                    DoReset();
                    isIncomingKeyUnusable = true;
                }

                byte[] tlsDecryptedRequest = decryptResponse.Result.GetBytes();

                ar.IsAuthenticated = true;
                ar.UserId          = this._server.UserId;
                ar.CommandData     = tlsDecryptedRequest;

                if (!isIncomingKeyUnusable)
                {
                    Guard.NotNull(tlsEnvelope.DynamicPublicKey);
                    if (tlsEnvelope.DynamicPublicKeyId == 0)
                    {
                        throw new ArgumentException("A dynamic public key must never have an ID of 0.");
                    }
                    this._server.LatestDynamicPublicKey   = tlsEnvelope.DynamicPublicKey;
                    this._server.LatestDynamicPublicKeyId = tlsEnvelope.DynamicPublicKeyId;
                }
                return(ar);
            }
            finally
            {
                this._publicMemberLock.Release();
            }
        }