Ejemplo n.º 1
0
        public async Task <byte[]> BeginAsync()
        {
            if (_ubiqWebServices == null)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            else if (_aesGcmBlockCipher != null)
            {
                throw new InvalidOperationException("encryption in progress");
            }

            if (_encryptionKey == null)
            {
                // JIT: request encryption key from server
                _encryptionKey = await _ubiqWebServices.GetEncryptionKeyAsync(_usesRequested).ConfigureAwait(false);
            }

            // check key 'usage count' against server-specified limit
            if (_useCount > _encryptionKey.MaxUses)
            {
                throw new InvalidOperationException("maximum key uses exceeded");
            }

            _useCount++;

            var algorithmInfo = new AlgorithmInfo(_encryptionKey.SecurityModel.Algorithm);

            // generate random IV for encryption
            byte[] initVector = new byte[algorithmInfo.InitVectorLength];
            var    random     = RandomNumberGenerator.Create();

            random.GetBytes(initVector);

            var cipherHeader = new CipherHeader
            {
                Version                = 0,
                Flags                  = CipherHeader.FLAGS_AAD_ENABLED,
                AlgorithmId            = algorithmInfo.Id,
                InitVectorLength       = (byte)initVector.Length,
                EncryptedDataKeyLength = (short)_encryptionKey.EncryptedDataKeyBytes.Length,
                InitVectorBytes        = initVector,
                EncryptedDataKeyBytes  = _encryptionKey.EncryptedDataKeyBytes
            };

            // note: include cipher header bytes in AES result!
            var cipherHeaderBytes = cipherHeader.Serialize();

            _aesGcmBlockCipher = new AesGcmBlockCipher(
                forEncryption: true,
                algorithmInfo: algorithmInfo,
                key: _encryptionKey.UnwrappedDataKey,
                initVector: initVector,
                additionalBytes: cipherHeaderBytes);

            return(cipherHeaderBytes);
        }
Ejemplo n.º 2
0
        public byte[] Begin()
        {
            if (_ubiqWebServices == null)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            else if (_aesGcmBlockCipher != null)
            {
                throw new InvalidOperationException("decryption in progress");
            }

            // prepare to receive initial header bytes
            _cipherHeader = null;
            _byteBuffer   = null;

            // note: cached '_decryptionKey' may be present from a previous decryption run

            return(new byte[0]);
        }
Ejemplo n.º 3
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);
        }