Пример #1
0
        public byte[] Update(byte[] plainBytes, int offset, int count)
        {
            if (_ubiqWebServices == null)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            else if ((_encryptionKey == null) || (_aesGcmBlockCipher == null))
            {
                throw new InvalidOperationException("encryptor not initialized");
            }

            var cipherBytes = _aesGcmBlockCipher.Update(plainBytes, offset, count);

            return(cipherBytes);
        }
Пример #2
0
        // each encryption has a header on it that identifies the algorithm
        // used and an encryption of the data key that was used to encrypt
        // the original plain text. there is no guarantee how much of that
        // data will be passed to this function or how many times this
        // function will be called to process all of the data. to that end,
        // this function buffers data internally, when it is unable to
        // process it.

        // the function buffers data internally until the entire header is
        // received. once the header has been received, the encrypted data
        // key is sent to the server for decryption. after the header has
        // been successfully handled, this function always decrypts all of
        // the data in its internal buffer
        public async Task <byte[]> UpdateAsync(byte[] cipherBytes, int offset, int count)
        {
            if (_ubiqWebServices == null)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            byte[] plainBytes = new byte[0];        // returned

            if (_byteBuffer == null)
            {
                _byteBuffer = new ByteBuffer();
            }

            // make sure new data is appended to end
            _byteBuffer.Enqueue(cipherBytes, offset, count);

            if (_cipherHeader == null)
            {
                // see if we've got enough data for the header record
                using (var byteStream = new MemoryStream(_byteBuffer.Peek()))
                {
                    _cipherHeader = CipherHeader.Deserialize(byteStream);
                }

                if (_cipherHeader != null)
                {
                    // success: prune cipher header bytes from the buffer
                    _byteBuffer.Dequeue(_cipherHeader.Length());

                    if (_decryptionKey != null)
                    {
                        // See if we can reuse the key from a previous decryption, meaning
                        // the new data was encrypted with the same key as the old data - i.e.
                        // both cipher headers have the same key.
                        //
                        // If not, clear the previous decryption key.
                        if (!_cipherHeader.EncryptedDataKeyBytes.SequenceEqual(
                                _decryptionKey.LastCipherHeaderEncryptedDataKeyBytes))
                        {
                            await ResetAsync().ConfigureAwait(false);
                        }
                    }

                    // If needed, use the header info to fetch the decryption key.
                    if (_decryptionKey == null)
                    {
                        // JIT: request encryption key from server
                        _decryptionKey = await _ubiqWebServices.GetDecryptionKeyAsync(_cipherHeader.EncryptedDataKeyBytes).ConfigureAwait(false);
                    }

                    if (_decryptionKey != null)
                    {
                        var algorithmInfo = new AlgorithmInfo(_cipherHeader.AlgorithmId);

                        // save key extracted from header to detect future key changes
                        _decryptionKey.LastCipherHeaderEncryptedDataKeyBytes = _cipherHeader.EncryptedDataKeyBytes;

                        // create decryptor from header-specified algorithm + server-supplied decryption key
                        _aesGcmBlockCipher = new AesGcmBlockCipher(forEncryption: false,
                                                                   algorithmInfo: algorithmInfo,
                                                                   key: _decryptionKey.UnwrappedDataKey,
                                                                   initVector: _cipherHeader.InitVectorBytes,
                                                                   additionalBytes: ((_cipherHeader.Flags & CipherHeader.FLAGS_AAD_ENABLED) != 0)
                                ? _cipherHeader.Serialize()
                                : null);

                        _decryptionKey.KeyUseCount++;
                    }
                }
                else
                {
                    // holding pattern... need more header bytes
                    return(plainBytes);
                }
            }

            if ((_decryptionKey != null) && (_aesGcmBlockCipher != null))
            {
                // pass all available buffered bytes to the decryptor
                if (_byteBuffer.Length > 0)
                {
                    // tricky: the block cipher object will process all provided ciphertext
                    // (including the trailing MAC signature), but may only return a subset of that
                    // as plaintext
                    var bufferedBytes = _byteBuffer.Dequeue(_byteBuffer.Length);
                    plainBytes = _aesGcmBlockCipher.Update(bufferedBytes, 0, bufferedBytes.Length);
                }
            }

            return(plainBytes);
        }