| 17 | DECLARE_FSTR_ARRAY(DecryptionKey, uint8_t) |
| 18 | |
| 19 | size_t EncryptedStream::write(const uint8_t* data, size_t size) |
| 20 | { |
| 21 | const size_t origSize = size; |
| 22 | |
| 23 | while(!hasError() && (size > 0)) { |
| 24 | std::size_t toConsume = std::min(remainingBytes, size); |
| 25 | memcpy(fragmentPtr, data, toConsume); |
| 26 | size -= toConsume; |
| 27 | data += toConsume; |
| 28 | fragmentPtr += toConsume; |
| 29 | remainingBytes -= toConsume; |
| 30 | |
| 31 | if(remainingBytes == 0) { |
| 32 | switch(fragment) { |
| 33 | case Fragment::Header: { |
| 34 | assert(DecryptionKey.length() == crypto_secretstream_xchacha20poly1305_KEYBYTES); |
| 35 | LOAD_FSTR_ARRAY(key, DecryptionKey); |
| 36 | bool ok = (crypto_secretstream_xchacha20poly1305_init_pull(&state, header, key) == 0); |
| 37 | sodium_memzero(key, sizeof(key)); |
| 38 | if(!ok) { |
| 39 | setError(Error::DecryptionFailed); |
| 40 | break; |
| 41 | } |
| 42 | fragment = Fragment::ChunkSize; |
| 43 | fragmentPtr = reinterpret_cast<uint8_t*>(&chunkSizeMinusOne); |
| 44 | remainingBytes = sizeof(chunkSizeMinusOne); |
| 45 | } break; |
| 46 | |
| 47 | case Fragment::ChunkSize: |
| 48 | remainingBytes = 1 + chunkSizeMinusOne; |
| 49 | if(!buffer || bufferSize < remainingBytes) { |
| 50 | buffer.reset(new uint8_t[remainingBytes]); |
| 51 | if(!buffer) { |
| 52 | setError(Error::OutOfMemory); |
| 53 | break; |
| 54 | } |
| 55 | bufferSize = remainingBytes; |
| 56 | } |
| 57 | fragmentPtr = buffer.get(); |
| 58 | fragment = Fragment::Chunk; |
| 59 | break; |
| 60 | |
| 61 | case Fragment::Chunk: { |
| 62 | unsigned char tag; |
| 63 | size_t chiperTextLength = 1 + chunkSizeMinusOne; |
| 64 | unsigned long long messageLength = 0; |
| 65 | bool ok = (crypto_secretstream_xchacha20poly1305_pull(&state, buffer.get(), &messageLength, &tag, |
| 66 | buffer.get(), chiperTextLength, nullptr, 0) == 0); |
| 67 | if(!ok || messageLength > bufferSize) { |
| 68 | setError(Error::DecryptionFailed); |
| 69 | break; |
| 70 | } |
| 71 | if(tag != crypto_secretstream_xchacha20poly1305_TAG_FINAL) { |
| 72 | fragment = Fragment::ChunkSize; |
| 73 | fragmentPtr = reinterpret_cast<uint8_t*>(&chunkSizeMinusOne); |
| 74 | remainingBytes = sizeof(chunkSizeMinusOne); |
| 75 | } else { |
| 76 | fragment = Fragment::None; |