/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Aes.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "../Crypto.hpp" #include "Aes.hpp" #include #include namespace Aurora::Crypto::AES { AUKN_SYM AuUInt GetSafeCipherPadding(const Memory::MemoryViewRead ¶meters) { auto tptr = reinterpret_cast(parameters.ptr); auto overhang = parameters.length & (128 - 1); auto primaryLength = parameters.length - overhang; if (overhang == 0) { auto lastbyte = tptr[primaryLength - 1]; if (lastbyte <= 128) { return parameters.length + 128; } else { return parameters.length; } } else { return 128 - overhang; } } static bool EncryptCoolCodePadding(const void *plainText, AuUInt plainTextLength, const void *iv, void *outIv, AuUInt ivLength, const void *key, AuUInt keyLength, Memory::ByteBuffer &out, symmetric_CBC &cbc) { auto overhang = plainTextLength & (128 - 1) /* || fast_rng_bool */; auto padding = 128 - overhang; auto primaryLength = plainTextLength - overhang; int ret; auto tptr = reinterpret_cast(plainText); unsigned char pad[128] = { 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x80 }; if (overhang == 0) { auto lastbyte = tptr[primaryLength - 1]; if (lastbyte <= 128) { if (!AuTryResize(out, primaryLength + 128)) { SysPushErrorMem(); return false; } // encrypt plain text ret = cbc_encrypt(tptr, out.data(), primaryLength, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypto("{}", ret); return false; } // encrypt another 128 bytes of trash :( 50/50 chance ret = cbc_encrypt(pad, out.data() + primaryLength, 128, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypto("{}", ret); return false; } } else { if (!AuTryResize(out, primaryLength)) { SysPushErrorMem(); return false; } ret = cbc_encrypt(tptr, out.data(), primaryLength, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypto("{}", ret); return false; } } } else { if (!AuTryResize(out, primaryLength + 128)) { SysPushErrorMem(); return false; } ret = cbc_encrypt(tptr, out.data(), primaryLength, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypto("{}", ret); return false; } AuMemcpy(pad, tptr + primaryLength, overhang); pad[127] = padding; ret = cbc_encrypt(pad, out.data() + primaryLength, 128, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypto("{}", ret); return false; } } return true; } AUKN_SYM bool Encrypt(const AuMemoryViewRead &plainText, const AuMemoryViewRead &inIv, const AuMemoryViewWrite & outIv, const AuMemoryViewRead &inKey, AuByteBuffer &out, bool auCoolCodePadding) { symmetric_CBC cbc; if (!plainText.length) { return false; } if (!plainText.ptr) { return false; } if (!inIv.length) { return false; } if (!inIv.ptr) { return false; } if (!inKey.length) { return false; } if (!inKey.ptr) { return false; } if (inIv.length != 16) { SysPushErrorCrypt("{}", inIv.length); return false; } if (outIv.length) { if (inIv.length != outIv.length) { SysPushErrorCrypt("{}", outIv.length); return false; } } if ((inKey.length != 16) && (inKey.length != 24) && (inKey.length != 32)) { SysPushErrorCrypt("{}", inKey.length); return false; } auto ret = cbc_start(::Crypto::gAesCipher, reinterpret_cast(inIv.ptr), reinterpret_cast(inKey.ptr), inKey.length, 0, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } auto tptr = reinterpret_cast(plainText.ptr); if (auCoolCodePadding) { if (!EncryptCoolCodePadding(tptr, plainText.length, inIv.ptr, outIv.ptr, inIv.length, inKey.ptr, inKey.length, out, cbc)) { return false; } } else { if ((plainText.length & (16 - 1)) != 0) { SysPushErrorArg("{}", plainText.length); return false; } ret = cbc_encrypt(tptr, out.data(), plainText.length, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } } if (outIv.ptr) { unsigned long ivLength = 16; ret = cbc_getiv(reinterpret_cast(outIv.ptr), &ivLength, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } } return true; } AUKN_SYM bool Decrypt(const AuMemoryViewRead &cipherText, const AuMemoryViewRead &inIv, const AuMemoryViewWrite &outIv, const AuMemoryViewRead &inKey, AuByteBuffer &plainText, bool safe) { symmetric_CBC cbc; if (!cipherText.length) { return false; } if (!cipherText.ptr) { return false; } if (!inIv.length) { return false; } if (!inIv.ptr) { return false; } if (!inKey.length) { return false; } if (!inKey.ptr) { return false; } if (inIv.length != 16) { SysPushErrorCrypt("{}", inIv.length); return false; } if (outIv.length) { if (inIv.length != outIv.length) { SysPushErrorCrypt("{}", outIv.length); return false; } } if ((inKey.length != 16) && (inKey.length != 24) && (inKey.length != 32)) { SysPushErrorCrypt("{}", inKey.length); return false; } auto ret = cbc_start(::Crypto::gAesCipher, reinterpret_cast(inIv.ptr), reinterpret_cast(inKey.ptr), inKey.length, 0, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } auto tptr = reinterpret_cast(cipherText.ptr); if (!AuTryResize(plainText, cipherText.length)) { SysPushErrorMem(); return false; } ret = cbc_decrypt(tptr, plainText.data(), cipherText.length, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } if (safe) { auto magic = plainText[cipherText.length - 1]; if (magic <= 128) { plainText.resize(cipherText.length - magic); } } if (outIv.ptr) { unsigned long ivLength = 16; ret = cbc_getiv(reinterpret_cast(outIv.ptr), &ivLength, &cbc); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } } return true; } }