@Override public void write(Cell cell) throws IOException { if (encryptor == null) { super.write(cell); return; } byte[] iv = nextIv(); encryptor.setIv(iv); encryptor.reset(); // TODO: Check if this is a cell for an encrypted CF. If not, we can // write a 0 here to signal an unwrapped cell and just dump the KV bytes // afterward StreamUtils.writeRawVInt32(out, iv.length); out.write(iv); // TODO: Add support for WAL compression ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStream cout = encryptor.createEncryptionStream(baos); int tlen = cell.getTagsLength(); // Write the KeyValue infrastructure as VInts. StreamUtils.writeRawVInt32(cout, KeyValueUtil.keyLength(cell)); StreamUtils.writeRawVInt32(cout, cell.getValueLength()); // To support tags StreamUtils.writeRawVInt32(cout, tlen); // Write row, qualifier, and family StreamUtils.writeRawVInt32(cout, cell.getRowLength()); cout.write(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); StreamUtils.writeRawVInt32(cout, cell.getFamilyLength()); cout.write(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); StreamUtils.writeRawVInt32(cout, cell.getQualifierLength()); cout.write(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); // Write the rest ie. ts, type, value and tags parts StreamUtils.writeLong(cout, cell.getTimestamp()); cout.write(cell.getTypeByte()); cout.write(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); if (tlen > 0) { cout.write(cell.getTagsArray(), cell.getTagsOffset(), tlen); } cout.close(); StreamUtils.writeRawVInt32(out, baos.size()); baos.writeTo(out); // Increment IV given the final payload length incrementIv(baos.size()); }
/** * @param uncompressedBytesWithHeader * @param blockType * @param headerBytes * @throws IOException */ protected void compressAfterEncoding( byte[] uncompressedBytesWithHeader, BlockType blockType, byte[] headerBytes) throws IOException { this.uncompressedBytesWithHeader = uncompressedBytesWithHeader; Encryption.Context cryptoContext = fileContext.getEncryptionContext(); if (cryptoContext != Encryption.Context.NONE) { // Encrypted block format: // +--------------------------+ // | byte iv length | // +--------------------------+ // | iv data ... | // +--------------------------+ // | encrypted block data ... | // +--------------------------+ cryptoByteStream.reset(); // Write the block header (plaintext) cryptoByteStream.write(headerBytes); InputStream in; int plaintextLength; // Run any compression before encryption if (fileContext.getCompression() != Compression.Algorithm.NONE) { compressedByteStream.reset(); compressionStream.resetState(); compressionStream.write( uncompressedBytesWithHeader, headerBytes.length, uncompressedBytesWithHeader.length - headerBytes.length); compressionStream.flush(); compressionStream.finish(); byte[] plaintext = compressedByteStream.toByteArray(); plaintextLength = plaintext.length; in = new ByteArrayInputStream(plaintext); } else { plaintextLength = uncompressedBytesWithHeader.length - headerBytes.length; in = new ByteArrayInputStream( uncompressedBytesWithHeader, headerBytes.length, plaintextLength); } if (plaintextLength > 0) { // Set up the cipher Cipher cipher = cryptoContext.getCipher(); Encryptor encryptor = cipher.getEncryptor(); encryptor.setKey(cryptoContext.getKey()); // Set up the IV int ivLength = iv.length; Preconditions.checkState(ivLength <= Byte.MAX_VALUE, "IV length out of range"); cryptoByteStream.write(ivLength); if (ivLength > 0) { encryptor.setIv(iv); cryptoByteStream.write(iv); } // Encrypt the data Encryption.encrypt(cryptoByteStream, in, encryptor); onDiskBytesWithHeader = cryptoByteStream.toByteArray(); // Increment the IV given the final block size Encryption.incrementIv(iv, 1 + (onDiskBytesWithHeader.length / encryptor.getBlockSize())); } else { cryptoByteStream.write(0); onDiskBytesWithHeader = cryptoByteStream.toByteArray(); } } else { if (this.fileContext.getCompression() != NONE) { compressedByteStream.reset(); compressedByteStream.write(headerBytes); compressionStream.resetState(); compressionStream.write( uncompressedBytesWithHeader, headerBytes.length, uncompressedBytesWithHeader.length - headerBytes.length); compressionStream.flush(); compressionStream.finish(); onDiskBytesWithHeader = compressedByteStream.toByteArray(); } else { onDiskBytesWithHeader = uncompressedBytesWithHeader; } } this.blockType = blockType; }
protected void incrementIv(int v) { Encryption.incrementIv(iv.get(), 1 + (v / encryptor.getBlockSize())); }
@Override protected byte[] initialValue() { byte[] iv = new byte[encryptor.getIvLength()]; new SecureRandom().nextBytes(iv); return iv; }