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._visualCrypt2Service.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 = VisualCrypt2Formatter.DissectVisualCryptBytes(tlsEnvelope.EncipheredPayload, lro.Context); var decryptResponse = this._visualCrypt2Service.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._visualCrypt2Service.CalculateAndHashSharedSecret(clientDynamicPrivateKey, this._server.StaticPublicKey); authSecretBytes = new byte[32]; symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, authSecretBytes); var decryptResponse2 = this._visualCrypt2Service.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(); } }
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._visualCrypt2Service.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 = VisualCrypt2Formatter.DissectVisualCryptBytes(tlsEnvelope.EncipheredPayload, lro.Context); var decryptResponse = this._visualCrypt2Service.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); }