/** * @file kCipherStream.cpp * * @internal * Copyright (C) 2016-2021 by LMI Technologies Inc. * Licensed under the MIT License. * Redistributed files must retain the above copyright notice. */ #include #include #include kBeginClassEx(k, kCipherStream) kAddPrivateVMethod(kCipherStream, kObject, VRelease) kAddPrivateVMethod(kCipherStream, kStream, VReadSomeImpl) kAddPrivateVMethod(kCipherStream, kStream, VWriteImpl) kAddPrivateVMethod(kCipherStream, kStream, VFlush) kEndClassEx() kFx(kStatus) kCipherStream_Construct(kCipherStream *cipherStream, kStream stream, kCipher cipher, kAlloc allocator) { kAlloc alloc = kAlloc_Fallback(allocator); kStatus status; kCheck(kAlloc_GetObject(alloc, kTypeOf(kCipherStream), cipherStream)); if (!kSuccess(status = xkCipherStream_Init(*cipherStream, kTypeOf(kCipherStream), stream, cipher, alloc))) { kAlloc_FreeRef(alloc, cipherStream); } return status; } kFx(kStatus) xkCipherStream_Init(kCipherStream cipherStream, kType type, kStream stream, kCipher cipher, kAlloc alloc) { kObjR(kCipherStream, cipherStream); kStatus status = kOK; kCheck(kStream_Init(cipherStream, type, alloc)); obj->writeBuffer = kNULL; obj->readBuffer = kNULL; obj->bufferSize = kCipher_Blocksize(cipher); obj->writeBufferUsed = 0; obj->readBufferUsed = 0; obj->encryptArray = kNULL; obj->decryptArray = kNULL; obj->stream = stream; obj->cipher = cipher; kTry { kTest(kObject_GetMem(cipherStream, obj->bufferSize, &obj->writeBuffer)); kTest(kObject_GetMem(cipherStream, obj->bufferSize, &obj->readBuffer)); kTest(kArray1_Construct(&obj->encryptArray, kTypeOf(kByte), 0, kObject_Alloc(cipherStream))); kTest(kArray1_Construct(&obj->decryptArray, kTypeOf(kByte), 0, kObject_Alloc(cipherStream))); } kCatch(&status) { xkCipherStream_VRelease(cipherStream); kEndCatch(status); } return kOK; } kFx(kStatus) xkCipherStream_VRelease(kCipherStream cipherStream) { kObj(kCipherStream, cipherStream); kCheck(kCipherStream_FlushFinal(cipherStream)); kDestroyRef(&obj->encryptArray); kDestroyRef(&obj->decryptArray); kCheck(kObject_FreeMemRef(cipherStream, &obj->writeBuffer)); kCheck(kObject_FreeMemRef(cipherStream, &obj->readBuffer)); kCheck(kObject_VRelease(cipherStream)); return kOK; } kFx(kStatus) xkCipherStream_VFlush(kCipherStream cipherStream) { kObj(kCipherStream, cipherStream); return kStream_Flush(obj->stream); } kFx(kStatus) kCipherStream_FlushFinal(kCipherStream cipherStream) { kObj(kCipherStream, cipherStream); kTry { if (obj->writeBufferUsed != 0) { kTest(kCipher_Encrypt(obj->cipher, obj->writeBuffer, obj->writeBufferUsed, obj->encryptArray)); kTest(kStream_Write(obj->stream, kArray1_Data(obj->encryptArray), kArray1_Length(obj->encryptArray))); } kTest(kStream_Flush(obj->stream)); } kFinally { kEndFinally(); } return kOK; } kFx(kStatus) xkCipherStream_VReadSomeImpl(kCipherStream cipherStream, void* buffer, kSize minCount, kSize maxCount, kSize* bytesRead) { kObj(kCipherStream, cipherStream); kSize i; kByte* writer = (kByte*) buffer; kTry { for (i = 0; i < minCount; i++) { if (obj->readBufferUsed == 0) { kTest(kStream_Read(obj->stream, obj->readBuffer, obj->bufferSize)); kTest(kCipher_Decrypt(obj->cipher, obj->readBuffer, obj->bufferSize, obj->decryptArray)); kMemCopy(obj->readBuffer, kArray1_Data(obj->decryptArray), obj->bufferSize); obj->readBufferUsed = obj->bufferSize; } writer[i] = obj->readBuffer[obj->bufferSize - obj->readBufferUsed--]; } } kFinally { kEndFinally(); } if (!kIsNull(bytesRead)) { *bytesRead = minCount; } return kOK; } kFx(kStatus) xkCipherStream_VWriteImpl(kCipherStream cipherStream, const void* buffer, kSize size) { kObj(kCipherStream, cipherStream); const kByte* reader = (const kByte*) buffer; kSize i; kTry { for (i = 0; i < size; i++) { obj->writeBuffer[obj->writeBufferUsed++] = reader[i]; if (obj->writeBufferUsed == obj->bufferSize) { kTest(kCipher_Encrypt(obj->cipher, obj->writeBuffer, obj->bufferSize, obj->encryptArray)); kTest(kStream_Write(obj->stream, kArray1_Data(obj->encryptArray), kArray1_Length(obj->encryptArray))); obj->writeBufferUsed = 0; } } } kFinally { kEndFinally(); } return kOK; }