/* * Botan 2.18.1 Amalgamation * (C) 1999-2020 The Botan Authors * * Botan is released under the Simplified BSD License (see license.txt) */ #include "botan_all.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //BOTAN_FUTURE_INTERNAL_HEADER(atomic.h) namespace Botan { template /** * Simple helper class to expand std::atomic with copy constructor and copy * assignment operator, i.e. for use as element in a container like * std::vector. The construction of instances of this wrapper is NOT atomic * and needs to be properly guarded. **/ class Atomic final { public: Atomic() = default; Atomic(const Atomic& data) : m_data(data.m_data.load()) {} Atomic(const std::atomic& data) : m_data(data.load()) {} ~Atomic() = default; Atomic& operator=(const Atomic& a) { m_data.store(a.m_data.load()); return *this; } Atomic& operator=(const std::atomic& a) { m_data.store(a.load()); return *this; } operator std::atomic& () { return m_data; } operator T() { return m_data.load(); } private: std::atomic m_data; }; } namespace Botan { /** Barrier implements a barrier synchronization primitive. wait() will indicate how many threads to synchronize; each thread needing synchronization should call sync(). When sync() returns, the barrier is reset to zero, and the m_syncs counter is incremented. m_syncs is a counter to ensure that wait() can be called after a sync() even if the previously sleeping threads have not awoken.) */ class Barrier final { public: explicit Barrier(int value = 0) : m_value(value), m_syncs(0) {} void wait(size_t delta); void sync(); private: size_t m_value; size_t m_syncs; std::mutex m_mutex; std::condition_variable m_cond; }; } namespace Botan { /** * If top bit of arg is set, return ~0. Otherwise return 0. */ template inline T expand_top_bit(T a) { return static_cast(0) - (a >> (sizeof(T)*8-1)); } /** * If arg is zero, return ~0. Otherwise return 0 */ template inline T ct_is_zero(T x) { return expand_top_bit(~x & (x - 1)); } /** * Power of 2 test. T should be an unsigned integer type * @param arg an integer value * @return true iff arg is 2^n for some n > 0 */ template inline constexpr bool is_power_of_2(T arg) { return (arg != 0) && (arg != 1) && ((arg & static_cast(arg-1)) == 0); } /** * Return the index of the highest set bit * T is an unsigned integer type * @param n an integer value * @return index of the highest set bit in n */ template inline size_t high_bit(T n) { size_t hb = 0; for(size_t s = 8*sizeof(T) / 2; s > 0; s /= 2) { const size_t z = s * ((~ct_is_zero(n >> s)) & 1); hb += z; n >>= z; } hb += n; return hb; } /** * Return the number of significant bytes in n * @param n an integer value * @return number of significant bytes in n */ template inline size_t significant_bytes(T n) { size_t b = 0; for(size_t s = 8*sizeof(n) / 2; s >= 8; s /= 2) { const size_t z = s * (~ct_is_zero(n >> s) & 1); b += z/8; n >>= z; } b += (n != 0); return b; } /** * Count the trailing zero bits in n * @param n an integer value * @return maximum x st 2^x divides n */ template inline size_t ctz(T n) { /* * If n == 0 then this function will compute 8*sizeof(T)-1, so * initialize lb to 1 if n == 0 to produce the expected result. */ size_t lb = ct_is_zero(n) & 1; for(size_t s = 8*sizeof(T) / 2; s > 0; s /= 2) { const T mask = (static_cast(1) << s) - 1; const size_t z = s * (ct_is_zero(n & mask) & 1); lb += z; n >>= z; } return lb; } template uint8_t ceil_log2(T x) { static_assert(sizeof(T) < 32, "Abnormally large scalar"); if(x >> (sizeof(T)*8-1)) return sizeof(T)*8; uint8_t result = 0; T compare = 1; while(compare < x) { compare <<= 1; result++; } return result; } // Potentially variable time ctz used for OCB inline size_t var_ctz32(uint32_t n) { #if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) if(n == 0) return 32; return __builtin_ctz(n); #else return ctz(n); #endif } template inline T bit_permute_step(T x, T mask, size_t shift) { /* See https://reflectionsonsecurity.wordpress.com/2014/05/11/efficient-bit-permutation-using-delta-swaps/ and http://programming.sirrida.de/bit_perm.html */ const T swap = ((x >> shift) ^ x) & mask; return (x ^ swap) ^ (swap << shift); } template inline void swap_bits(T& x, T& y, T mask, size_t shift) { const T swap = ((x >> shift) ^ y) & mask; x ^= swap << shift; y ^= swap; } } namespace Botan { alignas(64) const uint32_t CAST_SBOX1[256] = { 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; alignas(64) const uint32_t CAST_SBOX2[256] = { 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; alignas(64) const uint32_t CAST_SBOX3[256] = { 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; alignas(64) const uint32_t CAST_SBOX4[256] = { 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; } namespace Botan { /** * Expand an input to a bit mask depending on it being being zero or non-zero * @param tst the input * @return the mask 0xFFFF if tst is non-zero and 0 otherwise */ template uint16_t expand_mask_16bit(T tst) { const uint16_t result = (tst != 0); return ~(result - 1); } inline gf2m gray_to_lex(gf2m gray) { gf2m result = gray ^ (gray >> 8); result ^= (result >> 4); result ^= (result >> 2); result ^= (result >> 1); return result; } inline gf2m lex_to_gray(gf2m lex) { return (lex >> 1) ^ lex; } inline size_t bit_size_to_byte_size(size_t bit_size) { return (bit_size - 1) / 8 + 1; } inline size_t bit_size_to_32bit_size(size_t bit_size) { return (bit_size - 1) / 32 + 1; } } namespace Botan { /** * Perform encoding using the base provided * @param base object giving access to the encodings specifications * @param output an array of at least base.encode_max_output bytes * @param input is some binary data * @param input_length length of input in bytes * @param input_consumed is an output parameter which says how many * bytes of input were actually consumed. If less than * input_length, then the range input[consumed:length] * should be passed in later along with more input. * @param final_inputs true iff this is the last input, in which case padding chars will be applied if needed * @return number of bytes written to output */ template size_t base_encode(Base&& base, char output[], const uint8_t input[], size_t input_length, size_t& input_consumed, bool final_inputs) { input_consumed = 0; const size_t encoding_bytes_in = base.encoding_bytes_in(); const size_t encoding_bytes_out = base.encoding_bytes_out(); size_t input_remaining = input_length; size_t output_produced = 0; while(input_remaining >= encoding_bytes_in) { base.encode(output + output_produced, input + input_consumed); input_consumed += encoding_bytes_in; output_produced += encoding_bytes_out; input_remaining -= encoding_bytes_in; } if(final_inputs && input_remaining) { std::vector remainder(encoding_bytes_in, 0); for(size_t i = 0; i != input_remaining; ++i) { remainder[i] = input[input_consumed + i]; } base.encode(output + output_produced, remainder.data()); const size_t bits_consumed = base.bits_consumed(); const size_t remaining_bits_before_padding = base.remaining_bits_before_padding(); size_t empty_bits = 8 * (encoding_bytes_in - input_remaining); size_t index = output_produced + encoding_bytes_out - 1; while(empty_bits >= remaining_bits_before_padding) { output[index--] = '='; empty_bits -= bits_consumed; } input_consumed += input_remaining; output_produced += encoding_bytes_out; } return output_produced; } template std::string base_encode_to_string(Base&& base, const uint8_t input[], size_t input_length) { const size_t output_length = base.encode_max_output(input_length); std::string output(output_length, 0); size_t consumed = 0; size_t produced = 0; if(output_length > 0) { produced = base_encode(base, &output.front(), input, input_length, consumed, true); } BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); return output; } /** * Perform decoding using the base provided * @param base object giving access to the encodings specifications * @param output an array of at least Base::decode_max_output bytes * @param input some base input * @param input_length length of input in bytes * @param input_consumed is an output parameter which says how many * bytes of input were actually consumed. If less than * input_length, then the range input[consumed:length] * should be passed in later along with more input. * @param final_inputs true iff this is the last input, in which case padding is allowed * @param ignore_ws ignore whitespace on input; if false, throw an exception if whitespace is encountered * @return number of bytes written to output */ template size_t base_decode(Base&& base, uint8_t output[], const char input[], size_t input_length, size_t& input_consumed, bool final_inputs, bool ignore_ws = true) { const size_t decoding_bytes_in = base.decoding_bytes_in(); const size_t decoding_bytes_out = base.decoding_bytes_out(); uint8_t* out_ptr = output; std::vector decode_buf(decoding_bytes_in, 0); size_t decode_buf_pos = 0; size_t final_truncate = 0; clear_mem(output, base.decode_max_output(input_length)); for(size_t i = 0; i != input_length; ++i) { const uint8_t bin = base.lookup_binary_value(input[i]); if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument { decode_buf[decode_buf_pos] = bin; ++decode_buf_pos; } /* * If we're at the end of the input, pad with 0s and truncate */ if(final_inputs && (i == input_length - 1)) { if(decode_buf_pos) { for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j) { decode_buf[j] = 0; } final_truncate = decoding_bytes_in - decode_buf_pos; decode_buf_pos = decoding_bytes_in; } } if(decode_buf_pos == decoding_bytes_in) { base.decode(out_ptr, decode_buf.data()); out_ptr += decoding_bytes_out; decode_buf_pos = 0; input_consumed = i+1; } } while(input_consumed < input_length && base.lookup_binary_value(input[input_consumed]) == 0x80) { ++input_consumed; } size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate); return written; } template size_t base_decode_full(Base&& base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws) { size_t consumed = 0; const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws); if(consumed != input_length) { throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes"); } return written; } template Vector base_decode_to_vec(Base&& base, const char input[], size_t input_length, bool ignore_ws) { const size_t output_length = base.decode_max_output(input_length); Vector bin(output_length); const size_t written = base_decode_full(base, bin.data(), input, input_length, ignore_ws); bin.resize(written); return bin; } } #if defined(BOTAN_HAS_VALGRIND) #include #endif namespace Botan { namespace CT { /** * Use valgrind to mark the contents of memory as being undefined. * Valgrind will accept operations which manipulate undefined values, * but will warn if an undefined value is used to decided a conditional * jump or a load/store address. So if we poison all of our inputs we * can confirm that the operations in question are truly const time * when compiled by whatever compiler is in use. * * Even better, the VALGRIND_MAKE_MEM_* macros work even when the * program is not run under valgrind (though with a few cycles of * overhead, which is unfortunate in final binaries as these * annotations tend to be used in fairly important loops). * * This approach was first used in ctgrind (https://github.com/agl/ctgrind) * but calling the valgrind mecheck API directly works just as well and * doesn't require a custom patched valgrind. */ template inline void poison(const T* p, size_t n) { #if defined(BOTAN_HAS_VALGRIND) VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); #else BOTAN_UNUSED(p); BOTAN_UNUSED(n); #endif } template inline void unpoison(const T* p, size_t n) { #if defined(BOTAN_HAS_VALGRIND) VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); #else BOTAN_UNUSED(p); BOTAN_UNUSED(n); #endif } template inline void unpoison(T& p) { #if defined(BOTAN_HAS_VALGRIND) VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); #else BOTAN_UNUSED(p); #endif } /** * A Mask type used for constant-time operations. A Mask always has value * either 0 (all bits cleared) or ~0 (all bits set). All operations in a Mask * are intended to compile to code which does not contain conditional jumps. * This must be verified with tooling (eg binary disassembly or using valgrind) * since you never know what a compiler might do. */ template class Mask { public: static_assert(std::is_unsigned::value, "CT::Mask only defined for unsigned integer types"); Mask(const Mask& other) = default; Mask& operator=(const Mask& other) = default; /** * Derive a Mask from a Mask of a larger type */ template Mask(Mask o) : m_mask(static_cast(o.value())) { static_assert(sizeof(U) > sizeof(T), "sizes ok"); } /** * Return a Mask with all bits set */ static Mask set() { return Mask(static_cast(~0)); } /** * Return a Mask with all bits cleared */ static Mask cleared() { return Mask(0); } /** * Return a Mask which is set if v is != 0 */ static Mask expand(T v) { return ~Mask::is_zero(v); } /** * Return a Mask which is set if m is set */ template static Mask expand(Mask m) { static_assert(sizeof(U) < sizeof(T), "sizes ok"); return ~Mask::is_zero(m.value()); } /** * Return a Mask which is set if v is == 0 or cleared otherwise */ static Mask is_zero(T x) { return Mask(ct_is_zero(x)); } /** * Return a Mask which is set if x == y */ static Mask is_equal(T x, T y) { return Mask::is_zero(static_cast(x ^ y)); } /** * Return a Mask which is set if x < y */ static Mask is_lt(T x, T y) { return Mask(expand_top_bit(x^((x^y) | ((x-y)^x)))); } /** * Return a Mask which is set if x > y */ static Mask is_gt(T x, T y) { return Mask::is_lt(y, x); } /** * Return a Mask which is set if x <= y */ static Mask is_lte(T x, T y) { return ~Mask::is_gt(x, y); } /** * Return a Mask which is set if x >= y */ static Mask is_gte(T x, T y) { return ~Mask::is_lt(x, y); } static Mask is_within_range(T v, T l, T u) { //return Mask::is_gte(v, l) & Mask::is_lte(v, u); const T v_lt_l = v^((v^l) | ((v-l)^v)); const T v_gt_u = u^((u^v) | ((u-v)^u)); const T either = v_lt_l | v_gt_u; return ~Mask(expand_top_bit(either)); } static Mask is_any_of(T v, std::initializer_list accepted) { T accept = 0; for(auto a: accepted) { const T diff = a ^ v; const T eq_zero = ~diff & (diff - 1); accept |= eq_zero; } return Mask(expand_top_bit(accept)); } /** * AND-combine two masks */ Mask& operator&=(Mask o) { m_mask &= o.value(); return (*this); } /** * XOR-combine two masks */ Mask& operator^=(Mask o) { m_mask ^= o.value(); return (*this); } /** * OR-combine two masks */ Mask& operator|=(Mask o) { m_mask |= o.value(); return (*this); } /** * AND-combine two masks */ friend Mask operator&(Mask x, Mask y) { return Mask(x.value() & y.value()); } /** * XOR-combine two masks */ friend Mask operator^(Mask x, Mask y) { return Mask(x.value() ^ y.value()); } /** * OR-combine two masks */ friend Mask operator|(Mask x, Mask y) { return Mask(x.value() | y.value()); } /** * Negate this mask */ Mask operator~() const { return Mask(~value()); } /** * Return x if the mask is set, or otherwise zero */ T if_set_return(T x) const { return m_mask & x; } /** * Return x if the mask is cleared, or otherwise zero */ T if_not_set_return(T x) const { return ~m_mask & x; } /** * If this mask is set, return x, otherwise return y */ T select(T x, T y) const { // (x & value()) | (y & ~value()) return static_cast(y ^ (value() & (x ^ y))); } T select_and_unpoison(T x, T y) const { T r = this->select(x, y); CT::unpoison(r); return r; } /** * If this mask is set, return x, otherwise return y */ Mask select_mask(Mask x, Mask y) const { return Mask(select(x.value(), y.value())); } /** * Conditionally set output to x or y, depending on if mask is set or * cleared (resp) */ void select_n(T output[], const T x[], const T y[], size_t len) const { for(size_t i = 0; i != len; ++i) output[i] = this->select(x[i], y[i]); } /** * If this mask is set, zero out buf, otherwise do nothing */ void if_set_zero_out(T buf[], size_t elems) { for(size_t i = 0; i != elems; ++i) { buf[i] = this->if_not_set_return(buf[i]); } } /** * Return the value of the mask, unpoisoned */ T unpoisoned_value() const { T r = value(); CT::unpoison(r); return r; } /** * Return true iff this mask is set */ bool is_set() const { return unpoisoned_value() != 0; } /** * Return the underlying value of the mask */ T value() const { return m_mask; } private: Mask(T m) : m_mask(m) {} T m_mask; }; template inline Mask conditional_copy_mem(T cnd, T* to, const T* from0, const T* from1, size_t elems) { const auto mask = CT::Mask::expand(cnd); mask.select_n(to, from0, from1, elems); return mask; } template inline void conditional_swap(bool cnd, T& x, T& y) { const auto swap = CT::Mask::expand(cnd); T t0 = swap.select(y, x); T t1 = swap.select(x, y); x = t0; y = t1; } template inline void conditional_swap_ptr(bool cnd, T& x, T& y) { uintptr_t xp = reinterpret_cast(x); uintptr_t yp = reinterpret_cast(y); conditional_swap(cnd, xp, yp); x = reinterpret_cast(xp); y = reinterpret_cast(yp); } /** * If bad_mask is unset, return in[delim_idx:input_length] copied to * new buffer. If bad_mask is set, return an all zero vector of * unspecified length. */ secure_vector copy_output(CT::Mask bad_input, const uint8_t input[], size_t input_length, size_t delim_idx); secure_vector strip_leading_zeros(const uint8_t in[], size_t length); inline secure_vector strip_leading_zeros(const secure_vector& in) { return strip_leading_zeros(in.data(), in.size()); } } } namespace Botan { class donna128 final { public: donna128(uint64_t ll = 0, uint64_t hh = 0) { l = ll; h = hh; } donna128(const donna128&) = default; donna128& operator=(const donna128&) = default; friend donna128 operator>>(const donna128& x, size_t shift) { donna128 z = x; if(shift > 0) { const uint64_t carry = z.h << (64 - shift); z.h = (z.h >> shift); z.l = (z.l >> shift) | carry; } return z; } friend donna128 operator<<(const donna128& x, size_t shift) { donna128 z = x; if(shift > 0) { const uint64_t carry = z.l >> (64 - shift); z.l = (z.l << shift); z.h = (z.h << shift) | carry; } return z; } friend uint64_t operator&(const donna128& x, uint64_t mask) { return x.l & mask; } uint64_t operator&=(uint64_t mask) { h = 0; l &= mask; return l; } donna128& operator+=(const donna128& x) { l += x.l; h += x.h; const uint64_t carry = (l < x.l); h += carry; return *this; } donna128& operator+=(uint64_t x) { l += x; const uint64_t carry = (l < x); h += carry; return *this; } uint64_t lo() const { return l; } uint64_t hi() const { return h; } private: uint64_t h = 0, l = 0; }; inline donna128 operator*(const donna128& x, uint64_t y) { BOTAN_ARG_CHECK(x.hi() == 0, "High 64 bits of donna128 set to zero during multiply"); uint64_t lo = 0, hi = 0; mul64x64_128(x.lo(), y, &lo, &hi); return donna128(lo, hi); } inline donna128 operator*(uint64_t y, const donna128& x) { return x * y; } inline donna128 operator+(const donna128& x, const donna128& y) { donna128 z = x; z += y; return z; } inline donna128 operator+(const donna128& x, uint64_t y) { donna128 z = x; z += y; return z; } inline donna128 operator|(const donna128& x, const donna128& y) { return donna128(x.lo() | y.lo(), x.hi() | y.hi()); } inline uint64_t carry_shift(const donna128& a, size_t shift) { return (a >> shift).lo(); } inline uint64_t combine_lower(const donna128& a, size_t s1, const donna128& b, size_t s2) { donna128 z = (a >> s1) | (b << s2); return z.lo(); } #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) inline uint64_t carry_shift(const uint128_t a, size_t shift) { return static_cast(a >> shift); } inline uint64_t combine_lower(const uint128_t a, size_t s1, const uint128_t b, size_t s2) { return static_cast((a >> s1) | (b << s2)); } #endif } namespace Botan { /** * An element of the field \\Z/(2^255-19) */ class FE_25519 { public: ~FE_25519() { secure_scrub_memory(m_fe, sizeof(m_fe)); } /** * Zero element */ FE_25519(int init = 0) { if(init != 0 && init != 1) throw Invalid_Argument("Invalid FE_25519 initial value"); clear_mem(m_fe, 10); m_fe[0] = init; } FE_25519(std::initializer_list x) { if(x.size() != 10) throw Invalid_Argument("Invalid FE_25519 initializer list"); copy_mem(m_fe, x.begin(), 10); } FE_25519(int64_t h0, int64_t h1, int64_t h2, int64_t h3, int64_t h4, int64_t h5, int64_t h6, int64_t h7, int64_t h8, int64_t h9) { m_fe[0] = static_cast(h0); m_fe[1] = static_cast(h1); m_fe[2] = static_cast(h2); m_fe[3] = static_cast(h3); m_fe[4] = static_cast(h4); m_fe[5] = static_cast(h5); m_fe[6] = static_cast(h6); m_fe[7] = static_cast(h7); m_fe[8] = static_cast(h8); m_fe[9] = static_cast(h9); } FE_25519(const FE_25519& other) = default; FE_25519& operator=(const FE_25519& other) = default; FE_25519(FE_25519&& other) = default; FE_25519& operator=(FE_25519&& other) = default; void from_bytes(const uint8_t b[32]); void to_bytes(uint8_t b[32]) const; bool is_zero() const { uint8_t s[32]; to_bytes(s); uint8_t sum = 0; for(size_t i = 0; i != 32; ++i) { sum |= s[i]; } // TODO avoid ternary here return (sum == 0) ? 1 : 0; } /* return 1 if f is in {1,3,5,...,q-2} return 0 if f is in {0,2,4,...,q-1} */ bool is_negative() const { // TODO could avoid most of the to_bytes computation here uint8_t s[32]; to_bytes(s); return s[0] & 1; } static FE_25519 add(const FE_25519& a, const FE_25519& b) { FE_25519 z; for(size_t i = 0; i != 10; ++i) { z[i] = a[i] + b[i]; } return z; } static FE_25519 sub(const FE_25519& a, const FE_25519& b) { FE_25519 z; for(size_t i = 0; i != 10; ++i) { z[i] = a[i] - b[i]; } return z; } static FE_25519 negate(const FE_25519& a) { FE_25519 z; for(size_t i = 0; i != 10; ++i) { z[i] = -a[i]; } return z; } static FE_25519 mul(const FE_25519& a, const FE_25519& b); static FE_25519 sqr_iter(const FE_25519& a, size_t iter); static FE_25519 sqr(const FE_25519& a) { return sqr_iter(a, 1); } static FE_25519 sqr2(const FE_25519& a); static FE_25519 pow_22523(const FE_25519& a); static FE_25519 invert(const FE_25519& a); // TODO remove int32_t operator[](size_t i) const { return m_fe[i]; } int32_t& operator[](size_t i) { return m_fe[i]; } private: int32_t m_fe[10]; }; typedef FE_25519 fe; /* fe means field element. Here the field is An element t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on context. */ inline void fe_frombytes(fe& x, const uint8_t* b) { x.from_bytes(b); } inline void fe_tobytes(uint8_t* b, const fe& x) { x.to_bytes(b); } inline void fe_copy(fe& a, const fe& b) { a = b; } inline int fe_isnonzero(const fe& x) { return x.is_zero() ? 0 : 1; } inline int fe_isnegative(const fe& x) { return x.is_negative(); } inline void fe_0(fe& x) { x = FE_25519(); } inline void fe_1(fe& x) { x = FE_25519(1); } inline void fe_add(fe& x, const fe& a, const fe& b) { x = FE_25519::add(a, b); } inline void fe_sub(fe& x, const fe& a, const fe& b) { x = FE_25519::sub(a, b); } inline void fe_neg(fe& x, const fe& z) { x = FE_25519::negate(z); } inline void fe_mul(fe& x, const fe& a, const fe& b) { x = FE_25519::mul(a, b); } inline void fe_sq(fe& x, const fe& z) { x = FE_25519::sqr(z); } inline void fe_sq_iter(fe& x, const fe& z, size_t iter) { x = FE_25519::sqr_iter(z, iter); } inline void fe_sq2(fe& x, const fe& z) { x = FE_25519::sqr2(z); } inline void fe_invert(fe& x, const fe& z) { x = FE_25519::invert(z); } inline void fe_pow22523(fe& x, const fe& y) { x = FE_25519::pow_22523(y); } } namespace Botan { inline uint64_t load_3(const uint8_t in[3]) { return static_cast(in[0]) | (static_cast(in[1]) << 8) | (static_cast(in[2]) << 16); } inline uint64_t load_4(const uint8_t* in) { return load_le(in, 0); } template inline void carry(int64_t& h0, int64_t& h1) { static_assert(S > 0 && S < 64, "Shift in range"); const int64_t X1 = (static_cast(1) << S); const int64_t X2 = (static_cast(1) << (S - 1)); int64_t c = (h0 + X2) >> S; h1 += c * MUL; h0 -= c * X1; } template inline void carry0(int64_t& h0, int64_t& h1) { static_assert(S > 0 && S < 64, "Shift in range"); const int64_t X1 = (static_cast(1) << S); int64_t c = h0 >> S; h1 += c; h0 -= c * X1; } template inline void carry0(int32_t& h0, int32_t& h1) { static_assert(S > 0 && S < 32, "Shift in range"); const int32_t X1 = (static_cast(1) << S); int32_t c = h0 >> S; h1 += c; h0 -= c * X1; } inline void redc_mul(int64_t& s1, int64_t& s2, int64_t& s3, int64_t& s4, int64_t& s5, int64_t& s6, int64_t& X) { s1 += X * 666643; s2 += X * 470296; s3 += X * 654183; s4 -= X * 997805; s5 += X * 136657; s6 -= X * 683901; X = 0; } /* ge means group element. Here the group is the set of pairs (x,y) of field elements (see fe.h) satisfying -x^2 + y^2 = 1 + d x^2y^2 where d = -121665/121666. Representations: ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT */ typedef struct { fe X; fe Y; fe Z; fe T; } ge_p3; int ge_frombytes_negate_vartime(ge_p3*, const uint8_t*); void ge_scalarmult_base(uint8_t out[32], const uint8_t in[32]); void ge_double_scalarmult_vartime(uint8_t out[32], const uint8_t a[], const ge_p3* A, const uint8_t b[]); /* The set of scalars is \Z/l where l = 2^252 + 27742317777372353535851937790883648493. */ void sc_reduce(uint8_t*); void sc_muladd(uint8_t*, const uint8_t*, const uint8_t*, const uint8_t*); } namespace Botan { /** * Win32 Entropy Source */ class Win32_EntropySource final : public Entropy_Source { public: std::string name() const override { return "system_stats"; } size_t poll(RandomNumberGenerator& rng) override; }; } namespace Botan_FFI { class BOTAN_UNSTABLE_API FFI_Error final : public Botan::Exception { public: FFI_Error(const std::string& what, int err_code) : Exception("FFI error", what), m_err_code(err_code) {} int error_code() const noexcept override { return m_err_code; } Botan::ErrorType error_type() const noexcept override { return Botan::ErrorType::InvalidArgument; } private: int m_err_code; }; template struct botan_struct { public: botan_struct(T* obj) : m_magic(MAGIC), m_obj(obj) {} virtual ~botan_struct() { m_magic = 0; m_obj.reset(); } bool magic_ok() const { return (m_magic == MAGIC); } T* unsafe_get() const { return m_obj.get(); } private: uint32_t m_magic = 0; std::unique_ptr m_obj; }; #define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \ struct NAME final : public Botan_FFI::botan_struct { explicit NAME(TYPE* x) : botan_struct(x) {} } // Declared in ffi.cpp int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc = BOTAN_FFI_ERROR_EXCEPTION_THROWN); template T& safe_get(botan_struct* p) { if(!p) throw FFI_Error("Null pointer argument", BOTAN_FFI_ERROR_NULL_POINTER); if(p->magic_ok() == false) throw FFI_Error("Bad magic in ffi object", BOTAN_FFI_ERROR_INVALID_OBJECT); if(T* t = p->unsafe_get()) return *t; throw FFI_Error("Invalid object pointer", BOTAN_FFI_ERROR_INVALID_OBJECT); } int ffi_guard_thunk(const char* func_name, std::function); template int apply_fn(botan_struct* o, const char* func_name, F func) { if(!o) return BOTAN_FFI_ERROR_NULL_POINTER; if(o->magic_ok() == false) return BOTAN_FFI_ERROR_INVALID_OBJECT; T* p = o->unsafe_get(); if(p == nullptr) return BOTAN_FFI_ERROR_INVALID_OBJECT; return ffi_guard_thunk(func_name, [&]() { return func(*p); }); } #define BOTAN_FFI_DO(T, obj, param, block) \ apply_fn(obj, __func__, \ [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; }) /* * Like BOTAN_FFI_DO but with no trailing return with the expectation * that the block always returns a value. This exists because otherwise * MSVC warns about the dead return after the block in FFI_DO. */ #define BOTAN_FFI_RETURNING(T, obj, param, block) \ apply_fn(obj, __func__, \ [=](T& param) -> int { do { block } while(0); }) template int ffi_delete_object(botan_struct* obj, const char* func_name) { try { if(obj == nullptr) return BOTAN_FFI_SUCCESS; // ignore delete of null objects if(obj->magic_ok() == false) return BOTAN_FFI_ERROR_INVALID_OBJECT; delete obj; return BOTAN_FFI_SUCCESS; } catch(std::exception& e) { return ffi_error_exception_thrown(func_name, e.what()); } catch(...) { return ffi_error_exception_thrown(func_name, "unknown exception"); } } #define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, __func__) inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len) { if(out_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; const size_t avail = *out_len; *out_len = buf_len; if((avail >= buf_len) && (out != nullptr)) { Botan::copy_mem(out, buf, buf_len); return BOTAN_FFI_SUCCESS; } else { if(out != nullptr) { Botan::clear_mem(out, avail); } return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; } } template int write_vec_output(uint8_t out[], size_t* out_len, const std::vector& buf) { return write_output(out, out_len, buf.data(), buf.size()); } inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str) { return write_output(out, out_len, Botan::cast_char_ptr_to_uint8(str.data()), str.size() + 1); } inline int write_str_output(char out[], size_t* out_len, const std::string& str) { return write_str_output(Botan::cast_char_ptr_to_uint8(out), out_len, str); } inline int write_str_output(char out[], size_t* out_len, const std::vector& str_vec) { return write_output(Botan::cast_char_ptr_to_uint8(out), out_len, str_vec.data(), str_vec.size()); } } extern "C" { BOTAN_FFI_DECLARE_STRUCT(botan_mp_struct, Botan::BigInt, 0xC828B9D2); } extern "C" { BOTAN_FFI_DECLARE_STRUCT(botan_pubkey_struct, Botan::Public_Key, 0x2C286519); BOTAN_FFI_DECLARE_STRUCT(botan_privkey_struct, Botan::Private_Key, 0x7F96385E); } extern "C" { BOTAN_FFI_DECLARE_STRUCT(botan_rng_struct, Botan::RandomNumberGenerator, 0x4901F9C1); } namespace Botan { /** * No_Filesystem_Access Exception */ class BOTAN_PUBLIC_API(2,0) No_Filesystem_Access final : public Exception { public: No_Filesystem_Access() : Exception("No filesystem access enabled.") {} }; BOTAN_TEST_API bool has_filesystem_impl(); BOTAN_TEST_API std::vector get_files_recursive(const std::string& dir); } namespace Botan { void mceliece_decrypt(secure_vector& plaintext_out, secure_vector& error_mask_out, const uint8_t ciphertext[], size_t ciphertext_len, const McEliece_PrivateKey& key); void mceliece_decrypt(secure_vector& plaintext_out, secure_vector& error_mask_out, const secure_vector& ciphertext, const McEliece_PrivateKey& key); secure_vector mceliece_decrypt( secure_vector & error_pos, const uint8_t *ciphertext, size_t ciphertext_len, const McEliece_PrivateKey & key); void mceliece_encrypt(secure_vector& ciphertext_out, secure_vector& error_mask_out, const secure_vector& plaintext, const McEliece_PublicKey& key, RandomNumberGenerator& rng); McEliece_PrivateKey generate_mceliece_key(RandomNumberGenerator &rng, size_t ext_deg, size_t code_length, size_t t); } namespace Botan { class Bucket; class BOTAN_TEST_API Memory_Pool final { public: /** * Initialize a memory pool. The memory is not owned by *this, * it must be freed by the caller. * @param pages a list of pages to allocate from * @param page_size the system page size, each page should * point to exactly this much memory. */ Memory_Pool(const std::vector& pages, size_t page_size); ~Memory_Pool(); void* allocate(size_t size); bool deallocate(void* p, size_t size) noexcept; Memory_Pool(const Memory_Pool&) = delete; Memory_Pool(Memory_Pool&&) = delete; Memory_Pool& operator=(const Memory_Pool&) = delete; Memory_Pool& operator=(Memory_Pool&&) = delete; private: const size_t m_page_size = 0; mutex_type m_mutex; std::deque m_free_pages; std::map> m_buckets_for; uintptr_t m_min_page_ptr; uintptr_t m_max_page_ptr; }; } namespace Botan { class BigInt; class Modular_Reducer; class Montgomery_Params; class Montgomery_Exponentation_State; /* * Precompute for calculating values g^x mod p */ std::shared_ptr monty_precompute(std::shared_ptr params_p, const BigInt& g, size_t window_bits, bool const_time = true); /* * Return g^k mod p */ BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k, size_t max_k_bits); /* * Return g^k mod p taking variable time depending on k * @warning only use this if k is public */ BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k); /** * Return (x^z1 * y^z2) % p */ BigInt monty_multi_exp(std::shared_ptr params_p, const BigInt& x, const BigInt& z1, const BigInt& y, const BigInt& z2); } namespace Botan { #if (BOTAN_MP_WORD_BITS == 32) typedef uint64_t dword; #define BOTAN_HAS_MP_DWORD #elif (BOTAN_MP_WORD_BITS == 64) #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) typedef uint128_t dword; #define BOTAN_HAS_MP_DWORD #else // No native 128 bit integer type; use mul64x64_128 instead #endif #else #error BOTAN_MP_WORD_BITS must be 32 or 64 #endif #if defined(BOTAN_USE_GCC_INLINE_ASM) #if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32) #define BOTAN_MP_USE_X86_32_ASM #elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) #define BOTAN_MP_USE_X86_64_ASM #endif #endif /* * Word Multiply/Add */ inline word word_madd2(word a, word b, word* c) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm(R"( mull %[b] addl %[c],%[a] adcl $0,%[carry] )" : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) : "0"(a), "1"(b), [c]"g"(*c) : "cc"); return a; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm(R"( mulq %[b] addq %[c],%[a] adcq $0,%[carry] )" : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) : "0"(a), "1"(b), [c]"g"(*c) : "cc"); return a; #elif defined(BOTAN_HAS_MP_DWORD) const dword s = static_cast(a) * b + *c; *c = static_cast(s >> BOTAN_MP_WORD_BITS); return static_cast(s); #else static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); word hi = 0, lo = 0; mul64x64_128(a, b, &lo, &hi); lo += *c; hi += (lo < *c); // carry? *c = hi; return lo; #endif } /* * Word Multiply/Add */ inline word word_madd3(word a, word b, word c, word* d) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm(R"( mull %[b] addl %[c],%[a] adcl $0,%[carry] addl %[d],%[a] adcl $0,%[carry] )" : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); return a; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm(R"( mulq %[b] addq %[c],%[a] adcq $0,%[carry] addq %[d],%[a] adcq $0,%[carry] )" : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); return a; #elif defined(BOTAN_HAS_MP_DWORD) const dword s = static_cast(a) * b + c + *d; *d = static_cast(s >> BOTAN_MP_WORD_BITS); return static_cast(s); #else static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); word hi = 0, lo = 0; mul64x64_128(a, b, &lo, &hi); lo += c; hi += (lo < c); // carry? lo += *d; hi += (lo < *d); // carry? *d = hi; return lo; #endif } } namespace Botan { #if defined(BOTAN_MP_USE_X86_32_ASM) #define ADDSUB2_OP(OPERATION, INDEX) \ ASM("movl 4*" #INDEX "(%[y]), %[carry]") \ ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \ #define ADDSUB3_OP(OPERATION, INDEX) \ ASM("movl 4*" #INDEX "(%[x]), %[carry]") \ ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \ ASM("movl %[carry], 4*" #INDEX "(%[z])") \ #define LINMUL_OP(WRITE_TO, INDEX) \ ASM("movl 4*" #INDEX "(%[x]),%%eax") \ ASM("mull %[y]") \ ASM("addl %[carry],%%eax") \ ASM("adcl $0,%%edx") \ ASM("movl %%edx,%[carry]") \ ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])") #define MULADD_OP(IGNORED, INDEX) \ ASM("movl 4*" #INDEX "(%[x]),%%eax") \ ASM("mull %[y]") \ ASM("addl %[carry],%%eax") \ ASM("adcl $0,%%edx") \ ASM("addl 4*" #INDEX "(%[z]),%%eax") \ ASM("adcl $0,%%edx") \ ASM("movl %%edx,%[carry]") \ ASM("movl %%eax, 4*" #INDEX " (%[z])") #define ADD_OR_SUBTRACT(CORE_CODE) \ ASM("rorl %[carry]") \ CORE_CODE \ ASM("sbbl %[carry],%[carry]") \ ASM("negl %[carry]") #elif defined(BOTAN_MP_USE_X86_64_ASM) #define ADDSUB2_OP(OPERATION, INDEX) \ ASM("movq 8*" #INDEX "(%[y]), %[carry]") \ ASM(OPERATION " %[carry], 8*" #INDEX "(%[x])") \ #define ADDSUB3_OP(OPERATION, INDEX) \ ASM("movq 8*" #INDEX "(%[x]), %[carry]") \ ASM(OPERATION " 8*" #INDEX "(%[y]), %[carry]") \ ASM("movq %[carry], 8*" #INDEX "(%[z])") \ #define LINMUL_OP(WRITE_TO, INDEX) \ ASM("movq 8*" #INDEX "(%[x]),%%rax") \ ASM("mulq %[y]") \ ASM("addq %[carry],%%rax") \ ASM("adcq $0,%%rdx") \ ASM("movq %%rdx,%[carry]") \ ASM("movq %%rax, 8*" #INDEX "(%[" WRITE_TO "])") #define MULADD_OP(IGNORED, INDEX) \ ASM("movq 8*" #INDEX "(%[x]),%%rax") \ ASM("mulq %[y]") \ ASM("addq %[carry],%%rax") \ ASM("adcq $0,%%rdx") \ ASM("addq 8*" #INDEX "(%[z]),%%rax") \ ASM("adcq $0,%%rdx") \ ASM("movq %%rdx,%[carry]") \ ASM("movq %%rax, 8*" #INDEX " (%[z])") #define ADD_OR_SUBTRACT(CORE_CODE) \ ASM("rorq %[carry]") \ CORE_CODE \ ASM("sbbq %[carry],%[carry]") \ ASM("negq %[carry]") #endif #if defined(ADD_OR_SUBTRACT) #define ASM(x) x "\n\t" #define DO_8_TIMES(MACRO, ARG) \ MACRO(ARG, 0) \ MACRO(ARG, 1) \ MACRO(ARG, 2) \ MACRO(ARG, 3) \ MACRO(ARG, 4) \ MACRO(ARG, 5) \ MACRO(ARG, 6) \ MACRO(ARG, 7) #endif /* * Word Addition */ inline word word_add(word x, word y, word* carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]")) : [x]"=r"(x), [carry]"=r"(*carry) : "0"(x), [y]"rm"(y), "1"(*carry) : "cc"); return x; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]")) : [x]"=r"(x), [carry]"=r"(*carry) : "0"(x), [y]"rm"(y), "1"(*carry) : "cc"); return x; #else word z = x + y; word c1 = (z < x); z += *carry; *carry = c1 | (z < *carry); return z; #endif } /* * Eight Word Block Addition, Two Argument */ inline word word8_add2(word x[8], const word y[8], word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), "0"(carry) : "cc", "memory"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), "0"(carry) : "cc", "memory"); return carry; #else x[0] = word_add(x[0], y[0], &carry); x[1] = word_add(x[1], y[1], &carry); x[2] = word_add(x[2], y[2], &carry); x[3] = word_add(x[3], y[3], &carry); x[4] = word_add(x[4], y[4], &carry); x[5] = word_add(x[5], y[5], &carry); x[6] = word_add(x[6], y[6], &carry); x[7] = word_add(x[7], y[7], &carry); return carry; #endif } /* * Eight Word Block Addition, Three Argument */ inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) : "cc", "memory"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) : "cc", "memory"); return carry; #else z[0] = word_add(x[0], y[0], &carry); z[1] = word_add(x[1], y[1], &carry); z[2] = word_add(x[2], y[2], &carry); z[3] = word_add(x[3], y[3], &carry); z[4] = word_add(x[4], y[4], &carry); z[5] = word_add(x[5], y[5], &carry); z[6] = word_add(x[6], y[6], &carry); z[7] = word_add(x[7], y[7], &carry); return carry; #endif } /* * Word Subtraction */ inline word word_sub(word x, word y, word* carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]")) : [x]"=r"(x), [carry]"=r"(*carry) : "0"(x), [y]"rm"(y), "1"(*carry) : "cc"); return x; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]")) : [x]"=r"(x), [carry]"=r"(*carry) : "0"(x), [y]"rm"(y), "1"(*carry) : "cc"); return x; #else word t0 = x - y; word c1 = (t0 > x); word z = t0 - *carry; *carry = c1 | (z > t0); return z; #endif } /* * Eight Word Block Subtraction, Two Argument */ inline word word8_sub2(word x[8], const word y[8], word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), "0"(carry) : "cc", "memory"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), "0"(carry) : "cc", "memory"); return carry; #else x[0] = word_sub(x[0], y[0], &carry); x[1] = word_sub(x[1], y[1], &carry); x[2] = word_sub(x[2], y[2], &carry); x[3] = word_sub(x[3], y[3], &carry); x[4] = word_sub(x[4], y[4], &carry); x[5] = word_sub(x[5], y[5], &carry); x[6] = word_sub(x[6], y[6], &carry); x[7] = word_sub(x[7], y[7], &carry); return carry; #endif } /* * Eight Word Block Subtraction, Two Argument */ inline word word8_sub2_rev(word x[8], const word y[8], word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) : [carry]"=r"(carry) : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) : "cc", "memory"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) : [carry]"=r"(carry) : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) : "cc", "memory"); return carry; #else x[0] = word_sub(y[0], x[0], &carry); x[1] = word_sub(y[1], x[1], &carry); x[2] = word_sub(y[2], x[2], &carry); x[3] = word_sub(y[3], x[3], &carry); x[4] = word_sub(y[4], x[4], &carry); x[5] = word_sub(y[5], x[5], &carry); x[6] = word_sub(y[6], x[6], &carry); x[7] = word_sub(y[7], x[7], &carry); return carry; #endif } /* * Eight Word Block Subtraction, Three Argument */ inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) : "cc", "memory"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) : [carry]"=r"(carry) : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) : "cc", "memory"); return carry; #else z[0] = word_sub(x[0], y[0], &carry); z[1] = word_sub(x[1], y[1], &carry); z[2] = word_sub(x[2], y[2], &carry); z[3] = word_sub(x[3], y[3], &carry); z[4] = word_sub(x[4], y[4], &carry); z[5] = word_sub(x[5], y[5], &carry); z[6] = word_sub(x[6], y[6], &carry); z[7] = word_sub(x[7], y[7], &carry); return carry; #endif } /* * Eight Word Block Linear Multiplication */ inline word word8_linmul2(word x[8], word y, word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( DO_8_TIMES(LINMUL_OP, "x") : [carry]"=r"(carry) : [x]"r"(x), [y]"rm"(y), "0"(carry) : "cc", "%eax", "%edx"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( DO_8_TIMES(LINMUL_OP, "x") : [carry]"=r"(carry) : [x]"r"(x), [y]"rm"(y), "0"(carry) : "cc", "%rax", "%rdx"); return carry; #else x[0] = word_madd2(x[0], y, &carry); x[1] = word_madd2(x[1], y, &carry); x[2] = word_madd2(x[2], y, &carry); x[3] = word_madd2(x[3], y, &carry); x[4] = word_madd2(x[4], y, &carry); x[5] = word_madd2(x[5], y, &carry); x[6] = word_madd2(x[6], y, &carry); x[7] = word_madd2(x[7], y, &carry); return carry; #endif } /* * Eight Word Block Linear Multiplication */ inline word word8_linmul3(word z[8], const word x[8], word y, word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( DO_8_TIMES(LINMUL_OP, "z") : [carry]"=r"(carry) : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) : "cc", "%eax", "%edx"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( DO_8_TIMES(LINMUL_OP, "z") : [carry]"=r"(carry) : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) : "cc", "%rax", "%rdx"); return carry; #else z[0] = word_madd2(x[0], y, &carry); z[1] = word_madd2(x[1], y, &carry); z[2] = word_madd2(x[2], y, &carry); z[3] = word_madd2(x[3], y, &carry); z[4] = word_madd2(x[4], y, &carry); z[5] = word_madd2(x[5], y, &carry); z[6] = word_madd2(x[6], y, &carry); z[7] = word_madd2(x[7], y, &carry); return carry; #endif } /* * Eight Word Block Multiply/Add */ inline word word8_madd3(word z[8], const word x[8], word y, word carry) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm( DO_8_TIMES(MULADD_OP, "") : [carry]"=r"(carry) : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) : "cc", "%eax", "%edx"); return carry; #elif defined(BOTAN_MP_USE_X86_64_ASM) asm( DO_8_TIMES(MULADD_OP, "") : [carry]"=r"(carry) : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) : "cc", "%rax", "%rdx"); return carry; #else z[0] = word_madd3(x[0], y, z[0], &carry); z[1] = word_madd3(x[1], y, z[1], &carry); z[2] = word_madd3(x[2], y, z[2], &carry); z[3] = word_madd3(x[3], y, z[3], &carry); z[4] = word_madd3(x[4], y, z[4], &carry); z[5] = word_madd3(x[5], y, z[5], &carry); z[6] = word_madd3(x[6], y, z[6], &carry); z[7] = word_madd3(x[7], y, z[7], &carry); return carry; #endif } /* * Multiply-Add Accumulator * (w2,w1,w0) += x * y */ inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y) { #if defined(BOTAN_MP_USE_X86_32_ASM) word z0 = 0, z1 = 0; asm("mull %[y]" : "=a"(z0),"=d"(z1) : "a"(x), [y]"rm"(y) : "cc"); asm(R"( addl %[z0],%[w0] adcl %[z1],%[w1] adcl $0,%[w2] )" : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) : "cc"); #elif defined(BOTAN_MP_USE_X86_64_ASM) word z0 = 0, z1 = 0; asm("mulq %[y]" : "=a"(z0),"=d"(z1) : "a"(x), [y]"rm"(y) : "cc"); asm(R"( addq %[z0],%[w0] adcq %[z1],%[w1] adcq $0,%[w2] )" : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) : "cc"); #else word carry = *w0; *w0 = word_madd2(x, y, &carry); *w1 += carry; *w2 += (*w1 < carry); #endif } /* * 3-word addition * (w2,w1,w0) += x */ inline void word3_add(word* w2, word* w1, word* w0, word x) { #if defined(BOTAN_MP_USE_X86_32_ASM) asm(R"( addl %[x],%[w0] adcl $0,%[w1] adcl $0,%[w2] )" : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) : [x]"r"(x), "0"(*w0), "1"(*w1), "2"(*w2) : "cc"); #elif defined(BOTAN_MP_USE_X86_64_ASM) asm(R"( addq %[x],%[w0] adcq $0,%[w1] adcq $0,%[w2] )" : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) : [x]"r"(x), "0"(*w0), "1"(*w1), "2"(*w2) : "cc"); #else *w0 += x; word c1 = (*w0 < x); *w1 += c1; word c2 = (*w1 < c1); *w2 += c2; #endif } /* * Multiply-Add Accumulator * (w2,w1,w0) += 2 * x * y */ inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y) { #if defined(BOTAN_MP_USE_X86_32_ASM) word z0 = 0, z1 = 0; asm("mull %[y]" : "=a"(z0),"=d"(z1) : "a"(x), [y]"rm"(y) : "cc"); asm(R"( addl %[z0],%[w0] adcl %[z1],%[w1] adcl $0,%[w2] addl %[z0],%[w0] adcl %[z1],%[w1] adcl $0,%[w2] )" : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) : "cc"); #elif defined(BOTAN_MP_USE_X86_64_ASM) word z0 = 0, z1 = 0; asm("mulq %[y]" : "=a"(z0),"=d"(z1) : "a"(x), [y]"rm"(y) : "cc"); asm(R"( addq %[z0],%[w0] adcq %[z1],%[w1] adcq $0,%[w2] addq %[z0],%[w0] adcq %[z1],%[w1] adcq $0,%[w2] )" : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) : "cc"); #else word carry = 0; x = word_madd2(x, y, &carry); y = carry; word top = (y >> (BOTAN_MP_WORD_BITS-1)); y <<= 1; y |= (x >> (BOTAN_MP_WORD_BITS-1)); x <<= 1; carry = 0; *w0 = word_add(*w0, x, &carry); *w1 = word_add(*w1, y, &carry); *w2 = word_add(*w2, top, &carry); #endif } #if defined(ASM) #undef ASM #undef DO_8_TIMES #undef ADD_OR_SUBTRACT #undef ADDSUB2_OP #undef ADDSUB3_OP #undef LINMUL_OP #undef MULADD_OP #endif } namespace Botan { const word MP_WORD_MAX = ~static_cast(0); /* * If cond == 0, does nothing. * If cond > 0, swaps x[0:size] with y[0:size] * Runs in constant time */ inline void bigint_cnd_swap(word cnd, word x[], word y[], size_t size) { const auto mask = CT::Mask::expand(cnd); for(size_t i = 0; i != size; ++i) { const word a = x[i]; const word b = y[i]; x[i] = mask.select(b, a); y[i] = mask.select(a, b); } } inline word bigint_cnd_add(word cnd, word x[], word x_size, const word y[], size_t y_size) { BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); const auto mask = CT::Mask::expand(cnd); word carry = 0; const size_t blocks = y_size - (y_size % 8); word z[8] = { 0 }; for(size_t i = 0; i != blocks; i += 8) { carry = word8_add3(z, x + i, y + i, carry); mask.select_n(x + i, z, x + i, 8); } for(size_t i = blocks; i != y_size; ++i) { z[0] = word_add(x[i], y[i], &carry); x[i] = mask.select(z[0], x[i]); } for(size_t i = y_size; i != x_size; ++i) { z[0] = word_add(x[i], 0, &carry); x[i] = mask.select(z[0], x[i]); } return mask.if_set_return(carry); } /* * If cond > 0 adds x[0:size] and y[0:size] and returns carry * Runs in constant time */ inline word bigint_cnd_add(word cnd, word x[], const word y[], size_t size) { return bigint_cnd_add(cnd, x, size, y, size); } /* * If cond > 0 subtracts x[0:size] and y[0:size] and returns borrow * Runs in constant time */ inline word bigint_cnd_sub(word cnd, word x[], size_t x_size, const word y[], size_t y_size) { BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); const auto mask = CT::Mask::expand(cnd); word carry = 0; const size_t blocks = y_size - (y_size % 8); word z[8] = { 0 }; for(size_t i = 0; i != blocks; i += 8) { carry = word8_sub3(z, x + i, y + i, carry); mask.select_n(x + i, z, x + i, 8); } for(size_t i = blocks; i != y_size; ++i) { z[0] = word_sub(x[i], y[i], &carry); x[i] = mask.select(z[0], x[i]); } for(size_t i = y_size; i != x_size; ++i) { z[0] = word_sub(x[i], 0, &carry); x[i] = mask.select(z[0], x[i]); } return mask.if_set_return(carry); } /* * If cond > 0 adds x[0:size] and y[0:size] and returns carry * Runs in constant time */ inline word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size) { return bigint_cnd_sub(cnd, x, size, y, size); } /* * Equivalent to * bigint_cnd_add( mask, x, y, size); * bigint_cnd_sub(~mask, x, y, size); * * Mask must be either 0 or all 1 bits */ inline void bigint_cnd_add_or_sub(CT::Mask mask, word x[], const word y[], size_t size) { const size_t blocks = size - (size % 8); word carry = 0; word borrow = 0; word t0[8] = { 0 }; word t1[8] = { 0 }; for(size_t i = 0; i != blocks; i += 8) { carry = word8_add3(t0, x + i, y + i, carry); borrow = word8_sub3(t1, x + i, y + i, borrow); for(size_t j = 0; j != 8; ++j) x[i+j] = mask.select(t0[j], t1[j]); } for(size_t i = blocks; i != size; ++i) { const word a = word_add(x[i], y[i], &carry); const word s = word_sub(x[i], y[i], &borrow); x[i] = mask.select(a, s); } } /* * Equivalent to * bigint_cnd_add( mask, x, size, y, size); * bigint_cnd_sub(~mask, x, size, z, size); * * Mask must be either 0 or all 1 bits * * Returns the carry or borrow resp */ inline word bigint_cnd_addsub(CT::Mask mask, word x[], const word y[], const word z[], size_t size) { const size_t blocks = size - (size % 8); word carry = 0; word borrow = 0; word t0[8] = { 0 }; word t1[8] = { 0 }; for(size_t i = 0; i != blocks; i += 8) { carry = word8_add3(t0, x + i, y + i, carry); borrow = word8_sub3(t1, x + i, z + i, borrow); for(size_t j = 0; j != 8; ++j) x[i+j] = mask.select(t0[j], t1[j]); } for(size_t i = blocks; i != size; ++i) { t0[0] = word_add(x[i], y[i], &carry); t1[0] = word_sub(x[i], z[i], &borrow); x[i] = mask.select(t0[0], t1[0]); } return mask.select(carry, borrow); } /* * 2s complement absolute value * If cond > 0 sets x to ~x + 1 * Runs in constant time */ inline void bigint_cnd_abs(word cnd, word x[], size_t size) { const auto mask = CT::Mask::expand(cnd); word carry = mask.if_set_return(1); for(size_t i = 0; i != size; ++i) { const word z = word_add(~x[i], 0, &carry); x[i] = mask.select(z, x[i]); } } /** * Two operand addition with carry out */ inline word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) { word carry = 0; BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); const size_t blocks = y_size - (y_size % 8); for(size_t i = 0; i != blocks; i += 8) carry = word8_add2(x + i, y + i, carry); for(size_t i = blocks; i != y_size; ++i) x[i] = word_add(x[i], y[i], &carry); for(size_t i = y_size; i != x_size; ++i) x[i] = word_add(x[i], 0, &carry); return carry; } /** * Three operand addition with carry out */ inline word bigint_add3_nc(word z[], const word x[], size_t x_size, const word y[], size_t y_size) { if(x_size < y_size) { return bigint_add3_nc(z, y, y_size, x, x_size); } word carry = 0; const size_t blocks = y_size - (y_size % 8); for(size_t i = 0; i != blocks; i += 8) carry = word8_add3(z + i, x + i, y + i, carry); for(size_t i = blocks; i != y_size; ++i) z[i] = word_add(x[i], y[i], &carry); for(size_t i = y_size; i != x_size; ++i) z[i] = word_add(x[i], 0, &carry); return carry; } /** * Two operand addition * @param x the first operand (and output) * @param x_size size of x * @param y the second operand * @param y_size size of y (must be >= x_size) */ inline void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) { x[x_size] += bigint_add2_nc(x, x_size, y, y_size); } /** * Three operand addition */ inline void bigint_add3(word z[], const word x[], size_t x_size, const word y[], size_t y_size) { z[x_size > y_size ? x_size : y_size] += bigint_add3_nc(z, x, x_size, y, y_size); } /** * Two operand subtraction */ inline word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size) { word borrow = 0; BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); const size_t blocks = y_size - (y_size % 8); for(size_t i = 0; i != blocks; i += 8) borrow = word8_sub2(x + i, y + i, borrow); for(size_t i = blocks; i != y_size; ++i) x[i] = word_sub(x[i], y[i], &borrow); for(size_t i = y_size; i != x_size; ++i) x[i] = word_sub(x[i], 0, &borrow); return borrow; } /** * Two operand subtraction, x = y - x; assumes y >= x */ inline void bigint_sub2_rev(word x[], const word y[], size_t y_size) { word borrow = 0; const size_t blocks = y_size - (y_size % 8); for(size_t i = 0; i != blocks; i += 8) borrow = word8_sub2_rev(x + i, y + i, borrow); for(size_t i = blocks; i != y_size; ++i) x[i] = word_sub(y[i], x[i], &borrow); BOTAN_ASSERT(borrow == 0, "y must be greater than x"); } /** * Three operand subtraction */ inline word bigint_sub3(word z[], const word x[], size_t x_size, const word y[], size_t y_size) { word borrow = 0; BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); const size_t blocks = y_size - (y_size % 8); for(size_t i = 0; i != blocks; i += 8) borrow = word8_sub3(z + i, x + i, y + i, borrow); for(size_t i = blocks; i != y_size; ++i) z[i] = word_sub(x[i], y[i], &borrow); for(size_t i = y_size; i != x_size; ++i) z[i] = word_sub(x[i], 0, &borrow); return borrow; } /** * Return abs(x-y), ie if x >= y, then compute z = x - y * Otherwise compute z = y - x * No borrow is possible since the result is always >= 0 * * Returns ~0 if x >= y or 0 if x < y * @param z output array of at least N words * @param x input array of N words * @param y input array of N words * @param N length of x and y * @param ws array of at least 2*N words */ inline CT::Mask bigint_sub_abs(word z[], const word x[], const word y[], size_t N, word ws[]) { // Subtract in both direction then conditional copy out the result word* ws0 = ws; word* ws1 = ws + N; word borrow0 = 0; word borrow1 = 0; const size_t blocks = N - (N % 8); for(size_t i = 0; i != blocks; i += 8) { borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0); borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1); } for(size_t i = blocks; i != N; ++i) { ws0[i] = word_sub(x[i], y[i], &borrow0); ws1[i] = word_sub(y[i], x[i], &borrow1); } return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N); } /* * Shift Operations */ inline void bigint_shl1(word x[], size_t x_size, size_t x_words, size_t word_shift, size_t bit_shift) { copy_mem(x + word_shift, x, x_words); clear_mem(x, word_shift); const auto carry_mask = CT::Mask::expand(bit_shift); const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); word carry = 0; for(size_t i = word_shift; i != x_size; ++i) { const word w = x[i]; x[i] = (w << bit_shift) | carry; carry = carry_mask.if_set_return(w >> carry_shift); } } inline void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) { const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0; if(top > 0) copy_mem(x, x + word_shift, top); clear_mem(x + top, std::min(word_shift, x_size)); const auto carry_mask = CT::Mask::expand(bit_shift); const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); word carry = 0; for(size_t i = 0; i != top; ++i) { const word w = x[top - i - 1]; x[top-i-1] = (w >> bit_shift) | carry; carry = carry_mask.if_set_return(w << carry_shift); } } inline void bigint_shl2(word y[], const word x[], size_t x_size, size_t word_shift, size_t bit_shift) { copy_mem(y + word_shift, x, x_size); const auto carry_mask = CT::Mask::expand(bit_shift); const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); word carry = 0; for(size_t i = word_shift; i != x_size + word_shift + 1; ++i) { const word w = y[i]; y[i] = (w << bit_shift) | carry; carry = carry_mask.if_set_return(w >> carry_shift); } } inline void bigint_shr2(word y[], const word x[], size_t x_size, size_t word_shift, size_t bit_shift) { const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift); if(new_size > 0) copy_mem(y, x + word_shift, new_size); const auto carry_mask = CT::Mask::expand(bit_shift); const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); word carry = 0; for(size_t i = new_size; i > 0; --i) { word w = y[i-1]; y[i-1] = (w >> bit_shift) | carry; carry = carry_mask.if_set_return(w << carry_shift); } } /* * Linear Multiply - returns the carry */ inline word BOTAN_WARN_UNUSED_RESULT bigint_linmul2(word x[], size_t x_size, word y) { const size_t blocks = x_size - (x_size % 8); word carry = 0; for(size_t i = 0; i != blocks; i += 8) carry = word8_linmul2(x + i, y, carry); for(size_t i = blocks; i != x_size; ++i) x[i] = word_madd2(x[i], y, &carry); return carry; } inline void bigint_linmul3(word z[], const word x[], size_t x_size, word y) { const size_t blocks = x_size - (x_size % 8); word carry = 0; for(size_t i = 0; i != blocks; i += 8) carry = word8_linmul3(z + i, x + i, y, carry); for(size_t i = blocks; i != x_size; ++i) z[i] = word_madd2(x[i], y, &carry); z[x_size] = carry; } /** * Compare x and y * Return -1 if x < y * Return 0 if x == y * Return 1 if x > y */ inline int32_t bigint_cmp(const word x[], size_t x_size, const word y[], size_t y_size) { static_assert(sizeof(word) >= sizeof(uint32_t), "Size assumption"); const word LT = static_cast(-1); const word EQ = 0; const word GT = 1; const size_t common_elems = std::min(x_size, y_size); word result = EQ; // until found otherwise for(size_t i = 0; i != common_elems; i++) { const auto is_eq = CT::Mask::is_equal(x[i], y[i]); const auto is_lt = CT::Mask::is_lt(x[i], y[i]); result = is_eq.select(result, is_lt.select(LT, GT)); } if(x_size < y_size) { word mask = 0; for(size_t i = x_size; i != y_size; i++) mask |= y[i]; // If any bits were set in high part of y, then x < y result = CT::Mask::is_zero(mask).select(result, LT); } else if(y_size < x_size) { word mask = 0; for(size_t i = y_size; i != x_size; i++) mask |= x[i]; // If any bits were set in high part of x, then x > y result = CT::Mask::is_zero(mask).select(result, GT); } CT::unpoison(result); BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ); return static_cast(result); } /** * Compare x and y * Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise * If lt_or_equal is true, returns ~0 also for x == y */ inline CT::Mask bigint_ct_is_lt(const word x[], size_t x_size, const word y[], size_t y_size, bool lt_or_equal = false) { const size_t common_elems = std::min(x_size, y_size); auto is_lt = CT::Mask::expand(lt_or_equal); for(size_t i = 0; i != common_elems; i++) { const auto eq = CT::Mask::is_equal(x[i], y[i]); const auto lt = CT::Mask::is_lt(x[i], y[i]); is_lt = eq.select_mask(is_lt, lt); } if(x_size < y_size) { word mask = 0; for(size_t i = x_size; i != y_size; i++) mask |= y[i]; // If any bits were set in high part of y, then is_lt should be forced true is_lt |= CT::Mask::expand(mask); } else if(y_size < x_size) { word mask = 0; for(size_t i = y_size; i != x_size; i++) mask |= x[i]; // If any bits were set in high part of x, then is_lt should be false is_lt &= CT::Mask::is_zero(mask); } return is_lt; } inline CT::Mask bigint_ct_is_eq(const word x[], size_t x_size, const word y[], size_t y_size) { const size_t common_elems = std::min(x_size, y_size); word diff = 0; for(size_t i = 0; i != common_elems; i++) { diff |= (x[i] ^ y[i]); } // If any bits were set in high part of x/y, then they are not equal if(x_size < y_size) { for(size_t i = x_size; i != y_size; i++) diff |= y[i]; } else if(y_size < x_size) { for(size_t i = y_size; i != x_size; i++) diff |= x[i]; } return CT::Mask::is_zero(diff); } /** * Set z to abs(x-y), ie if x >= y, then compute z = x - y * Otherwise compute z = y - x * No borrow is possible since the result is always >= 0 * * Return the relative size of x vs y (-1, 0, 1) * * @param z output array of max(x_size,y_size) words * @param x input param * @param x_size length of x * @param y input param * @param y_size length of y */ inline int32_t bigint_sub_abs(word z[], const word x[], size_t x_size, const word y[], size_t y_size) { const int32_t relative_size = bigint_cmp(x, x_size, y, y_size); // Swap if relative_size == -1 const bool need_swap = relative_size < 0; CT::conditional_swap_ptr(need_swap, x, y); CT::conditional_swap(need_swap, x_size, y_size); /* * We know at this point that x >= y so if y_size is larger than * x_size, we are guaranteed they are just leading zeros which can * be ignored */ y_size = std::min(x_size, y_size); bigint_sub3(z, x, x_size, y, y_size); return relative_size; } /** * Set t to t-s modulo mod * * @param t first integer * @param s second integer * @param mod the modulus * @param mod_sw size of t, s, and mod * @param ws workspace of size mod_sw */ inline void bigint_mod_sub(word t[], const word s[], const word mod[], size_t mod_sw, word ws[]) { // is t < s or not? const auto is_lt = bigint_ct_is_lt(t, mod_sw, s, mod_sw); // ws = p - s const word borrow = bigint_sub3(ws, mod, mod_sw, s, mod_sw); // Compute either (t - s) or (t + (p - s)) depending on mask const word carry = bigint_cnd_addsub(is_lt, t, ws, s, mod_sw); BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); BOTAN_UNUSED(carry, borrow); } template inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[]) { // is t < s or not? const auto is_lt = bigint_ct_is_lt(t, N, s, N); // ws = p - s const word borrow = bigint_sub3(ws, mod, N, s, N); // Compute either (t - s) or (t + (p - s)) depending on mask const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N); BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); BOTAN_UNUSED(carry, borrow); } /** * Compute ((n1<(n1) << BOTAN_MP_WORD_BITS) | n0) / d; #else word high = n1 % d; word quotient = 0; for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i) { const word high_top_bit = high >> (BOTAN_MP_WORD_BITS-1); high <<= 1; high |= (n0 >> (BOTAN_MP_WORD_BITS-1-i)) & 1; quotient <<= 1; if(high_top_bit || high >= d) { high -= d; quotient |= 1; } } return quotient; #endif } /** * Compute ((n1<(n1) << BOTAN_MP_WORD_BITS) | n0) % d; #else word z = bigint_divop(n1, n0, d); word dummy = 0; z = word_madd2(z, d, &dummy); return (n0-z); #endif } /* * Comba Multiplication / Squaring */ void bigint_comba_mul4(word z[8], const word x[4], const word y[4]); void bigint_comba_mul6(word z[12], const word x[6], const word y[6]); void bigint_comba_mul8(word z[16], const word x[8], const word y[8]); void bigint_comba_mul9(word z[18], const word x[9], const word y[9]); void bigint_comba_mul16(word z[32], const word x[16], const word y[16]); void bigint_comba_mul24(word z[48], const word x[24], const word y[24]); void bigint_comba_sqr4(word out[8], const word in[4]); void bigint_comba_sqr6(word out[12], const word in[6]); void bigint_comba_sqr8(word out[16], const word in[8]); void bigint_comba_sqr9(word out[18], const word in[9]); void bigint_comba_sqr16(word out[32], const word in[16]); void bigint_comba_sqr24(word out[48], const word in[24]); /** * Montgomery Reduction * @param z integer to reduce, of size exactly 2*(p_size+1). Output is in the first p_size+1 words, higher words are set to zero. * @param p modulus * @param p_size size of p * @param p_dash Montgomery value * @param workspace array of at least 2*(p_size+1) words * @param ws_size size of workspace in words */ void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word workspace[], size_t ws_size); /* * High Level Multiplication/Squaring Interfaces */ void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size); void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size); } namespace Botan { /* * Each of these functions makes the following assumptions: * * z_size >= 2*(p_size + 1) * ws_size >= z_size */ void bigint_monty_redc_4(word z[], const word p[], word p_dash, word ws[]); void bigint_monty_redc_6(word z[], const word p[], word p_dash, word ws[]); void bigint_monty_redc_8(word z[], const word p[], word p_dash, word ws[]); void bigint_monty_redc_16(word z[], const word p[], word p_dash, word ws[]); void bigint_monty_redc_24(word z[], const word p[], word p_dash, word ws[]); void bigint_monty_redc_32(word z[], const word p[], word p_dash, word ws[]); } namespace Botan { namespace OS { /* * This header is internal (not installed) and these functions are not * intended to be called by applications. However they are given public * visibility (using BOTAN_TEST_API macro) for the tests. This also probably * allows them to be overridden by the application on ELF systems, but * this hasn't been tested. */ /** * @return process ID assigned by the operating system. * On Unix and Windows systems, this always returns a result * On IncludeOS it returns 0 since there is no process ID to speak of * in a unikernel. */ uint32_t BOTAN_TEST_API get_process_id(); /** * Test if we are currently running with elevated permissions * eg setuid, setgid, or with POSIX caps set. */ bool running_in_privileged_state(); /** * @return CPU processor clock, if available * * On Windows, calls QueryPerformanceCounter. * * Under GCC or Clang on supported platforms the hardware cycle counter is queried. * Currently supported processors are x86, PPC, Alpha, SPARC, IA-64, S/390x, and HP-PA. * If no CPU cycle counter is available on this system, returns zero. */ uint64_t BOTAN_TEST_API get_cpu_cycle_counter(); size_t BOTAN_TEST_API get_cpu_total(); size_t BOTAN_TEST_API get_cpu_available(); /** * Return the ELF auxiliary vector cooresponding to the given ID. * This only makes sense on Unix-like systems and is currently * only supported on Linux, Android, and FreeBSD. * * Returns zero if not supported on the current system or if * the id provided is not known. */ unsigned long get_auxval(unsigned long id); /* * @return best resolution timestamp available * * The epoch and update rate of this clock is arbitrary and depending * on the hardware it may not tick at a constant rate. * * Uses hardware cycle counter, if available. * On POSIX platforms clock_gettime is used with a monotonic timer * As a final fallback std::chrono::high_resolution_clock is used. */ uint64_t BOTAN_TEST_API get_high_resolution_clock(); /** * @return system clock (reflecting wall clock) with best resolution * available, normalized to nanoseconds resolution. */ uint64_t BOTAN_TEST_API get_system_timestamp_ns(); /** * @return maximum amount of memory (in bytes) Botan could/should * hyptothetically allocate for the memory poool. Reads environment * variable "BOTAN_MLOCK_POOL_SIZE", set to "0" to disable pool. */ size_t get_memory_locking_limit(); /** * Return the size of a memory page, if that can be derived on the * current system. Otherwise returns some default value (eg 4096) */ size_t system_page_size(); /** * Read the value of an environment variable, setting it to value_out if it * exists. Returns false and sets value_out to empty string if no such variable * is set. If the process seems to be running in a privileged state (such as * setuid) then always returns false and does not examine the environment. */ bool read_env_variable(std::string& value_out, const std::string& var_name); /** * Read the value of an environment variable and convert it to an * integer. If not set or conversion fails, returns the default value. * * If the process seems to be running in a privileged state (such as setuid) * then always returns nullptr, similiar to glibc's secure_getenv. */ size_t read_env_variable_sz(const std::string& var_name, size_t def_value = 0); /** * Request count pages of RAM which are locked into memory using mlock, * VirtualLock, or some similar OS specific API. Free it with free_locked_pages. * * Returns an empty list on failure. This function is allowed to return fewer * than count pages. * * The contents of the allocated pages are undefined. * * Each page is preceded by and followed by a page which is marked * as noaccess, such that accessing it will cause a crash. This turns * out of bound reads/writes into crash events. * * @param count requested number of locked pages */ std::vector allocate_locked_pages(size_t count); /** * Free memory allocated by allocate_locked_pages * @param pages a list of pages returned by allocate_locked_pages */ void free_locked_pages(const std::vector& pages); /** * Set the MMU to prohibit access to this page */ void page_prohibit_access(void* page); /** * Set the MMU to allow R/W access to this page */ void page_allow_access(void* page); /** * Run a probe instruction to test for support for a CPU instruction. * Runs in system-specific env that catches illegal instructions; this * function always fails if the OS doesn't provide this. * Returns value of probe_fn, if it could run. * If error occurs, returns negative number. * This allows probe_fn to indicate errors of its own, if it wants. * For example the instruction might not only be only available on some * CPUs, but also buggy on some subset of these - the probe function * can test to make sure the instruction works properly before * indicating that the instruction is available. * * @warning on Unix systems uses signal handling in a way that is not * thread safe. It should only be called in a single-threaded context * (ie, at static init time). * * If probe_fn throws an exception the result is undefined. * * Return codes: * -1 illegal instruction detected */ int BOTAN_TEST_API run_cpu_instruction_probe(std::function probe_fn); /** * Represents a terminal state */ class BOTAN_UNSTABLE_API Echo_Suppression { public: /** * Reenable echo on this terminal. Can be safely called * multiple times. May throw if an error occurs. */ virtual void reenable_echo() = 0; /** * Implicitly calls reenable_echo, but swallows/ignored all * errors which would leave the terminal in an invalid state. */ virtual ~Echo_Suppression() = default; }; /** * Suppress echo on the terminal * Returns null if this operation is not supported on the current system. */ std::unique_ptr BOTAN_UNSTABLE_API suppress_echo_on_terminal(); } } namespace Botan { /** * Container of output buffers for Pipe */ class Output_Buffers final { public: size_t read(uint8_t[], size_t, Pipe::message_id); size_t peek(uint8_t[], size_t, size_t, Pipe::message_id) const; size_t get_bytes_read(Pipe::message_id) const; size_t remaining(Pipe::message_id) const; void add(class SecureQueue*); void retire(); Pipe::message_id message_count() const; Output_Buffers(); private: class SecureQueue* get(Pipe::message_id) const; std::deque> m_buffers; Pipe::message_id m_offset; }; } namespace Botan { namespace PKCS11 { /** * Simple class to build and hold the data for a CK_MECHANISM struct * for RSA (encryption/decryption, signature/verification) * and EC (ECDSA signature/verification, ECDH key derivation). */ class MechanismWrapper final { public: /// @param mechanism_type the CK_MECHANISM_TYPE for the `mechanism` field of the CK_MECHANISM struct explicit MechanismWrapper(MechanismType mechanism_type); /** * Creates the CK_MECHANISM data for RSA encryption/decryption * @param padding supported paddings are Raw (X.509), EME-PKCS1-v1_5 (PKCS#1 v1.5) and OAEP (PKCS#1 OAEP) */ static MechanismWrapper create_rsa_crypt_mechanism(const std::string& padding); /** * Creates the CK_MECHANISM data for RSA signature/verification * @param padding supported paddings are Raw (X.509), EMSA3 (PKCS#1 v1.5), EMSA4 (PKCS#1 PSS), * EMSA2 (ANSI X9.31) and ISO9796 (ISO/IEC 9796) */ static MechanismWrapper create_rsa_sign_mechanism(const std::string& padding); /** * Creates the CK_MECHANISM data for ECDSA signature/verification * @param hash the hash algorithm used to hash the data to sign. * supported hash functions are Raw and SHA-160 to SHA-512 */ static MechanismWrapper create_ecdsa_mechanism(const std::string& hash); /** * Creates the CK_MECHANISM data for ECDH key derivation (CKM_ECDH1_DERIVE or CKM_ECDH1_COFACTOR_DERIVE) * @param params specifies the key derivation function to use. * Supported KDFs are Raw and SHA-160 to SHA-512. * Params can also include the string "Cofactor" if the cofactor * key derivation mechanism should be used, for example "SHA-512,Cofactor" */ static MechanismWrapper create_ecdh_mechanism(const std::string& params); /** * Sets the salt for the ECDH mechanism parameters. * @param salt the salt * @param salt_len size of the salt in bytes */ inline void set_ecdh_salt(const uint8_t salt[], size_t salt_len) { m_parameters->ecdh_params.pSharedData = const_cast(salt); m_parameters->ecdh_params.ulSharedDataLen = static_cast(salt_len); } /** * Sets the public key of the other party for the ECDH mechanism parameters. * @param other_key key of the other party * @param other_key_len size of the key of the other party in bytes */ inline void set_ecdh_other_key(const uint8_t other_key[], size_t other_key_len) { m_parameters->ecdh_params.pPublicData = const_cast(other_key); m_parameters->ecdh_params.ulPublicDataLen = static_cast(other_key_len); } /// @return a pointer to the CK_MECHANISM struct that can be passed to the cryptoki functions inline Mechanism* data() const { return const_cast(&m_mechanism); } /// @return the size of the padding in bytes (for encryption/decryption) inline size_t padding_size() const { return m_padding_size; } /// Holds the mechanism parameters for OAEP, PSS and ECDH union MechanismParameters { MechanismParameters() { clear_mem(this, 1); } RsaPkcsOaepParams oaep_params; RsaPkcsPssParams pss_params; Ecdh1DeriveParams ecdh_params; }; private: Mechanism m_mechanism; std::shared_ptr m_parameters; size_t m_padding_size = 0; }; } } namespace Botan { /** * Returns the allowed padding schemes when using the given * algorithm (key type) for creating digital signatures. * * @param algo the algorithm for which to look up supported padding schemes * @return a vector of supported padding schemes */ BOTAN_TEST_API const std::vector get_sig_paddings(const std::string algo); /** * Returns true iff the given padding scheme is valid for the given * signature algorithm (key type). * * @param algo the signature algorithm to be used * @param padding the padding scheme to be used */ bool sig_algo_and_pad_ok(const std::string algo, const std::string padding); } namespace Botan { namespace PK_Ops { class Encryption_with_EME : public Encryption { public: size_t max_input_bits() const override; secure_vector encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; ~Encryption_with_EME() = default; protected: explicit Encryption_with_EME(const std::string& eme); private: virtual size_t max_raw_input_bits() const = 0; virtual secure_vector raw_encrypt(const uint8_t msg[], size_t len, RandomNumberGenerator& rng) = 0; std::unique_ptr m_eme; }; class Decryption_with_EME : public Decryption { public: secure_vector decrypt(uint8_t& valid_mask, const uint8_t msg[], size_t msg_len) override; ~Decryption_with_EME() = default; protected: explicit Decryption_with_EME(const std::string& eme); private: virtual secure_vector raw_decrypt(const uint8_t msg[], size_t len) = 0; std::unique_ptr m_eme; }; class Verification_with_EMSA : public Verification { public: ~Verification_with_EMSA() = default; void update(const uint8_t msg[], size_t msg_len) override; bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; bool do_check(const secure_vector& msg, const uint8_t sig[], size_t sig_len); std::string hash_for_signature() { return m_hash; } protected: explicit Verification_with_EMSA(const std::string& emsa); /** * Get the maximum message size in bits supported by this public key. * @return maximum message in bits */ virtual size_t max_input_bits() const = 0; /** * @return boolean specifying if this signature scheme uses * a message prefix returned by message_prefix() */ virtual bool has_prefix() { return false; } /** * @return the message prefix if this signature scheme uses * a message prefix, signaled via has_prefix() */ virtual secure_vector message_prefix() const { throw Invalid_State("No prefix"); } /** * @return boolean specifying if this key type supports message * recovery and thus if you need to call verify() or verify_mr() */ virtual bool with_recovery() const = 0; /* * Perform a signature check operation * @param msg the message * @param msg_len the length of msg in bytes * @param sig the signature * @param sig_len the length of sig in bytes * @returns if signature is a valid one for message */ virtual bool verify(const uint8_t[], size_t, const uint8_t[], size_t) { throw Invalid_State("Message recovery required"); } /* * Perform a signature operation (with message recovery) * Only call this if with_recovery() returns true * @param msg the message * @param msg_len the length of msg in bytes * @returns recovered message */ virtual secure_vector verify_mr(const uint8_t[], size_t) { throw Invalid_State("Message recovery not supported"); } std::unique_ptr clone_emsa() const { return std::unique_ptr(m_emsa->clone()); } private: std::unique_ptr m_emsa; const std::string m_hash; bool m_prefix_used; }; class Signature_with_EMSA : public Signature { public: void update(const uint8_t msg[], size_t msg_len) override; secure_vector sign(RandomNumberGenerator& rng) override; protected: explicit Signature_with_EMSA(const std::string& emsa); ~Signature_with_EMSA() = default; std::string hash_for_signature() { return m_hash; } /** * @return boolean specifying if this signature scheme uses * a message prefix returned by message_prefix() */ virtual bool has_prefix() { return false; } /** * @return the message prefix if this signature scheme uses * a message prefix, signaled via has_prefix() */ virtual secure_vector message_prefix() const { throw Invalid_State("No prefix"); } std::unique_ptr clone_emsa() const { return std::unique_ptr(m_emsa->clone()); } private: /** * Get the maximum message size in bits supported by this public key. * @return maximum message in bits */ virtual size_t max_input_bits() const = 0; bool self_test_signature(const std::vector& msg, const std::vector& sig) const; virtual secure_vector raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) = 0; std::unique_ptr m_emsa; const std::string m_hash; bool m_prefix_used; }; class Key_Agreement_with_KDF : public Key_Agreement { public: secure_vector agree(size_t key_len, const uint8_t other_key[], size_t other_key_len, const uint8_t salt[], size_t salt_len) override; protected: explicit Key_Agreement_with_KDF(const std::string& kdf); ~Key_Agreement_with_KDF() = default; private: virtual secure_vector raw_agree(const uint8_t w[], size_t w_len) = 0; std::unique_ptr m_kdf; }; class KEM_Encryption_with_KDF : public KEM_Encryption { public: void kem_encrypt(secure_vector& out_encapsulated_key, secure_vector& out_shared_key, size_t desired_shared_key_len, Botan::RandomNumberGenerator& rng, const uint8_t salt[], size_t salt_len) override; protected: virtual void raw_kem_encrypt(secure_vector& out_encapsulated_key, secure_vector& raw_shared_key, Botan::RandomNumberGenerator& rng) = 0; explicit KEM_Encryption_with_KDF(const std::string& kdf); ~KEM_Encryption_with_KDF() = default; private: std::unique_ptr m_kdf; }; class KEM_Decryption_with_KDF : public KEM_Decryption { public: secure_vector kem_decrypt(const uint8_t encap_key[], size_t len, size_t desired_shared_key_len, const uint8_t salt[], size_t salt_len) override; protected: virtual secure_vector raw_kem_decrypt(const uint8_t encap_key[], size_t len) = 0; explicit KEM_Decryption_with_KDF(const std::string& kdf); ~KEM_Decryption_with_KDF() = default; private: std::unique_ptr m_kdf; }; } } namespace Botan { class Modular_Reducer; class PointGFp_Base_Point_Precompute final { public: PointGFp_Base_Point_Precompute(const PointGFp& base_point, const Modular_Reducer& mod_order); PointGFp mul(const BigInt& k, RandomNumberGenerator& rng, const BigInt& group_order, std::vector& ws) const; private: const PointGFp& m_base_point; const Modular_Reducer& m_mod_order; enum { WINDOW_BITS = 3 }; enum { WINDOW_SIZE = (1 << WINDOW_BITS) - 1 }; const size_t m_p_words; /* * This is a table of T_size * 3*p_word words */ std::vector m_W; }; class PointGFp_Var_Point_Precompute final { public: PointGFp_Var_Point_Precompute(const PointGFp& point, RandomNumberGenerator& rng, std::vector& ws); PointGFp mul(const BigInt& k, RandomNumberGenerator& rng, const BigInt& group_order, std::vector& ws) const; private: const CurveGFp m_curve; const size_t m_p_words; const size_t m_window_bits; /* * Table of 2^window_bits * 3*2*p_word words * Kept in locked vector since the base point might be sensitive * (normally isn't in most protocols but hard to say anything * categorically.) */ secure_vector m_T; }; class PointGFp_Multi_Point_Precompute final { public: PointGFp_Multi_Point_Precompute(const PointGFp& g1, const PointGFp& g2); /* * Return (g1*k1 + g2*k2) * Not constant time, intended to use with public inputs */ PointGFp multi_exp(const BigInt& k1, const BigInt& k2) const; private: std::vector m_M; bool m_no_infinity; }; } namespace Botan { /** * Polynomial doubling in GF(2^n) */ void BOTAN_TEST_API poly_double_n(uint8_t out[], const uint8_t in[], size_t n); /** * Returns true iff poly_double_n is implemented for this size. */ inline bool poly_double_supported_size(size_t n) { return (n == 8 || n == 16 || n == 24 || n == 32 || n == 64 || n == 128); } inline void poly_double_n(uint8_t buf[], size_t n) { return poly_double_n(buf, buf, n); } /* * Little endian convention - used for XTS */ void BOTAN_TEST_API poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n); } namespace Botan { template inline void prefetch_readonly(const T* addr, size_t length) { #if defined(__GNUG__) const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); for(size_t i = 0; i <= length; i += Ts_per_cache_line) __builtin_prefetch(addr + i, 0); #endif } template inline void prefetch_readwrite(const T* addr, size_t length) { #if defined(__GNUG__) const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); for(size_t i = 0; i <= length; i += Ts_per_cache_line) __builtin_prefetch(addr + i, 1); #endif } } namespace Botan { class BigInt; class Modular_Reducer; class Montgomery_Params; class RandomNumberGenerator; /** * Perform Lucas primality test * @see FIPS 186-4 C.3.3 * * @warning it is possible to construct composite integers which pass * this test alone. * * @param n the positive integer to test * @param mod_n a pre-created Modular_Reducer for n * @return true if n seems probably prime, false if n is composite */ bool BOTAN_TEST_API is_lucas_probable_prime(const BigInt& n, const Modular_Reducer& mod_n); /** * Perform Bailie-PSW primality test * * This is a combination of Miller-Rabin with base 2 and a Lucas test. No known * composite integer passes both tests, though it is conjectured that infinitely * many composite counterexamples exist. * * @param n the positive integer to test * @param mod_n a pre-created Modular_Reducer for n * @return true if n seems probably prime, false if n is composite */ bool BOTAN_TEST_API is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n); /** * Perform Bailie-PSW primality test * * This is a combination of Miller-Rabin with base 2 and a Lucas test. No known * composite integer passes both tests, though it is conjectured that infinitely * many composite counterexamples exist. * * @param n the positive integer to test * @return true if n seems probably prime, false if n is composite */ bool is_bailie_psw_probable_prime(const BigInt& n); /** * Return required number of Miller-Rabin tests in order to * reach the specified probability of error. * * @param n_bits the bit-length of the integer being tested * @param prob chance of false positive is bounded by 1/2**prob * @param random is set if (and only if) the integer was randomly generated by us * and thus cannot have been maliciously constructed. */ size_t miller_rabin_test_iterations(size_t n_bits, size_t prob, bool random); /** * Perform a single Miller-Rabin test with specified base * * @param n the positive integer to test * @param mod_n a pre-created Modular_Reducer for n * @param monty_n Montgomery parameters for n * @param a the base to check * @return result of primality test */ bool passes_miller_rabin_test(const BigInt& n, const Modular_Reducer& mod_n, const std::shared_ptr& monty_n, const BigInt& a); /** * Perform t iterations of a Miller-Rabin primality test with random bases * * @param n the positive integer to test * @param mod_n a pre-created Modular_Reducer for n * @param rng a random number generator * @param t number of tests to perform * * @return result of primality test */ bool BOTAN_TEST_API is_miller_rabin_probable_prime(const BigInt& n, const Modular_Reducer& mod_n, RandomNumberGenerator& rng, size_t t); } namespace Botan { /** * Entropy source using the rdseed instruction first introduced on * Intel's Broadwell architecture. */ class Intel_Rdseed final : public Entropy_Source { public: std::string name() const override { return "rdseed"; } size_t poll(RandomNumberGenerator& rng) override; }; } namespace Botan { /** * Round up * @param n a non-negative integer * @param align_to the alignment boundary * @return n rounded up to a multiple of align_to */ inline size_t round_up(size_t n, size_t align_to) { BOTAN_ARG_CHECK(align_to != 0, "align_to must not be 0"); if(n % align_to) n += align_to - (n % align_to); return n; } /** * Round down * @param n an integer * @param align_to the alignment boundary * @return n rounded down to a multiple of align_to */ template inline constexpr T round_down(T n, T align_to) { return (align_to == 0) ? n : (n - (n % align_to)); } /** * Clamp */ inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound) { if(n < lower_bound) return lower_bound; if(n > upper_bound) return upper_bound; return n; } } namespace Botan { /** * A read-write lock. Writers are favored. */ class BOTAN_TEST_API RWLock final { public: RWLock(); void lock(); void unlock(); void lock_shared(); void unlock_shared(); private: std::mutex m_mutex; std::condition_variable m_gate1; std::condition_variable m_gate2; uint32_t m_state; // 2**31 concurrent readers should be enough for anyone static const uint32_t is_writing = static_cast(1) << 31; static const uint32_t readers_mask = ~is_writing; }; } namespace Botan { class BOTAN_PUBLIC_API(2,0) Integer_Overflow_Detected final : public Exception { public: Integer_Overflow_Detected(const std::string& file, int line) : Exception("Integer overflow detected at " + file + ":" + std::to_string(line)) {} ErrorType error_type() const noexcept override { return ErrorType::InternalError; } }; inline size_t checked_add(size_t x, size_t y, const char* file, int line) { // TODO: use __builtin_x_overflow on GCC and Clang size_t z = x + y; if(z < x) { throw Integer_Overflow_Detected(file, line); } return z; } #define BOTAN_CHECKED_ADD(x,y) checked_add(x,y,__FILE__,__LINE__) } namespace Botan { class Semaphore final { public: explicit Semaphore(int value = 0) : m_value(value), m_wakeups(0) {} void acquire(); void release(size_t n = 1); private: int m_value; int m_wakeups; std::mutex m_mutex; std::condition_variable m_cond; }; } template BOTAN_FORCE_INLINE void SBoxE0(T& a, T& b, T& c, T& d) { d ^= a; T t0 = b; b &= d; t0 ^= c; b ^= a; a |= d; a ^= t0; t0 ^= d; d ^= c; c |= b; c ^= t0; t0 = ~t0; t0 |= b; b ^= d; b ^= t0; d |= a; b ^= d; t0 ^= d; d = a; a = b; b = t0; } template BOTAN_FORCE_INLINE void SBoxE1(T& a, T& b, T& c, T& d) { a = ~a; c = ~c; T t0 = a; a &= b; c ^= a; a |= d; d ^= c; b ^= a; a ^= t0; t0 |= b; b ^= d; c |= a; c &= t0; a ^= b; b &= c; b ^= a; a &= c; t0 ^= a; a = c; c = d; d = b; b = t0; } template BOTAN_FORCE_INLINE void SBoxE2(T& a, T& b, T& c, T& d) { T t0 = a; a &= c; a ^= d; c ^= b; c ^= a; d |= t0; d ^= b; t0 ^= c; b = d; d |= t0; d ^= a; a &= b; t0 ^= a; b ^= d; b ^= t0; a = c; c = b; b = d; d = ~t0; } template BOTAN_FORCE_INLINE void SBoxE3(T& a, T& b, T& c, T& d) { T t0 = a; a |= d; d ^= b; b &= t0; t0 ^= c; c ^= d; d &= a; t0 |= b; d ^= t0; a ^= b; t0 &= a; b ^= d; t0 ^= c; b |= a; b ^= c; a ^= d; c = b; b |= d; a ^= b; b = c; c = d; d = t0; } template BOTAN_FORCE_INLINE void SBoxE4(T& a, T& b, T& c, T& d) { b ^= d; d = ~d; c ^= d; d ^= a; T t0 = b; b &= d; b ^= c; t0 ^= d; a ^= t0; c &= t0; c ^= a; a &= b; d ^= a; t0 |= b; t0 ^= a; a |= d; a ^= c; c &= d; a = ~a; t0 ^= c; c = a; a = b; b = t0; } template BOTAN_FORCE_INLINE void SBoxE5(T& a, T& b, T& c, T& d) { a ^= b; b ^= d; d = ~d; T t0 = b; b &= a; c ^= d; b ^= c; c |= t0; t0 ^= d; d &= b; d ^= a; t0 ^= b; t0 ^= c; c ^= a; a &= d; c = ~c; a ^= t0; t0 |= d; t0 ^= c; c = a; a = b; b = d; d = t0; } template BOTAN_FORCE_INLINE void SBoxE6(T& a, T& b, T& c, T& d) { c = ~c; T t0 = d; d &= a; a ^= t0; d ^= c; c |= t0; b ^= d; c ^= a; a |= b; c ^= b; t0 ^= a; a |= d; a ^= c; t0 ^= d; t0 ^= a; d = ~d; c &= t0; d ^= c; c = t0; } template BOTAN_FORCE_INLINE void SBoxE7(T& a, T& b, T& c, T& d) { T t0 = b; b |= c; b ^= d; t0 ^= c; c ^= b; d |= t0; d &= a; t0 ^= c; d ^= b; b |= t0; b ^= a; a |= t0; a ^= c; b ^= t0; c ^= b; b &= a; b ^= t0; c = ~c; c |= a; t0 ^= c; c = b; b = d; d = a; a = t0; } template BOTAN_FORCE_INLINE void SBoxD0(T& a, T& b, T& c, T& d) { c = ~c; T t0 = b; b |= a; t0 = ~t0; b ^= c; c |= t0; b ^= d; a ^= t0; c ^= a; a &= d; t0 ^= a; a |= b; a ^= c; d ^= t0; c ^= b; d ^= a; d ^= b; c &= d; t0 ^= c; c = b; b = t0; } template BOTAN_FORCE_INLINE void SBoxD1(T& a, T& b, T& c, T& d) { T t0 = b; b ^= d; d &= b; t0 ^= c; d ^= a; a |= b; c ^= d; a ^= t0; a |= c; b ^= d; a ^= b; b |= d; b ^= a; t0 = ~t0; t0 ^= b; b |= a; b ^= a; b |= t0; d ^= b; b = a; a = t0; t0 = c; c = d; d = t0; } template BOTAN_FORCE_INLINE void SBoxD2(T& a, T& b, T& c, T& d) { c ^= d; d ^= a; T t0 = d; d &= c; d ^= b; b |= c; b ^= t0; t0 &= d; c ^= d; t0 &= a; t0 ^= c; c &= b; c |= a; d = ~d; c ^= d; a ^= d; a &= b; d ^= t0; d ^= a; a = b; b = t0; } template BOTAN_FORCE_INLINE void SBoxD3(T& a, T& b, T& c, T& d) { T t0 = c; c ^= b; a ^= c; t0 &= c; t0 ^= a; a &= b; b ^= d; d |= t0; c ^= d; a ^= d; b ^= t0; d &= c; d ^= b; b ^= a; b |= c; a ^= d; b ^= t0; a ^= b; t0 = a; a = c; c = d; d = t0; } template BOTAN_FORCE_INLINE void SBoxD4(T& a, T& b, T& c, T& d) { T t0 = c; c &= d; c ^= b; b |= d; b &= a; t0 ^= c; t0 ^= b; b &= c; a = ~a; d ^= t0; b ^= d; d &= a; d ^= c; a ^= b; c &= a; d ^= a; c ^= t0; c |= d; d ^= a; c ^= b; b = d; d = t0; } template BOTAN_FORCE_INLINE void SBoxD5(T& a, T& b, T& c, T& d) { b = ~b; T t0 = d; c ^= b; d |= a; d ^= c; c |= b; c &= a; t0 ^= d; c ^= t0; t0 |= a; t0 ^= b; b &= c; b ^= d; t0 ^= c; d &= t0; t0 ^= b; d ^= t0; t0 = ~t0; d ^= a; a = b; b = t0; t0 = d; d = c; c = t0; } template BOTAN_FORCE_INLINE void SBoxD6(T& a, T& b, T& c, T& d) { a ^= c; T t0 = c; c &= a; t0 ^= d; c = ~c; d ^= b; c ^= d; t0 |= a; a ^= c; d ^= t0; t0 ^= b; b &= d; b ^= a; a ^= d; a |= c; d ^= b; t0 ^= a; a = b; b = c; c = t0; } template BOTAN_FORCE_INLINE void SBoxD7(T& a, T& b, T& c, T& d) { T t0 = c; c ^= a; a &= d; t0 |= d; c = ~c; d ^= b; b |= a; a ^= c; c &= t0; d &= t0; b ^= c; c ^= a; a |= c; t0 ^= b; a ^= d; d ^= t0; t0 |= a; d ^= c; t0 ^= c; c = b; b = a; a = d; d = t0; } #if defined(BOTAN_TARGET_SUPPORTS_SSE2) #include #define BOTAN_SIMD_USE_SSE2 #elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) #include #undef vector #undef bool #define BOTAN_SIMD_USE_ALTIVEC #elif defined(BOTAN_TARGET_SUPPORTS_NEON) #include #define BOTAN_SIMD_USE_NEON #else #error "No SIMD instruction set enabled" #endif #if defined(BOTAN_SIMD_USE_SSE2) #define BOTAN_SIMD_ISA "sse2" #define BOTAN_VPERM_ISA "ssse3" #define BOTAN_CLMUL_ISA "pclmul" #elif defined(BOTAN_SIMD_USE_NEON) #if defined(BOTAN_TARGET_ARCH_IS_ARM64) #define BOTAN_SIMD_ISA "+simd" #define BOTAN_CLMUL_ISA "+crypto" #else #define BOTAN_SIMD_ISA "fpu=neon" #endif #define BOTAN_VPERM_ISA BOTAN_SIMD_ISA #elif defined(BOTAN_SIMD_USE_ALTIVEC) #define BOTAN_SIMD_ISA "altivec" #define BOTAN_VPERM_ISA "altivec" #define BOTAN_CLMUL_ISA "crypto" #endif namespace Botan { #if defined(BOTAN_SIMD_USE_SSE2) typedef __m128i native_simd_type; #elif defined(BOTAN_SIMD_USE_ALTIVEC) typedef __vector unsigned int native_simd_type; #elif defined(BOTAN_SIMD_USE_NEON) typedef uint32x4_t native_simd_type; #endif /** * 4x32 bit SIMD register * * This class is not a general purpose SIMD type, and only offers * instructions needed for evaluation of specific crypto primitives. * For example it does not currently have equality operators of any * kind. * * Implemented for SSE2, VMX (Altivec), and NEON. */ class SIMD_4x32 final { public: SIMD_4x32& operator=(const SIMD_4x32& other) = default; SIMD_4x32(const SIMD_4x32& other) = default; SIMD_4x32& operator=(SIMD_4x32&& other) = default; SIMD_4x32(SIMD_4x32&& other) = default; /** * Zero initialize SIMD register with 4 32-bit elements */ SIMD_4x32() // zero initialized { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_setzero_si128(); #elif defined(BOTAN_SIMD_USE_ALTIVEC) m_simd = vec_splat_u32(0); #elif defined(BOTAN_SIMD_USE_NEON) m_simd = vdupq_n_u32(0); #endif } /** * Load SIMD register with 4 32-bit elements */ explicit SIMD_4x32(const uint32_t B[4]) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_loadu_si128(reinterpret_cast(B)); #elif defined(BOTAN_SIMD_USE_ALTIVEC) __vector unsigned int val = { B[0], B[1], B[2], B[3]}; m_simd = val; #elif defined(BOTAN_SIMD_USE_NEON) m_simd = vld1q_u32(B); #endif } /** * Load SIMD register with 4 32-bit elements */ SIMD_4x32(uint32_t B0, uint32_t B1, uint32_t B2, uint32_t B3) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_set_epi32(B3, B2, B1, B0); #elif defined(BOTAN_SIMD_USE_ALTIVEC) __vector unsigned int val = {B0, B1, B2, B3}; m_simd = val; #elif defined(BOTAN_SIMD_USE_NEON) // Better way to do this? const uint32_t B[4] = { B0, B1, B2, B3 }; m_simd = vld1q_u32(B); #endif } /** * Load SIMD register with one 32-bit element repeated */ static SIMD_4x32 splat(uint32_t B) { #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_set1_epi32(B)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vdupq_n_u32(B)); #else return SIMD_4x32(B, B, B, B); #endif } /** * Load SIMD register with one 8-bit element repeated */ static SIMD_4x32 splat_u8(uint8_t B) { #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_set1_epi8(B)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vreinterpretq_u32_u8(vdupq_n_u8(B))); #else const uint32_t B4 = make_uint32(B, B, B, B); return SIMD_4x32(B4, B4, B4, B4); #endif } /** * Load a SIMD register with little-endian convention */ static SIMD_4x32 load_le(const void* in) { #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_loadu_si128(reinterpret_cast(in))); #elif defined(BOTAN_SIMD_USE_ALTIVEC) uint32_t R[4]; Botan::load_le(R, static_cast(in), 4); return SIMD_4x32(R); #elif defined(BOTAN_SIMD_USE_NEON) SIMD_4x32 l(vld1q_u32(static_cast(in))); return CPUID::is_big_endian() ? l.bswap() : l; #endif } /** * Load a SIMD register with big-endian convention */ static SIMD_4x32 load_be(const void* in) { #if defined(BOTAN_SIMD_USE_SSE2) return load_le(in).bswap(); #elif defined(BOTAN_SIMD_USE_ALTIVEC) uint32_t R[4]; Botan::load_be(R, static_cast(in), 4); return SIMD_4x32(R); #elif defined(BOTAN_SIMD_USE_NEON) SIMD_4x32 l(vld1q_u32(static_cast(in))); return CPUID::is_little_endian() ? l.bswap() : l; #endif } void store_le(uint32_t out[4]) const { this->store_le(reinterpret_cast(out)); } void store_le(uint64_t out[2]) const { this->store_le(reinterpret_cast(out)); } /** * Load a SIMD register with little-endian convention */ void store_le(uint8_t out[]) const { #if defined(BOTAN_SIMD_USE_SSE2) _mm_storeu_si128(reinterpret_cast<__m128i*>(out), raw()); #elif defined(BOTAN_SIMD_USE_ALTIVEC) union { __vector unsigned int V; uint32_t R[4]; } vec; vec.V = raw(); Botan::store_le(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); #elif defined(BOTAN_SIMD_USE_NEON) if(CPUID::is_little_endian()) { vst1q_u8(out, vreinterpretq_u8_u32(m_simd)); } else { vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd)); } #endif } /** * Load a SIMD register with big-endian convention */ void store_be(uint8_t out[]) const { #if defined(BOTAN_SIMD_USE_SSE2) bswap().store_le(out); #elif defined(BOTAN_SIMD_USE_ALTIVEC) union { __vector unsigned int V; uint32_t R[4]; } vec; vec.V = m_simd; Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); #elif defined(BOTAN_SIMD_USE_NEON) if(CPUID::is_little_endian()) { vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd)); } else { vst1q_u8(out, vreinterpretq_u8_u32(m_simd)); } #endif } /* * This is used for SHA-2/SHACAL2 * Return rotr(ROT1) ^ rotr(ROT2) ^ rotr(ROT3) */ template SIMD_4x32 rho() const { const SIMD_4x32 rot1 = this->rotr(); const SIMD_4x32 rot2 = this->rotr(); const SIMD_4x32 rot3 = this->rotr(); return (rot1 ^ rot2 ^ rot3); } /** * Left rotation by a compile time constant */ template SIMD_4x32 rotl() const { static_assert(ROT > 0 && ROT < 32, "Invalid rotation constant"); #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_or_si128(_mm_slli_epi32(m_simd, static_cast(ROT)), _mm_srli_epi32(m_simd, static_cast(32-ROT)))); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const unsigned int r = static_cast(ROT); __vector unsigned int rot = {r, r, r, r}; return SIMD_4x32(vec_rl(m_simd, rot)); #elif defined(BOTAN_SIMD_USE_NEON) #if defined(BOTAN_TARGET_ARCH_IS_ARM64) BOTAN_IF_CONSTEXPR(ROT == 8) { const uint8_t maskb[16] = { 3,0,1,2, 7,4,5,6, 11,8,9,10, 15,12,13,14 }; const uint8x16_t mask = vld1q_u8(maskb); return SIMD_4x32(vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(m_simd), mask))); } else BOTAN_IF_CONSTEXPR(ROT == 16) { return SIMD_4x32(vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(m_simd)))); } #endif return SIMD_4x32(vorrq_u32(vshlq_n_u32(m_simd, static_cast(ROT)), vshrq_n_u32(m_simd, static_cast(32-ROT)))); #endif } /** * Right rotation by a compile time constant */ template SIMD_4x32 rotr() const { return this->rotl<32-ROT>(); } /** * Add elements of a SIMD vector */ SIMD_4x32 operator+(const SIMD_4x32& other) const { SIMD_4x32 retval(*this); retval += other; return retval; } /** * Subtract elements of a SIMD vector */ SIMD_4x32 operator-(const SIMD_4x32& other) const { SIMD_4x32 retval(*this); retval -= other; return retval; } /** * XOR elements of a SIMD vector */ SIMD_4x32 operator^(const SIMD_4x32& other) const { SIMD_4x32 retval(*this); retval ^= other; return retval; } /** * Binary OR elements of a SIMD vector */ SIMD_4x32 operator|(const SIMD_4x32& other) const { SIMD_4x32 retval(*this); retval |= other; return retval; } /** * Binary AND elements of a SIMD vector */ SIMD_4x32 operator&(const SIMD_4x32& other) const { SIMD_4x32 retval(*this); retval &= other; return retval; } void operator+=(const SIMD_4x32& other) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_add_epi32(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_ALTIVEC) m_simd = vec_add(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_NEON) m_simd = vaddq_u32(m_simd, other.m_simd); #endif } void operator-=(const SIMD_4x32& other) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_sub_epi32(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_ALTIVEC) m_simd = vec_sub(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_NEON) m_simd = vsubq_u32(m_simd, other.m_simd); #endif } void operator^=(const SIMD_4x32& other) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_xor_si128(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_ALTIVEC) m_simd = vec_xor(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_NEON) m_simd = veorq_u32(m_simd, other.m_simd); #endif } void operator|=(const SIMD_4x32& other) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_or_si128(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_ALTIVEC) m_simd = vec_or(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_NEON) m_simd = vorrq_u32(m_simd, other.m_simd); #endif } void operator&=(const SIMD_4x32& other) { #if defined(BOTAN_SIMD_USE_SSE2) m_simd = _mm_and_si128(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_ALTIVEC) m_simd = vec_and(m_simd, other.m_simd); #elif defined(BOTAN_SIMD_USE_NEON) m_simd = vandq_u32(m_simd, other.m_simd); #endif } template SIMD_4x32 shl() const { static_assert(SHIFT > 0 && SHIFT <= 31, "Invalid shift count"); #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_slli_epi32(m_simd, SHIFT)); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const unsigned int s = static_cast(SHIFT); const __vector unsigned int shifts = {s, s, s, s}; return SIMD_4x32(vec_sl(m_simd, shifts)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vshlq_n_u32(m_simd, SHIFT)); #endif } template SIMD_4x32 shr() const { #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_srli_epi32(m_simd, SHIFT)); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const unsigned int s = static_cast(SHIFT); const __vector unsigned int shifts = {s, s, s, s}; return SIMD_4x32(vec_sr(m_simd, shifts)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vshrq_n_u32(m_simd, SHIFT)); #endif } SIMD_4x32 operator~() const { #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_xor_si128(m_simd, _mm_set1_epi32(0xFFFFFFFF))); #elif defined(BOTAN_SIMD_USE_ALTIVEC) return SIMD_4x32(vec_nor(m_simd, m_simd)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vmvnq_u32(m_simd)); #endif } // (~reg) & other SIMD_4x32 andc(const SIMD_4x32& other) const { #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_andnot_si128(m_simd, other.m_simd)); #elif defined(BOTAN_SIMD_USE_ALTIVEC) /* AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2 so swap the arguments */ return SIMD_4x32(vec_andc(other.m_simd, m_simd)); #elif defined(BOTAN_SIMD_USE_NEON) // NEON is also a & ~b return SIMD_4x32(vbicq_u32(other.m_simd, m_simd)); #endif } /** * Return copy *this with each word byte swapped */ SIMD_4x32 bswap() const { #if defined(BOTAN_SIMD_USE_SSE2) __m128i T = m_simd; T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); return SIMD_4x32(_mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8))); #elif defined(BOTAN_SIMD_USE_ALTIVEC) union { __vector unsigned int V; uint32_t R[4]; } vec; vec.V = m_simd; bswap_4(vec.R); return SIMD_4x32(vec.R[0], vec.R[1], vec.R[2], vec.R[3]); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(m_simd)))); #endif } template SIMD_4x32 shift_elems_left() const { static_assert(I <= 3, "Invalid shift count"); #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_slli_si128(raw(), 4*I)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vextq_u32(vdupq_n_u32(0), raw(), 4-I)); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const __vector unsigned int zero = vec_splat_u32(0); const __vector unsigned char shuf[3] = { { 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7 }, { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 1, 2, 3 }, }; return SIMD_4x32(vec_perm(raw(), zero, shuf[I-1])); #endif } template SIMD_4x32 shift_elems_right() const { static_assert(I <= 3, "Invalid shift count"); #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_srli_si128(raw(), 4*I)); #elif defined(BOTAN_SIMD_USE_NEON) return SIMD_4x32(vextq_u32(raw(), vdupq_n_u32(0), I)); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const __vector unsigned int zero = vec_splat_u32(0); const __vector unsigned char shuf[3] = { { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }, { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }, { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, }; return SIMD_4x32(vec_perm(raw(), zero, shuf[I-1])); #endif } /** * 4x4 Transposition on SIMD registers */ static void transpose(SIMD_4x32& B0, SIMD_4x32& B1, SIMD_4x32& B2, SIMD_4x32& B3) { #if defined(BOTAN_SIMD_USE_SSE2) const __m128i T0 = _mm_unpacklo_epi32(B0.m_simd, B1.m_simd); const __m128i T1 = _mm_unpacklo_epi32(B2.m_simd, B3.m_simd); const __m128i T2 = _mm_unpackhi_epi32(B0.m_simd, B1.m_simd); const __m128i T3 = _mm_unpackhi_epi32(B2.m_simd, B3.m_simd); B0.m_simd = _mm_unpacklo_epi64(T0, T1); B1.m_simd = _mm_unpackhi_epi64(T0, T1); B2.m_simd = _mm_unpacklo_epi64(T2, T3); B3.m_simd = _mm_unpackhi_epi64(T2, T3); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const __vector unsigned int T0 = vec_mergeh(B0.m_simd, B2.m_simd); const __vector unsigned int T1 = vec_mergeh(B1.m_simd, B3.m_simd); const __vector unsigned int T2 = vec_mergel(B0.m_simd, B2.m_simd); const __vector unsigned int T3 = vec_mergel(B1.m_simd, B3.m_simd); B0.m_simd = vec_mergeh(T0, T1); B1.m_simd = vec_mergel(T0, T1); B2.m_simd = vec_mergeh(T2, T3); B3.m_simd = vec_mergel(T2, T3); #elif defined(BOTAN_SIMD_USE_NEON) && defined(BOTAN_TARGET_ARCH_IS_ARM32) const uint32x4x2_t T0 = vzipq_u32(B0.m_simd, B2.m_simd); const uint32x4x2_t T1 = vzipq_u32(B1.m_simd, B3.m_simd); const uint32x4x2_t O0 = vzipq_u32(T0.val[0], T1.val[0]); const uint32x4x2_t O1 = vzipq_u32(T0.val[1], T1.val[1]); B0.m_simd = O0.val[0]; B1.m_simd = O0.val[1]; B2.m_simd = O1.val[0]; B3.m_simd = O1.val[1]; #elif defined(BOTAN_SIMD_USE_NEON) && defined(BOTAN_TARGET_ARCH_IS_ARM64) const uint32x4_t T0 = vzip1q_u32(B0.m_simd, B2.m_simd); const uint32x4_t T2 = vzip2q_u32(B0.m_simd, B2.m_simd); const uint32x4_t T1 = vzip1q_u32(B1.m_simd, B3.m_simd); const uint32x4_t T3 = vzip2q_u32(B1.m_simd, B3.m_simd); B0.m_simd = vzip1q_u32(T0, T1); B1.m_simd = vzip2q_u32(T0, T1); B2.m_simd = vzip1q_u32(T2, T3); B3.m_simd = vzip2q_u32(T2, T3); #endif } native_simd_type raw() const BOTAN_FUNC_ISA(BOTAN_SIMD_ISA) { return m_simd; } explicit SIMD_4x32(native_simd_type x) : m_simd(x) {} private: native_simd_type m_simd; }; } namespace Botan { namespace OS { /* * This header is internal (not installed) and these functions are not * intended to be called by applications. However they are given public * visibility (using BOTAN_TEST_API macro) for the tests. This also probably * allows them to be overridden by the application on ELF systems, but * this hasn't been tested. */ /** * A wrapper around a simple blocking TCP socket */ class BOTAN_TEST_API Socket { public: /** * The socket will be closed upon destruction */ virtual ~Socket() = default; /** * Write to the socket. Blocks until all bytes sent. * Throws on error. */ virtual void write(const uint8_t buf[], size_t len) = 0; /** * Reads up to len bytes, returns bytes written to buf. * Returns 0 on EOF. Throws on error. */ virtual size_t read(uint8_t buf[], size_t len) = 0; }; /** * Open up a socket. Will throw on error. Returns null if sockets are * not available on this platform. */ std::unique_ptr BOTAN_TEST_API open_socket(const std::string& hostname, const std::string& service, std::chrono::milliseconds timeout); } // OS } // Botan namespace Botan { namespace OS { /* * This header is internal (not installed) and these functions are not * intended to be called by applications. However they are given public * visibility (using BOTAN_TEST_API macro) for the tests. This also probably * allows them to be overridden by the application on ELF systems, but * this hasn't been tested. */ /** * A wrapper around a simple blocking UDP socket */ class BOTAN_TEST_API SocketUDP { public: /** * The socket will be closed upon destruction */ virtual ~SocketUDP() = default; /** * Write to the socket. Returns immediately. * Throws on error. */ virtual void write(const uint8_t buf[], size_t len) = 0; /** * Reads up to len bytes, returns bytes written to buf. * Returns 0 on EOF. Throws on error. */ virtual size_t read(uint8_t buf[], size_t len) = 0; }; /** * Open up a socket. Will throw on error. Returns null if sockets are * not available on this platform. */ std::unique_ptr BOTAN_TEST_API open_socket_udp(const std::string& hostname, const std::string& service, std::chrono::microseconds timeout); /** * Open up a socket. Will throw on error. Returns null if sockets are * not available on this platform. */ std::unique_ptr BOTAN_TEST_API open_socket_udp(const std::string& uri, std::chrono::microseconds timeout); } // OS } // Botan namespace Botan { inline std::vector to_byte_vector(const std::string& s) { return std::vector(s.cbegin(), s.cend()); } inline std::string to_string(const secure_vector &bytes) { return std::string(bytes.cbegin(), bytes.cend()); } /** * Return the keys of a map as a std::set */ template std::set map_keys_as_set(const std::map& kv) { std::set s; for(auto&& i : kv) { s.insert(i.first); } return s; } /* * Searching through a std::map * @param mapping the map to search * @param key is what to look for * @param null_result is the value to return if key is not in mapping * @return mapping[key] or null_result */ template inline V search_map(const std::map& mapping, const K& key, const V& null_result = V()) { auto i = mapping.find(key); if(i == mapping.end()) return null_result; return i->second; } template inline R search_map(const std::map& mapping, const K& key, const R& null_result, const R& found_result) { auto i = mapping.find(key); if(i == mapping.end()) return null_result; return found_result; } /* * Insert a key/value pair into a multimap */ template void multimap_insert(std::multimap& multimap, const K& key, const V& value) { multimap.insert(std::make_pair(key, value)); } /** * Existence check for values */ template bool value_exists(const std::vector& vec, const T& val) { for(size_t i = 0; i != vec.size(); ++i) if(vec[i] == val) return true; return false; } template void map_remove_if(Pred pred, T& assoc) { auto i = assoc.begin(); while(i != assoc.end()) { if(pred(i->first)) assoc.erase(i++); else i++; } } } namespace Botan { class BOTAN_TEST_API Thread_Pool { public: /** * Return an instance to a shared thread pool */ static Thread_Pool& global_instance(); /** * Initialize a thread pool with some number of threads * @param pool_size number of threads in the pool, if 0 * then some default value is chosen */ Thread_Pool(size_t pool_size = 0); ~Thread_Pool() { shutdown(); } void shutdown(); size_t worker_count() const { return m_workers.size(); } Thread_Pool(const Thread_Pool&) = delete; Thread_Pool& operator=(const Thread_Pool&) = delete; Thread_Pool(Thread_Pool&&) = delete; Thread_Pool& operator=(Thread_Pool&&) = delete; /* * Enqueue some work */ void queue_thunk(std::function); template auto run(F&& f, Args&&... args) -> std::future::type> { typedef typename std::result_of::type return_type; auto future_work = std::bind(std::forward(f), std::forward(args)...); auto task = std::make_shared>(future_work); auto future_result = task->get_future(); queue_thunk([task]() { (*task)(); }); return future_result; } private: void worker_thread(); // Only touched in constructor and destructor std::vector m_workers; std::mutex m_mutex; std::condition_variable m_more_tasks; std::deque> m_tasks; bool m_shutdown; }; } namespace Botan { class BOTAN_TEST_API Timer final { public: Timer(const std::string& name, const std::string& provider, const std::string& doing, uint64_t event_mult, size_t buf_size, double clock_cycle_ratio, uint64_t clock_speed) : m_name(name + ((provider.empty() || provider == "base") ? "" : " [" + provider + "]")) , m_doing(doing) , m_buf_size(buf_size) , m_event_mult(event_mult) , m_clock_cycle_ratio(clock_cycle_ratio) , m_clock_speed(clock_speed) {} Timer(const std::string& name) : Timer(name, "", "", 1, 0, 0.0, 0) {} Timer(const std::string& name, size_t buf_size) : Timer(name, "", "", buf_size, buf_size, 0.0, 0) {} Timer(const Timer& other) = default; Timer& operator=(const Timer& other) = default; void start(); void stop(); bool under(std::chrono::milliseconds msec) { return (milliseconds() < msec.count()); } class Timer_Scope final { public: explicit Timer_Scope(Timer& timer) : m_timer(timer) { m_timer.start(); } ~Timer_Scope() { try { m_timer.stop(); } catch(...) {} } private: Timer& m_timer; }; template auto run(F f) -> decltype(f()) { Timer_Scope timer(*this); return f(); } template void run_until_elapsed(std::chrono::milliseconds msec, F f) { while(this->under(msec)) { run(f); } } uint64_t value() const { return m_time_used; } double seconds() const { return milliseconds() / 1000.0; } double milliseconds() const { return value() / 1000000.0; } double ms_per_event() const { return milliseconds() / events(); } uint64_t cycles_consumed() const { if(m_clock_speed != 0) { return static_cast((m_clock_speed * value()) / 1000.0); } return m_cpu_cycles_used; } uint64_t events() const { return m_event_count * m_event_mult; } const std::string& get_name() const { return m_name; } const std::string& doing() const { return m_doing; } size_t buf_size() const { return m_buf_size; } double bytes_per_second() const { return seconds() > 0.0 ? events() / seconds() : 0.0; } double events_per_second() const { return seconds() > 0.0 ? events() / seconds() : 0.0; } double seconds_per_event() const { return events() > 0 ? seconds() / events() : 0.0; } void set_custom_msg(const std::string& s) { m_custom_msg = s; } bool operator<(const Timer& other) const; std::string to_string() const; private: std::string result_string_bps() const; std::string result_string_ops() const; // const data std::string m_name, m_doing; size_t m_buf_size; uint64_t m_event_mult; double m_clock_cycle_ratio; uint64_t m_clock_speed; // set at runtime std::string m_custom_msg; uint64_t m_time_used = 0, m_timer_start = 0; uint64_t m_event_count = 0; uint64_t m_max_time = 0, m_min_time = 0; uint64_t m_cpu_cycles_start = 0, m_cpu_cycles_used = 0; }; } namespace Botan { namespace TLS { /** * TLS CBC+HMAC AEAD base class (GenericBlockCipher in TLS spec) * This is the weird TLS-specific mode, not for general consumption. */ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Mode : public AEAD_Mode { public: size_t process(uint8_t buf[], size_t sz) override final; std::string name() const override final; void set_associated_data(const uint8_t ad[], size_t ad_len) override; size_t update_granularity() const override final; Key_Length_Specification key_spec() const override final; bool valid_nonce_length(size_t nl) const override final; size_t tag_size() const override final { return m_tag_size; } size_t default_nonce_length() const override final { return m_iv_size; } void clear() override final; void reset() override final; protected: TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir direction, std::unique_ptr cipher, std::unique_ptr mac, size_t cipher_keylen, size_t mac_keylen, Protocol_Version version, bool use_encrypt_then_mac); size_t cipher_keylen() const { return m_cipher_keylen; } size_t mac_keylen() const { return m_mac_keylen; } size_t iv_size() const { return m_iv_size; } size_t block_size() const { return m_block_size; } bool use_encrypt_then_mac() const { return m_use_encrypt_then_mac; } bool is_datagram_protocol() const { return m_is_datagram; } Cipher_Mode& cbc() const { return *m_cbc; } MessageAuthenticationCode& mac() const { BOTAN_ASSERT_NONNULL(m_mac); return *m_mac; } secure_vector& cbc_state() { return m_cbc_state; } std::vector& assoc_data() { return m_ad; } secure_vector& msg() { return m_msg; } std::vector assoc_data_with_len(uint16_t len); private: void start_msg(const uint8_t nonce[], size_t nonce_len) override final; void key_schedule(const uint8_t key[], size_t length) override final; const std::string m_cipher_name; const std::string m_mac_name; size_t m_cipher_keylen; size_t m_mac_keylen; size_t m_iv_size; size_t m_tag_size; size_t m_block_size; bool m_use_encrypt_then_mac; bool m_is_datagram; std::unique_ptr m_cbc; std::unique_ptr m_mac; secure_vector m_cbc_state; std::vector m_ad; secure_vector m_msg; }; /** * TLS_CBC_HMAC_AEAD Encryption */ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Encryption final : public TLS_CBC_HMAC_AEAD_Mode { public: /** */ TLS_CBC_HMAC_AEAD_Encryption( std::unique_ptr cipher, std::unique_ptr mac, const size_t cipher_keylen, const size_t mac_keylen, const Protocol_Version version, bool use_encrypt_then_mac) : TLS_CBC_HMAC_AEAD_Mode(ENCRYPTION, std::move(cipher), std::move(mac), cipher_keylen, mac_keylen, version, use_encrypt_then_mac) {} void set_associated_data(const uint8_t ad[], size_t ad_len) override; size_t output_length(size_t input_length) const override; size_t minimum_final_size() const override { return 0; } void finish(secure_vector& final_block, size_t offset = 0) override; private: void cbc_encrypt_record(secure_vector& buffer, size_t offset, size_t padding_length); }; /** * TLS_CBC_HMAC_AEAD Decryption */ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Decryption final : public TLS_CBC_HMAC_AEAD_Mode { public: /** */ TLS_CBC_HMAC_AEAD_Decryption(std::unique_ptr cipher, std::unique_ptr mac, const size_t cipher_keylen, const size_t mac_keylen, const Protocol_Version version, bool use_encrypt_then_mac) : TLS_CBC_HMAC_AEAD_Mode(DECRYPTION, std::move(cipher), std::move(mac), cipher_keylen, mac_keylen, version, use_encrypt_then_mac) {} size_t output_length(size_t input_length) const override; size_t minimum_final_size() const override { return tag_size(); } void finish(secure_vector& final_block, size_t offset = 0) override; private: void cbc_decrypt_record(uint8_t record_contents[], size_t record_len); void perform_additional_compressions(size_t plen, size_t padlen); }; /** * Check the TLS padding of a record * @param record the record bits * @param record_len length of record * @return 0 if padding is invalid, otherwise padding_bytes + 1 */ BOTAN_TEST_API uint16_t check_tls_cbc_padding(const uint8_t record[], size_t record_len); } } namespace Botan { namespace TLS { /** * TLS Handshake Hash */ class Handshake_Hash final { public: void update(const uint8_t in[], size_t length) { m_data += std::make_pair(in, length); } void update(const std::vector& in) { m_data += in; } secure_vector final(Protocol_Version version, const std::string& mac_algo) const; const std::vector& get_contents() const { return m_data; } void reset() { m_data.clear(); } private: std::vector m_data; }; } } namespace Botan { namespace TLS { class Handshake_Message; /** * Handshake IO Interface */ class Handshake_IO { public: virtual Protocol_Version initial_record_version() const = 0; virtual std::vector send(const Handshake_Message& msg) = 0; virtual std::vector send_under_epoch(const Handshake_Message& msg, uint16_t epoch) = 0; virtual bool timeout_check() = 0; virtual std::vector format( const std::vector& handshake_msg, Handshake_Type handshake_type) const = 0; virtual void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) = 0; /** * Returns (HANDSHAKE_NONE, std::vector<>()) if no message currently available */ virtual std::pair> get_next_record(bool expecting_ccs) = 0; Handshake_IO() = default; Handshake_IO(const Handshake_IO&) = delete; Handshake_IO& operator=(const Handshake_IO&) = delete; virtual ~Handshake_IO() = default; }; /** * Handshake IO for stream-based handshakes */ class Stream_Handshake_IO final : public Handshake_IO { public: typedef std::function&)> writer_fn; explicit Stream_Handshake_IO(writer_fn writer) : m_send_hs(writer) {} Protocol_Version initial_record_version() const override; bool timeout_check() override { return false; } std::vector send(const Handshake_Message& msg) override; std::vector send_under_epoch(const Handshake_Message& msg, uint16_t epoch) override; std::vector format( const std::vector& handshake_msg, Handshake_Type handshake_type) const override; void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override; std::pair> get_next_record(bool expecting_ccs) override; private: std::deque m_queue; writer_fn m_send_hs; }; /** * Handshake IO for datagram-based handshakes */ class Datagram_Handshake_IO final : public Handshake_IO { public: typedef std::function&)> writer_fn; Datagram_Handshake_IO(writer_fn writer, class Connection_Sequence_Numbers& seq, uint16_t mtu, uint64_t initial_timeout_ms, uint64_t max_timeout_ms) : m_seqs(seq), m_flights(1), m_initial_timeout(initial_timeout_ms), m_max_timeout(max_timeout_ms), m_send_hs(writer), m_mtu(mtu) {} Protocol_Version initial_record_version() const override; bool timeout_check() override; std::vector send(const Handshake_Message& msg) override; std::vector send_under_epoch(const Handshake_Message& msg, uint16_t epoch) override; std::vector format( const std::vector& handshake_msg, Handshake_Type handshake_type) const override; void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override; std::pair> get_next_record(bool expecting_ccs) override; private: void retransmit_flight(size_t flight); void retransmit_last_flight(); std::vector format_fragment( const uint8_t fragment[], size_t fragment_len, uint16_t frag_offset, uint16_t msg_len, Handshake_Type type, uint16_t msg_sequence) const; std::vector format_w_seq( const std::vector& handshake_msg, Handshake_Type handshake_type, uint16_t msg_sequence) const; std::vector send_message(uint16_t msg_seq, uint16_t epoch, Handshake_Type msg_type, const std::vector& msg); class Handshake_Reassembly final { public: void add_fragment(const uint8_t fragment[], size_t fragment_length, size_t fragment_offset, uint16_t epoch, uint8_t msg_type, size_t msg_length); bool complete() const; uint16_t epoch() const { return m_epoch; } std::pair> message() const; private: uint8_t m_msg_type = HANDSHAKE_NONE; size_t m_msg_length = 0; uint16_t m_epoch = 0; // vector m_seen; // vector m_fragments std::map m_fragments; std::vector m_message; }; struct Message_Info final { Message_Info(uint16_t e, Handshake_Type mt, const std::vector& msg) : epoch(e), msg_type(mt), msg_bits(msg) {} Message_Info() : epoch(0xFFFF), msg_type(HANDSHAKE_NONE) {} uint16_t epoch; Handshake_Type msg_type; std::vector msg_bits; }; class Connection_Sequence_Numbers& m_seqs; std::map m_messages; std::set m_ccs_epochs; std::vector> m_flights; std::map m_flight_data; uint64_t m_initial_timeout = 0; uint64_t m_max_timeout = 0; uint64_t m_last_write = 0; uint64_t m_next_timeout = 0; uint16_t m_in_message_seq = 0; uint16_t m_out_message_seq = 0; writer_fn m_send_hs; uint16_t m_mtu; }; } } namespace Botan { namespace TLS { class Handshake_State; /** * TLS Session Keys */ class Session_Keys final { public: /** * @return client AEAD key */ const secure_vector& client_aead_key() const { return m_c_aead; } /** * @return server AEAD key */ const secure_vector& server_aead_key() const { return m_s_aead; } /** * @return client nonce */ const std::vector& client_nonce() const { return m_c_nonce; } /** * @return server nonce */ const std::vector& server_nonce() const { return m_s_nonce; } /** * @return TLS master secret */ const secure_vector& master_secret() const { return m_master_sec; } const secure_vector& aead_key(Connection_Side side) const { return (side == Connection_Side::CLIENT) ? client_aead_key() : server_aead_key(); } const std::vector& nonce(Connection_Side side) const { return (side == Connection_Side::CLIENT) ? client_nonce() : server_nonce(); } Session_Keys() = default; /** * @param state state the handshake state * @param pre_master_secret the pre-master secret * @param resuming whether this TLS session is resumed */ Session_Keys(const Handshake_State* state, const secure_vector& pre_master_secret, bool resuming); private: secure_vector m_master_sec; secure_vector m_c_aead, m_s_aead; std::vector m_c_nonce, m_s_nonce; }; } } namespace Botan { class KDF; namespace TLS { class Callbacks; class Policy; class Hello_Verify_Request; class Client_Hello; class Server_Hello; class Certificate; class Certificate_Status; class Server_Key_Exchange; class Certificate_Req; class Server_Hello_Done; class Certificate; class Client_Key_Exchange; class Certificate_Verify; class New_Session_Ticket; class Finished; /** * SSL/TLS Handshake State */ class Handshake_State { public: Handshake_State(Handshake_IO* io, Callbacks& callbacks); virtual ~Handshake_State() = default; Handshake_State(const Handshake_State&) = delete; Handshake_State& operator=(const Handshake_State&) = delete; Handshake_IO& handshake_io() { return *m_handshake_io; } /** * Return true iff we have received a particular message already * @param msg_type the message type */ bool received_handshake_msg(Handshake_Type msg_type) const; /** * Confirm that we were expecting this message type * @param msg_type the message type */ void confirm_transition_to(Handshake_Type msg_type); /** * Record that we are expecting a particular message type next * @param msg_type the message type */ void set_expected_next(Handshake_Type msg_type); std::pair> get_next_handshake_msg(); std::vector session_ticket() const; std::pair parse_sig_format(const Public_Key& key, Signature_Scheme scheme, bool for_client_auth, const Policy& policy) const; std::pair choose_sig_format(const Private_Key& key, Signature_Scheme& scheme, bool for_client_auth, const Policy& policy) const; std::string srp_identifier() const; KDF* protocol_specific_prf() const; Protocol_Version version() const { return m_version; } void set_version(const Protocol_Version& version); void hello_verify_request(const Hello_Verify_Request& hello_verify); void client_hello(Client_Hello* client_hello); void server_hello(Server_Hello* server_hello); void server_certs(Certificate* server_certs); void server_cert_status(Certificate_Status* server_cert_status); void server_kex(Server_Key_Exchange* server_kex); void cert_req(Certificate_Req* cert_req); void server_hello_done(Server_Hello_Done* server_hello_done); void client_certs(Certificate* client_certs); void client_kex(Client_Key_Exchange* client_kex); void client_verify(Certificate_Verify* client_verify); void new_session_ticket(New_Session_Ticket* new_session_ticket); void server_finished(Finished* server_finished); void client_finished(Finished* client_finished); const Client_Hello* client_hello() const { return m_client_hello.get(); } const Server_Hello* server_hello() const { return m_server_hello.get(); } const Certificate* server_certs() const { return m_server_certs.get(); } const Server_Key_Exchange* server_kex() const { return m_server_kex.get(); } const Certificate_Req* cert_req() const { return m_cert_req.get(); } const Server_Hello_Done* server_hello_done() const { return m_server_hello_done.get(); } const Certificate* client_certs() const { return m_client_certs.get(); } const Client_Key_Exchange* client_kex() const { return m_client_kex.get(); } const Certificate_Verify* client_verify() const { return m_client_verify.get(); } const Certificate_Status* server_cert_status() const { return m_server_cert_status.get(); } const New_Session_Ticket* new_session_ticket() const { return m_new_session_ticket.get(); } const Finished* server_finished() const { return m_server_finished.get(); } const Finished* client_finished() const { return m_client_finished.get(); } const Ciphersuite& ciphersuite() const { return m_ciphersuite; } const Session_Keys& session_keys() const { return m_session_keys; } Callbacks& callbacks() const { return m_callbacks; } void compute_session_keys(); void compute_session_keys(const secure_vector& resume_master_secret); Handshake_Hash& hash() { return m_handshake_hash; } const Handshake_Hash& hash() const { return m_handshake_hash; } void note_message(const Handshake_Message& msg); private: Callbacks& m_callbacks; std::unique_ptr m_handshake_io; uint32_t m_hand_expecting_mask = 0; uint32_t m_hand_received_mask = 0; Protocol_Version m_version; Ciphersuite m_ciphersuite; Session_Keys m_session_keys; Handshake_Hash m_handshake_hash; std::unique_ptr m_client_hello; std::unique_ptr m_server_hello; std::unique_ptr m_server_certs; std::unique_ptr m_server_cert_status; std::unique_ptr m_server_kex; std::unique_ptr m_cert_req; std::unique_ptr m_server_hello_done; std::unique_ptr m_client_certs; std::unique_ptr m_client_kex; std::unique_ptr m_client_verify; std::unique_ptr m_new_session_ticket; std::unique_ptr m_server_finished; std::unique_ptr m_client_finished; }; } } namespace Botan { namespace TLS { /** * Helper class for decoding TLS protocol messages */ class TLS_Data_Reader final { public: TLS_Data_Reader(const char* type, const std::vector& buf_in) : m_typename(type), m_buf(buf_in), m_offset(0) {} void assert_done() const { if(has_remaining()) throw decode_error("Extra bytes at end of message"); } size_t read_so_far() const { return m_offset; } size_t remaining_bytes() const { return m_buf.size() - m_offset; } bool has_remaining() const { return (remaining_bytes() > 0); } std::vector get_remaining() { return std::vector(m_buf.begin() + m_offset, m_buf.end()); } void discard_next(size_t bytes) { assert_at_least(bytes); m_offset += bytes; } uint32_t get_uint32_t() { assert_at_least(4); uint32_t result = make_uint32(m_buf[m_offset ], m_buf[m_offset+1], m_buf[m_offset+2], m_buf[m_offset+3]); m_offset += 4; return result; } uint16_t get_uint16_t() { assert_at_least(2); uint16_t result = make_uint16(m_buf[m_offset], m_buf[m_offset+1]); m_offset += 2; return result; } uint8_t get_byte() { assert_at_least(1); uint8_t result = m_buf[m_offset]; m_offset += 1; return result; } template Container get_elem(size_t num_elems) { assert_at_least(num_elems * sizeof(T)); Container result(num_elems); for(size_t i = 0; i != num_elems; ++i) result[i] = load_be(&m_buf[m_offset], i); m_offset += num_elems * sizeof(T); return result; } template std::vector get_range(size_t len_bytes, size_t min_elems, size_t max_elems) { const size_t num_elems = get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); return get_elem>(num_elems); } template std::vector get_range_vector(size_t len_bytes, size_t min_elems, size_t max_elems) { const size_t num_elems = get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); return get_elem>(num_elems); } std::string get_string(size_t len_bytes, size_t min_bytes, size_t max_bytes) { std::vector v = get_range_vector(len_bytes, min_bytes, max_bytes); return std::string(cast_uint8_ptr_to_char(v.data()), v.size()); } template std::vector get_fixed(size_t size) { return get_elem>(size); } private: size_t get_length_field(size_t len_bytes) { assert_at_least(len_bytes); if(len_bytes == 1) return get_byte(); else if(len_bytes == 2) return get_uint16_t(); throw decode_error("Bad length size"); } size_t get_num_elems(size_t len_bytes, size_t T_size, size_t min_elems, size_t max_elems) { const size_t byte_length = get_length_field(len_bytes); if(byte_length % T_size != 0) throw decode_error("Size isn't multiple of T"); const size_t num_elems = byte_length / T_size; if(num_elems < min_elems || num_elems > max_elems) throw decode_error("Length field outside parameters"); return num_elems; } void assert_at_least(size_t n) const { if(m_buf.size() - m_offset < n) throw decode_error("Expected " + std::to_string(n) + " bytes remaining, only " + std::to_string(m_buf.size()-m_offset) + " left"); } Decoding_Error decode_error(const std::string& why) const { return Decoding_Error("Invalid " + std::string(m_typename) + ": " + why); } const char* m_typename; const std::vector& m_buf; size_t m_offset; }; /** * Helper function for encoding length-tagged vectors */ template void append_tls_length_value(std::vector& buf, const T* vals, size_t vals_size, size_t tag_size) { const size_t T_size = sizeof(T); const size_t val_bytes = T_size * vals_size; if(tag_size != 1 && tag_size != 2) throw Invalid_Argument("append_tls_length_value: invalid tag size"); if((tag_size == 1 && val_bytes > 255) || (tag_size == 2 && val_bytes > 65535)) throw Invalid_Argument("append_tls_length_value: value too large"); for(size_t i = 0; i != tag_size; ++i) buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); for(size_t i = 0; i != vals_size; ++i) for(size_t j = 0; j != T_size; ++j) buf.push_back(get_byte(j, vals[i])); } template void append_tls_length_value(std::vector& buf, const std::vector& vals, size_t tag_size) { append_tls_length_value(buf, vals.data(), vals.size(), tag_size); } template void append_tls_length_value(std::vector& buf, const std::string& str, size_t tag_size) { append_tls_length_value(buf, cast_char_ptr_to_uint8(str.data()), str.size(), tag_size); } } } namespace Botan { namespace TLS { class Ciphersuite; class Session_Keys; class Connection_Sequence_Numbers; /** * TLS Cipher State */ class Connection_Cipher_State final { public: /** * Initialize a new cipher state */ Connection_Cipher_State(Protocol_Version version, Connection_Side which_side, bool is_our_side, const Ciphersuite& suite, const Session_Keys& keys, bool uses_encrypt_then_mac); AEAD_Mode& aead() { BOTAN_ASSERT_NONNULL(m_aead.get()); return *m_aead.get(); } std::vector aead_nonce(uint64_t seq, RandomNumberGenerator& rng); std::vector aead_nonce(const uint8_t record[], size_t record_len, uint64_t seq); std::vector format_ad(uint64_t seq, uint8_t type, Protocol_Version version, uint16_t ptext_length); size_t nonce_bytes_from_handshake() const { return m_nonce_bytes_from_handshake; } size_t nonce_bytes_from_record() const { return m_nonce_bytes_from_record; } Nonce_Format nonce_format() const { return m_nonce_format; } std::chrono::seconds age() const { return std::chrono::duration_cast( std::chrono::system_clock::now() - m_start_time); } private: std::chrono::system_clock::time_point m_start_time; std::unique_ptr m_aead; std::vector m_nonce; Nonce_Format m_nonce_format; size_t m_nonce_bytes_from_handshake; size_t m_nonce_bytes_from_record; }; class Record_Header final { public: Record_Header(uint64_t sequence, Protocol_Version version, Record_Type type) : m_needed(0), m_sequence(sequence), m_version(version), m_type(type) {} Record_Header(size_t needed) : m_needed(needed), m_sequence(0), m_version(Protocol_Version()), m_type(NO_RECORD) {} size_t needed() const { return m_needed; } Protocol_Version version() const { BOTAN_ASSERT_NOMSG(m_needed == 0); return m_version; } uint64_t sequence() const { BOTAN_ASSERT_NOMSG(m_needed == 0); return m_sequence; } uint16_t epoch() const { return static_cast(sequence() >> 48); } Record_Type type() const { BOTAN_ASSERT_NOMSG(m_needed == 0); return m_type; } private: size_t m_needed; uint64_t m_sequence; Protocol_Version m_version; Record_Type m_type; }; /** * Create an initial (unencrypted) TLS handshake record * @param write_buffer the output record is placed here * @param record_type the record layer type * @param record_version the record layer version * @param record_sequence the record layer sequence number * @param message the record contents * @param message_len is size of message */ void write_unencrypted_record(secure_vector& write_buffer, uint8_t record_type, Protocol_Version record_version, uint64_t record_sequence, const uint8_t* message, size_t message_len); /** * Create a TLS record * @param write_buffer the output record is placed here * @param record_type the record layer type * @param record_version the record layer version * @param record_sequence the record layer sequence number * @param message the record contents * @param message_len is size of message * @param cipherstate is the writing cipher state * @param rng is a random number generator */ void write_record(secure_vector& write_buffer, uint8_t record_type, Protocol_Version record_version, uint64_t record_sequence, const uint8_t* message, size_t message_len, Connection_Cipher_State& cipherstate, RandomNumberGenerator& rng); // epoch -> cipher state typedef std::function (uint16_t)> get_cipherstate_fn; /** * Decode a TLS record * @return zero if full message, else number of bytes still needed */ Record_Header read_record(bool is_datagram, secure_vector& read_buffer, const uint8_t input[], size_t input_len, size_t& consumed, secure_vector& record_buf, Connection_Sequence_Numbers* sequence_numbers, get_cipherstate_fn get_cipherstate, bool allow_epoch0_restart); } } namespace Botan { namespace TLS { class Connection_Sequence_Numbers { public: virtual ~Connection_Sequence_Numbers() = default; virtual void new_read_cipher_state() = 0; virtual void new_write_cipher_state() = 0; virtual uint16_t current_read_epoch() const = 0; virtual uint16_t current_write_epoch() const = 0; virtual uint64_t next_write_sequence(uint16_t) = 0; virtual uint64_t next_read_sequence() = 0; virtual bool already_seen(uint64_t seq) const = 0; virtual void read_accept(uint64_t seq) = 0; virtual void reset() = 0; }; class Stream_Sequence_Numbers final : public Connection_Sequence_Numbers { public: Stream_Sequence_Numbers() { Stream_Sequence_Numbers::reset(); } void reset() override { m_write_seq_no = 0; m_read_seq_no = 0; m_read_epoch = 0; m_write_epoch = 0; } void new_read_cipher_state() override { m_read_seq_no = 0; m_read_epoch++; } void new_write_cipher_state() override { m_write_seq_no = 0; m_write_epoch++; } uint16_t current_read_epoch() const override { return m_read_epoch; } uint16_t current_write_epoch() const override { return m_write_epoch; } uint64_t next_write_sequence(uint16_t) override { return m_write_seq_no++; } uint64_t next_read_sequence() override { return m_read_seq_no; } bool already_seen(uint64_t) const override { return false; } void read_accept(uint64_t) override { m_read_seq_no++; } private: uint64_t m_write_seq_no; uint64_t m_read_seq_no; uint16_t m_read_epoch; uint16_t m_write_epoch; }; class Datagram_Sequence_Numbers final : public Connection_Sequence_Numbers { public: Datagram_Sequence_Numbers() { Datagram_Sequence_Numbers::reset(); } void reset() override { m_write_seqs.clear(); m_write_seqs[0] = 0; m_write_epoch = 0; m_read_epoch = 0; m_window_highest = 0; m_window_bits = 0; } void new_read_cipher_state() override { m_read_epoch++; } void new_write_cipher_state() override { m_write_epoch++; m_write_seqs[m_write_epoch] = 0; } uint16_t current_read_epoch() const override { return m_read_epoch; } uint16_t current_write_epoch() const override { return m_write_epoch; } uint64_t next_write_sequence(uint16_t epoch) override { auto i = m_write_seqs.find(epoch); BOTAN_ASSERT(i != m_write_seqs.end(), "Found epoch"); return (static_cast(epoch) << 48) | i->second++; } uint64_t next_read_sequence() override { throw Invalid_State("DTLS uses explicit sequence numbers"); } bool already_seen(uint64_t sequence) const override { const size_t window_size = sizeof(m_window_bits) * 8; if(sequence > m_window_highest) { return false; } const uint64_t offset = m_window_highest - sequence; if(offset >= window_size) { return true; // really old? } return (((m_window_bits >> offset) & 1) == 1); } void read_accept(uint64_t sequence) override { const size_t window_size = sizeof(m_window_bits) * 8; if(sequence > m_window_highest) { // We've received a later sequence which advances our window const uint64_t offset = sequence - m_window_highest; m_window_highest += offset; if(offset >= window_size) m_window_bits = 0; else m_window_bits <<= offset; m_window_bits |= 0x01; } else { const uint64_t offset = m_window_highest - sequence; if(offset < window_size) { // We've received an old sequence but still within our window m_window_bits |= (static_cast(1) << offset); } else { // This occurs only if we have reset state (DTLS reconnection case) m_window_highest = sequence; m_window_bits = 0; } } } private: std::map m_write_seqs; uint16_t m_write_epoch = 0; uint16_t m_read_epoch = 0; uint64_t m_window_highest = 0; uint64_t m_window_bits = 0; }; } } namespace Botan { struct BOTAN_TEST_API URI { enum class Type : uint8_t { NotSet, IPv4, IPv6, Domain, }; static URI fromAny(const std::string& uri); static URI fromIPv4(const std::string& uri); static URI fromIPv6(const std::string& uri); static URI fromDomain(const std::string& uri); URI() = default; URI(Type xtype, const std::string& xhost, unsigned short xport) : type { xtype } , host { xhost } , port { xport } {} bool operator==(const URI& a) const { return type == a.type && host == a.host && port == a.port; } std::string to_string() const; const Type type{Type::NotSet}; const std::string host{}; const uint16_t port{}; }; } namespace Botan { /** * Generic XMSS Address type holding 256 Bits of data. Properties * of all three address formats L-Tree-Address, Hash-Tree-Address, * OTS-Hash-Address can be called depending on the type currently * assigned to the XMSS address using set_type(). **/ class XMSS_Address final { public: /** * Distinct types an XMSS_Address can represent. The available types * are specified in [1] - 2.5 Hash Function Address Scheme. **/ enum class Type : uint8_t { None = 255, OTS_Hash_Address = 0, LTree_Address = 1, Hash_Tree_Address = 2 }; /** * The available modes for an XMSS Address: * - Key_Mode: Used to generate the key. * - Mask_Mode: Sets the n-byte bitmask (OTS-Hash-Address) * - Mask_MSB_Mode: Used to generate the b most significant bytes of * the 2n-byte bitmask (LTree Address and Hash Tree Address). * - Mask_LSB_Mode: Used to generated the b least significant bytes * of the 2n-byte bitmask. (LTree Address and Hash Tree Address). **/ enum class Key_Mask : uint8_t { Key_Mode = 0, Mask_Mode = 1, Mask_MSB_Mode = 1, Mask_LSB_Mode = 2 }; /** * Layer Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. * * @return Layer address, which is constant 0 for XMSS. **/ uint8_t get_layer_addr() const { return 0; } /** * Layer Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. Calling this method for * XMSS will result in an error. **/ void set_layer_addr() { BOTAN_ASSERT(false, "Only available in XMSS_MT."); } /** * Tree Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. * * @return Tree address, which is constant 0 for XMSS. **/ uint64_t get_tree_addr() const { return 0; } /** * Tree Address for XMSS is constantly zero and can not be changed this * property is only of relevance to XMSS_MT. Calling this method for * XMSS will result in an error. **/ void set_tree_addr() { BOTAN_ASSERT(false, "Only available in XMSS_MT."); } /** * retrieves the logical type currently assigned to the XMSS Address * instance. * * @return Type of the address (OTS_Hash_Address, LTree_Address or * Hash_Tree_Address) **/ Type get_type() const { return static_cast(m_data[15]); } /** * Changes the logical type currently assigned to the XMSS Address * instance. Please note that changing the type will automatically * reset the 128 LSBs of the Address to zero. This affects the * key_mask_mode property as well as all properties identified by * XMSS_Address::Property. * * @param type Type that shall be assigned to the address * (OTS_Hash_Address, LTree_Address or Hash_Tree_Address) **/ void set_type(Type type) { m_data[15] = static_cast(type); std::fill(m_data.begin() + 16, m_data.end(), static_cast(0)); } /** * Retrieves the mode the address os currently set to. (See * XMSS_Address::Key_Mask for details.) * * @return currently active mode **/ Key_Mask get_key_mask_mode() const { return Key_Mask(m_data[31]); } /** * Changes the mode the address currently used address mode. * (XMSS_Address::Key_Mask for details.) * * @param value Target mode. **/ void set_key_mask_mode(Key_Mask value) { BOTAN_ASSERT(value != Key_Mask::Mask_LSB_Mode || get_type() != Type::OTS_Hash_Address, "Invalid Key_Mask for current XMSS_Address::Type."); m_data[31] = static_cast(value); } /** * Retrieve the index of the OTS key pair within the tree. A call to * this method is only valid, if the address type is set to * Type::OTS_Hash_Address. * * @return index of OTS key pair. **/ uint32_t get_ots_address() const { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "get_ots_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); return get_hi32(2); } /** * Sets the index of the OTS key pair within the tree. A call to this * method is only valid, if the address type is set to * Type::OTS_Hash_Address. * * @param value index of OTS key pair. **/ void set_ots_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "set_ots_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); set_hi32(2, value); } /** * Retrieves the index of the leaf computed with this LTree. A call to * this method is only valid, if the address type is set to * Type::LTree_Address. * * @return index of the leaf. **/ uint32_t get_ltree_address() const { BOTAN_ASSERT(get_type() == Type::LTree_Address, "set_ltree_address() requires XMSS_Address::Type::" "LTree_Address."); return get_hi32(2); } /** * Sets the index of the leaf computed with this LTree. A call to this * method is only valid, if the address type is set to * Type::LTree_Address. * * @param value index of the leaf. **/ void set_ltree_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::LTree_Address, "set_ltree_address() requires XMSS_Address::Type::" "LTree_Address."); set_hi32(2, value); } /** * Retrieve the chain address. A call to this method is only valid, if * the address type is set to Type::OTS_Hash_Address. * * @return chain address. **/ uint32_t get_chain_address() const { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "get_chain_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); return get_lo32(2); } /** * Set the chain address. A call to this method is only valid, if * the address type is set to Type::OTS_Hash_Address. **/ void set_chain_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "set_chain_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); set_lo32(2, value); } /** * Retrieves the height of the tree node to be computed within the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @return height of the tree node. **/ uint32_t get_tree_height() const { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "get_tree_height() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); return get_lo32(2); } /** * Sets the height of the tree node to be computed within the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @param value height of the tree node. **/ void set_tree_height(uint32_t value) { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "set_tree_height() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); set_lo32(2, value); } /** * Retrieves the address of the hash function call within the chain. * A call to this method is only valid, if the address type is * set to Type::OTS_Hash_Address. * * @return address of the hash function call within chain. **/ uint32_t get_hash_address() const { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "get_hash_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); return get_hi32(3); } /** * Sets the address of the hash function call within the chain. * A call to this method is only valid, if the address type is * set to Type::OTS_Hash_Address. * * @param value address of the hash function call within chain. **/ void set_hash_address(uint32_t value) { BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, "set_hash_address() requires XMSS_Address::Type::" "OTS_Hash_Address."); set_hi32(3, value); } /** * Retrieves the index of the tree node at current tree height in the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @return index of the tree node at current height. **/ uint32_t get_tree_index() const { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "get_tree_index() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); return get_hi32(3); } /** * Sets the index of the tree node at current tree height in the * tree. A call to this method is only valid, if the address type is * set to Type::LTree_Address or Type::Hash_Tree_Address. * * @param value index of the tree node at current height. **/ void set_tree_index(uint32_t value) { BOTAN_ASSERT(get_type() == Type::LTree_Address || get_type() == Type::Hash_Tree_Address, "set_tree_index() requires XMSS_Address::Type::" "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); set_hi32(3, value); } const secure_vector& bytes() const { return m_data; } secure_vector& bytes() { return m_data; } /** * @return the size of an XMSS_Address **/ size_t size() const { return m_data.size(); } XMSS_Address() : m_data(m_address_size) { set_type(Type::None); } XMSS_Address(Type type) : m_data(m_address_size) { set_type(type); } XMSS_Address(const secure_vector& data) : m_data(data) { BOTAN_ASSERT(m_data.size() == m_address_size, "XMSS_Address must be of 256 bits size."); } XMSS_Address(secure_vector&& data) : m_data(std::move(data)) { BOTAN_ASSERT(m_data.size() == m_address_size, "XMSS_Address must be of 256 bits size."); } protected: secure_vector m_data; private: static const size_t m_address_size = 32; inline uint32_t get_hi32(size_t offset) const { return ((0x000000FF & m_data[8 * offset + 3]) | (0x000000FF & m_data[8 * offset + 2]) << 8 | (0x000000FF & m_data[8 * offset + 1]) << 16 | (0x000000FF & m_data[8 * offset ]) << 24); } inline void set_hi32(size_t offset, uint32_t value) { m_data[offset * 8 ] = ((value >> 24) & 0xFF); m_data[offset * 8 + 1] = ((value >> 16) & 0xFF); m_data[offset * 8 + 2] = ((value >> 8) & 0xFF); m_data[offset * 8 + 3] = ((value ) & 0xFF); } inline uint32_t get_lo32(size_t offset) const { return ((0x000000FF & m_data[8 * offset + 7]) | (0x000000FF & m_data[8 * offset + 6]) << 8 | (0x000000FF & m_data[8 * offset + 5]) << 16 | (0x000000FF & m_data[8 * offset + 4]) << 24); } inline void set_lo32(size_t offset, uint32_t value) { m_data[offset * 8 + 4] = ((value >> 24) & 0xFF); m_data[offset * 8 + 5] = ((value >> 16) & 0xFF); m_data[offset * 8 + 6] = ((value >> 8) & 0xFF); m_data[offset * 8 + 7] = ((value ) & 0xFF); } }; } BOTAN_FUTURE_INTERNAL_HEADER(xmss_common_ops.h) namespace Botan { typedef std::vector> wots_keysig_t; /** * Operations shared by XMSS signature generation and verification operations. **/ class XMSS_Common_Ops { public: /** * Algorithm 7: "RAND_HASH" * * Generates a randomized hash. * * This overload is used in multithreaded scenarios, where it is * required to provide seperate instances of XMSS_Hash to each * thread. * * @param[out] result The resulting randomized hash. * @param[in] left Left half of the hash function input. * @param[in] right Right half of the hash function input. * @param[in] adrs Adress of the hash function call. * @param[in] seed The seed for G. * @param[in] hash Instance of XMSS_Hash, that may only by the thead * executing generate_public_key. * @param[in] params **/ static void randomize_tree_hash( secure_vector& result, const secure_vector& left, const secure_vector& right, XMSS_Address& adrs, const secure_vector& seed, XMSS_Hash& hash, const XMSS_Parameters& params); /** * Algorithm 8: "ltree" * Create an L-tree used to compute the leaves of the binary hash tree. * Takes a WOTS+ public key and compresses it to a single n-byte value. * * This overload is used in multithreaded scenarios, where it is * required to provide seperate instances of XMSS_Hash to each thread. * * @param[out] result Public key compressed to a single n-byte value * pk[0]. * @param[in] pk Winternitz One Time Signatures+ public key. * @param[in] adrs Address encoding the address of the L-Tree * @param[in] seed The seed generated during the public key generation. * @param[in] hash Instance of XMSS_Hash, that may only be used by the * thead executing create_l_tree. * @param[in] params **/ static void create_l_tree(secure_vector& result, wots_keysig_t pk, XMSS_Address& adrs, const secure_vector& seed, XMSS_Hash& hash, const XMSS_Parameters& params); }; } //BOTAN_FUTURE_INTERNAL_HEADER(xmss_index_registry.h) namespace Botan { /** * A registry for XMSS private keys, keeps track of the leaf index for * independend copies of the same key. **/ class XMSS_Index_Registry final { public: XMSS_Index_Registry(const XMSS_Index_Registry&) = delete; XMSS_Index_Registry& operator=(const XMSS_Index_Registry&) = delete; /** * Retrieves a handle to the process-wide unique XMSS index registry. * * @return Reference to unique XMSS index registry. **/ static XMSS_Index_Registry& get_instance() { static XMSS_Index_Registry self; return self; } /** * Retrieves the last unused leaf index for the private key identified * by private_seed and prf. The leaf index will be updated properly * across independent copies of private_key. * * @param private_seed Part of the unique identifier for an * XMSS_PrivateKey. * @param prf Part of the unique identifier for an XMSS_PrivateKey. * * @return last unused leaf index for private_key. **/ std::shared_ptr> get(const secure_vector& private_seed, const secure_vector& prf); private: XMSS_Index_Registry() = default; static const std::string m_index_hash_function; /** * Creates a unique 64-bit id for an XMSS_Private key, by interpreting * the first 64-bit of HASH(PRIVATE_SEED || PRF) as 64 bit integer * value. * * @return unique integral identifier for an XMSS private key. **/ uint64_t make_key_id(const secure_vector& private_seed, const secure_vector& prf) const; /** * Retrieves the index position of a key within the registry or * max(size_t) if key has not been found. * * @param id unique id of the XMSS private key (see make_key_id()). * * @return index position of key or max(size_t) if key not found. **/ size_t get(uint64_t id) const; /** * If XMSS_PrivateKey identified by id is already registered, the * position of the according registry entry is returned. If last_unused * is bigger than the last unused index stored for the key identified by * id the unused leaf index for this key is set to last_unused. If no key * matching id is registed yet, an entry of id is added, with the last * unused leaf index initialized to the value of last_unused. * * @last_unused Initial value for the last unused leaf index of the * registered key. * * @return positon of leaf index registry entry for key identified * by id. **/ size_t add(uint64_t id, size_t last_unused = 0); std::vector m_key_ids; std::vector>> m_leaf_indices; mutex_type m_mutex; }; } namespace Botan { class XMSS_Signature final { public: /** * Creates a signature from an XMSS signature method and a uint8_t sequence * representing a raw signature. * * @param oid XMSS signature method * @param raw_sig An XMSS signature serialized using * XMSS_Signature::bytes(). **/ XMSS_Signature(XMSS_Parameters::xmss_algorithm_t oid, const secure_vector& raw_sig); /** * Creates an XMSS Signature from a leaf index used for signature * generation, a random value and a tree signature. * * @param leaf_idx Leaf index used to generate the signature. * @param randomness A random value. * @param tree_sig A tree signature. **/ XMSS_Signature(size_t leaf_idx, const secure_vector& randomness, const XMSS_WOTS_PublicKey::TreeSignature& tree_sig) : m_leaf_idx(leaf_idx), m_randomness(randomness), m_tree_sig(tree_sig) {} /** * Creates an XMSS Signature from a leaf index used for signature * generation, a random value and a tree signature. * * @param leaf_idx Leaf index used to generate the signature. * @param randomness A random value. * @param tree_sig A tree signature. **/ XMSS_Signature(size_t leaf_idx, secure_vector&& randomness, XMSS_WOTS_PublicKey::TreeSignature&& tree_sig) : m_leaf_idx(leaf_idx), m_randomness(std::move(randomness)), m_tree_sig(std::move(tree_sig)) {} size_t unused_leaf_index() const { return m_leaf_idx; } void set_unused_leaf_idx(size_t idx) { m_leaf_idx = idx; } const secure_vector randomness() const { return m_randomness; } secure_vector& randomness() { return m_randomness; } void set_randomness(const secure_vector& randomness) { m_randomness = randomness; } void set_randomness(secure_vector&& randomness) { m_randomness = std::move(randomness); } const XMSS_WOTS_PublicKey::TreeSignature& tree() const { return m_tree_sig; } XMSS_WOTS_PublicKey::TreeSignature& tree() { return m_tree_sig; } void set_tree(const XMSS_WOTS_PublicKey::TreeSignature& tree_sig) { m_tree_sig = tree_sig; } void set_tree(XMSS_WOTS_PublicKey::TreeSignature&& tree_sig) { m_tree_sig = std::move(tree_sig); } /** * Generates a serialized representation of XMSS Signature by * concatenating the following elements in order: * 4-byte leaf index, n-bytes randomness, ots_signature, * authentication path. * * n is the element_size(), len equal to len(), h the tree height * defined by the chosen XMSS signature method. * * @return serialized signature, a sequence of * 4+(len + h + 1)n bytes. **/ secure_vector bytes() const; private: size_t m_leaf_idx; secure_vector m_randomness; XMSS_WOTS_PublicKey::TreeSignature m_tree_sig; }; } namespace Botan { /** * Signature generation operation for Extended Hash-Based Signatures (XMSS) as * defined in: * * [1] XMSS: Extended Hash-Based Signatures, * Request for Comments: 8391 * Release: May 2018. * https://datatracker.ietf.org/doc/rfc8391/ **/ class XMSS_Signature_Operation final : public virtual PK_Ops::Signature { public: XMSS_Signature_Operation(const XMSS_PrivateKey& private_key); /** * Creates an XMSS signature for the message provided through call to * update(). * * @return serialized XMSS signature. **/ secure_vector sign(RandomNumberGenerator&) override; void update(const uint8_t msg[], size_t msg_len) override; size_t signature_length() const override; private: /** * Algorithm 11: "treeSig" * Generate a WOTS+ signature on a message with corresponding auth path. * * @param msg A message. * @param xmss_priv_key A XMSS private key. * @param adrs A XMSS Address. **/ XMSS_WOTS_PublicKey::TreeSignature generate_tree_signature( const secure_vector& msg, XMSS_PrivateKey& xmss_priv_key, XMSS_Address& adrs); /** * Algorithm 12: "XMSS_sign" * Generate an XMSS signature and update the XMSS secret key * * @param msg A message to sign of arbitrary length. * @param [out] xmss_priv_key A XMSS private key. The private key will be * updated during the signing process. * * @return The signature of msg signed using xmss_priv_key. **/ XMSS_Signature sign( const secure_vector& msg, XMSS_PrivateKey& xmss_priv_key); wots_keysig_t build_auth_path(XMSS_PrivateKey& priv_key, XMSS_Address& adrs); void initialize(); XMSS_PrivateKey m_priv_key; const XMSS_Parameters m_xmss_params; XMSS_Hash m_hash; secure_vector m_randomness; uint32_t m_leaf_idx; bool m_is_initialized; }; } //BOTAN_FUTURE_INTERNAL_HEADER(xmss_tools.h) namespace Botan { /** * Helper tools for low level byte operations required * for the XMSS implementation. **/ class XMSS_Tools final { public: XMSS_Tools(const XMSS_Tools&) = delete; void operator=(const XMSS_Tools&) = delete; /** * Concatenates the byte representation in big-endian order of any * integral value to a secure_vector. * * @param target Vector to concatenate the byte representation of the * integral value to. * @param src integral value to concatenate. **/ template::value, void>::type> static void concat(secure_vector& target, const T& src); /** * Concatenates the last n bytes of the byte representation in big-endian * order of any integral value to a to a secure_vector. * * @param target Vector to concatenate the byte representation of the * integral value to. * @param src Integral value to concatenate. * @param len number of bytes to concatenate. This value must be smaller * or equal to the size of type T. **/ template ::value, void>::type> static void concat(secure_vector& target, const T& src, size_t len); private: XMSS_Tools(); }; template void XMSS_Tools::concat(secure_vector& target, const T& src) { const uint8_t* src_bytes = reinterpret_cast(&src); if(CPUID::is_little_endian()) { std::reverse_copy(src_bytes, src_bytes + sizeof(src), std::back_inserter(target)); } else { std::copy(src_bytes, src_bytes + sizeof(src), std::back_inserter(target)); } } template void XMSS_Tools::concat(secure_vector& target, const T& src, size_t len) { size_t c = static_cast(std::min(len, sizeof(src))); if(len > sizeof(src)) { target.resize(target.size() + len - sizeof(src), 0); } const uint8_t* src_bytes = reinterpret_cast(&src); if(CPUID::is_little_endian()) { std::reverse_copy(src_bytes, src_bytes + c, std::back_inserter(target)); } else { std::copy(src_bytes + sizeof(src) - c, src_bytes + sizeof(src), std::back_inserter(target)); } } } namespace Botan { /** * Provides signature verification capabilities for Extended Hash-Based * Signatures (XMSS). **/ class XMSS_Verification_Operation final : public virtual PK_Ops::Verification { public: XMSS_Verification_Operation( const XMSS_PublicKey& public_key); bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; void update(const uint8_t msg[], size_t msg_len) override; private: /** * Algorithm 13: "XMSS_rootFromSig" * Computes a root node using an XMSS signature, a message and a seed. * * @param msg A message. * @param sig The XMSS signature for msg. * @param ards A XMSS tree address. * @param seed A seed. * * @return An n-byte string holding the value of the root of a tree * defined by the input parameters. **/ secure_vector root_from_signature( const XMSS_Signature& sig, const secure_vector& msg, XMSS_Address& ards, const secure_vector& seed); /** * Algorithm 14: "XMSS_verify" * Verifies a XMSS signature using the corresponding XMSS public key. * * @param sig A XMSS signature. * @param msg The message signed with sig. * @param pub_key the public key * * @return true if signature sig is valid for msg, false otherwise. **/ bool verify(const XMSS_Signature& sig, const secure_vector& msg, const XMSS_PublicKey& pub_key); const XMSS_PublicKey& m_pub_key; XMSS_Hash m_hash; secure_vector m_msg_buf; }; } namespace Botan { /** * Wrapper class to pair a XMSS_WOTS_PublicKey with an XMSS Address. Since * the PK_Ops::Verification interface does not allow an extra address * parameter to be passed to the sign(RandomNumberGenerator&), the address * needs to be stored together with the key and passed to the * XMSS_WOTS_Verification_Operation() on creation. **/ class XMSS_WOTS_Addressed_PublicKey : public virtual Public_Key { public: XMSS_WOTS_Addressed_PublicKey(const XMSS_WOTS_PublicKey& public_key) : m_pub_key(public_key), m_adrs() {} XMSS_WOTS_Addressed_PublicKey(const XMSS_WOTS_PublicKey& public_key, const XMSS_Address& adrs) : m_pub_key(public_key), m_adrs(adrs) {} XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey&& public_key) : m_pub_key(std::move(public_key)), m_adrs() {} XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey&& public_key, XMSS_Address&& adrs) : m_pub_key(std::move(public_key)), m_adrs(std::move(adrs)) {} const XMSS_WOTS_PublicKey& public_key() const { return m_pub_key; } XMSS_WOTS_PublicKey& public_key() { return m_pub_key; } const XMSS_Address& address() const { return m_adrs; } XMSS_Address& address() { return m_adrs; } std::string algo_name() const override { return m_pub_key.algo_name(); } AlgorithmIdentifier algorithm_identifier() const override { return m_pub_key.algorithm_identifier(); } bool check_key(RandomNumberGenerator& rng, bool strong) const override { return m_pub_key.check_key(rng, strong); } std::unique_ptr create_verification_op(const std::string& params, const std::string& provider) const override { return m_pub_key.create_verification_op(params, provider); } OID get_oid() const override { return m_pub_key.get_oid(); } size_t estimated_strength() const override { return m_pub_key.estimated_strength(); } size_t key_length() const override { return m_pub_key.estimated_strength(); } std::vector public_key_bits() const override { return m_pub_key.public_key_bits(); } protected: XMSS_WOTS_PublicKey m_pub_key; XMSS_Address m_adrs; }; } namespace Botan { /** * Wrapper class to pair an XMSS_WOTS_PrivateKey with an XMSS Address. Since * the PK_Ops::Signature interface does not allow an extra address * parameter to be passed to the sign(RandomNumberGenerator&), the address * needs to be stored together with the key and passed to the * XMSS_WOTS_Signature_Operation() on creation. **/ class XMSS_WOTS_Addressed_PrivateKey final : public virtual XMSS_WOTS_Addressed_PublicKey, public virtual Private_Key { public: XMSS_WOTS_Addressed_PrivateKey(const XMSS_WOTS_PrivateKey& private_key) : XMSS_WOTS_Addressed_PublicKey(private_key), m_priv_key(private_key) {} XMSS_WOTS_Addressed_PrivateKey(const XMSS_WOTS_PrivateKey& private_key, const XMSS_Address& adrs) : XMSS_WOTS_Addressed_PublicKey(private_key, adrs), m_priv_key(private_key) {} XMSS_WOTS_Addressed_PrivateKey(XMSS_WOTS_PrivateKey&& private_key) : XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey(private_key)), m_priv_key(std::move(private_key)) {} XMSS_WOTS_Addressed_PrivateKey(XMSS_WOTS_PrivateKey&& private_key, XMSS_Address&& adrs) : XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey(private_key), std::move(adrs)), m_priv_key(std::move(private_key)) {} const XMSS_WOTS_PrivateKey& private_key() const { return m_priv_key; } XMSS_WOTS_PrivateKey& private_key() { return m_priv_key; } AlgorithmIdentifier pkcs8_algorithm_identifier() const override { return m_priv_key.pkcs8_algorithm_identifier(); } secure_vector private_key_bits() const override { return m_priv_key.private_key_bits(); } private: XMSS_WOTS_PrivateKey m_priv_key; }; } /* * Adler32 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void adler32_update(const uint8_t input[], size_t length, uint16_t& S1, uint16_t& S2) { uint32_t S1x = S1; uint32_t S2x = S2; while(length >= 16) { S1x += input[ 0]; S2x += S1x; S1x += input[ 1]; S2x += S1x; S1x += input[ 2]; S2x += S1x; S1x += input[ 3]; S2x += S1x; S1x += input[ 4]; S2x += S1x; S1x += input[ 5]; S2x += S1x; S1x += input[ 6]; S2x += S1x; S1x += input[ 7]; S2x += S1x; S1x += input[ 8]; S2x += S1x; S1x += input[ 9]; S2x += S1x; S1x += input[10]; S2x += S1x; S1x += input[11]; S2x += S1x; S1x += input[12]; S2x += S1x; S1x += input[13]; S2x += S1x; S1x += input[14]; S2x += S1x; S1x += input[15]; S2x += S1x; input += 16; length -= 16; } for(size_t j = 0; j != length; ++j) { S1x += input[j]; S2x += S1x; } S1 = S1x % 65521; S2 = S2x % 65521; } } /* * Update an Adler32 Checksum */ void Adler32::add_data(const uint8_t input[], size_t length) { const size_t PROCESS_AMOUNT = 5552; while(length >= PROCESS_AMOUNT) { adler32_update(input, PROCESS_AMOUNT, m_S1, m_S2); input += PROCESS_AMOUNT; length -= PROCESS_AMOUNT; } adler32_update(input, length, m_S1, m_S2); } /* * Finalize an Adler32 Checksum */ void Adler32::final_result(uint8_t output[]) { store_be(output, m_S2, m_S1); clear(); } std::unique_ptr Adler32::copy_state() const { return std::unique_ptr(new Adler32(*this)); } } /* * (C) 2013,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_HAS_BLOCK_CIPHER) #endif #if defined(BOTAN_HAS_AEAD_CCM) #endif #if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) #endif #if defined(BOTAN_HAS_AEAD_EAX) #endif #if defined(BOTAN_HAS_AEAD_GCM) #endif #if defined(BOTAN_HAS_AEAD_OCB) #endif #if defined(BOTAN_HAS_AEAD_SIV) #endif namespace Botan { void AEAD_Mode::set_associated_data_n(size_t i, const uint8_t ad[], size_t ad_len) { if(i == 0) this->set_associated_data(ad, ad_len); else throw Invalid_Argument("AEAD '" + name() + "' does not support multiple associated data"); } std::unique_ptr AEAD_Mode::create_or_throw(const std::string& algo, Cipher_Dir dir, const std::string& provider) { if(auto aead = AEAD_Mode::create(algo, dir, provider)) return aead; throw Lookup_Error("AEAD", algo, provider); } std::unique_ptr AEAD_Mode::create(const std::string& algo, Cipher_Dir dir, const std::string& provider) { BOTAN_UNUSED(provider); #if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) if(algo == "ChaCha20Poly1305") { if(dir == ENCRYPTION) return std::unique_ptr(new ChaCha20Poly1305_Encryption); else return std::unique_ptr(new ChaCha20Poly1305_Decryption); } #endif if(algo.find('/') != std::string::npos) { const std::vector algo_parts = split_on(algo, '/'); const std::string cipher_name = algo_parts[0]; const std::vector mode_info = parse_algorithm_name(algo_parts[1]); if(mode_info.empty()) return std::unique_ptr(); std::ostringstream alg_args; alg_args << '(' << cipher_name; for(size_t i = 1; i < mode_info.size(); ++i) alg_args << ',' << mode_info[i]; for(size_t i = 2; i < algo_parts.size(); ++i) alg_args << ',' << algo_parts[i]; alg_args << ')'; const std::string mode_name = mode_info[0] + alg_args.str(); return AEAD_Mode::create(mode_name, dir); } #if defined(BOTAN_HAS_BLOCK_CIPHER) SCAN_Name req(algo); if(req.arg_count() == 0) { return std::unique_ptr(); } std::unique_ptr bc(BlockCipher::create(req.arg(0), provider)); if(!bc) { return std::unique_ptr(); } #if defined(BOTAN_HAS_AEAD_CCM) if(req.algo_name() == "CCM") { size_t tag_len = req.arg_as_integer(1, 16); size_t L_len = req.arg_as_integer(2, 3); if(dir == ENCRYPTION) return std::unique_ptr(new CCM_Encryption(bc.release(), tag_len, L_len)); else return std::unique_ptr(new CCM_Decryption(bc.release(), tag_len, L_len)); } #endif #if defined(BOTAN_HAS_AEAD_GCM) if(req.algo_name() == "GCM") { size_t tag_len = req.arg_as_integer(1, 16); if(dir == ENCRYPTION) return std::unique_ptr(new GCM_Encryption(bc.release(), tag_len)); else return std::unique_ptr(new GCM_Decryption(bc.release(), tag_len)); } #endif #if defined(BOTAN_HAS_AEAD_OCB) if(req.algo_name() == "OCB") { size_t tag_len = req.arg_as_integer(1, 16); if(dir == ENCRYPTION) return std::unique_ptr(new OCB_Encryption(bc.release(), tag_len)); else return std::unique_ptr(new OCB_Decryption(bc.release(), tag_len)); } #endif #if defined(BOTAN_HAS_AEAD_EAX) if(req.algo_name() == "EAX") { size_t tag_len = req.arg_as_integer(1, bc->block_size()); if(dir == ENCRYPTION) return std::unique_ptr(new EAX_Encryption(bc.release(), tag_len)); else return std::unique_ptr(new EAX_Decryption(bc.release(), tag_len)); } #endif #if defined(BOTAN_HAS_AEAD_SIV) if(req.algo_name() == "SIV") { if(dir == ENCRYPTION) return std::unique_ptr(new SIV_Encryption(bc.release())); else return std::unique_ptr(new SIV_Decryption(bc.release())); } #endif #endif return std::unique_ptr(); } } /* * (C) 1999-2010,2015,2017,2018,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { #if defined(BOTAN_HAS_AES_POWER8) || defined(BOTAN_HAS_AES_ARMV8) || defined(BOTAN_HAS_AES_NI) #define BOTAN_HAS_HW_AES_SUPPORT #endif /* * One of three AES implementation strategies are used to get a constant time * implementation which is immune to common cache/timing based side channels: * * - If AES hardware support is available (AES-NI, POWER8, Aarch64) use that * * - If 128-bit SIMD with byte shuffles are available (SSSE3, NEON, or Altivec), * use the vperm technique published by Mike Hamburg at CHES 2009. * * - If no hardware or SIMD support, fall back to a constant time bitsliced * implementation. This uses 32-bit words resulting in 2 blocks being processed * in parallel. Moving to 4 blocks (with 64-bit words) would approximately * double performance on 64-bit CPUs. Likewise moving to 128 bit SIMD would * again approximately double performance vs 64-bit. However the assumption is * that most 64-bit CPUs either have hardware AES or SIMD shuffle support and * that the majority of users falling back to this code will be 32-bit cores. * If this assumption proves to be unsound, the bitsliced code can easily be * extended to operate on either 32 or 64 bit words depending on the native * wordsize of the target processor. * * Useful references * * - "Accelerating AES with Vector Permute Instructions" Mike Hamburg * https://www.shiftleft.org/papers/vector_aes/vector_aes.pdf * * - "Faster and Timing-Attack Resistant AES-GCM" Käsper and Schwabe * https://eprint.iacr.org/2009/129.pdf * * - "A new combinational logic minimization technique with applications to cryptology." * Boyar and Peralta https://eprint.iacr.org/2009/191.pdf * * - "A depth-16 circuit for the AES S-box" Boyar and Peralta * https://eprint.iacr.org/2011/332.pdf * * - "A Very Compact S-box for AES" Canright * https://www.iacr.org/archive/ches2005/032.pdf * https://core.ac.uk/download/pdf/36694529.pdf (extended) */ namespace { /* This is an AES sbox circuit which can execute in bitsliced mode up to 32x in parallel. The circuit is from the "Circuit Minimization Team" group http://www.cs.yale.edu/homes/peralta/CircuitStuff/CMT.html http://www.cs.yale.edu/homes/peralta/CircuitStuff/SLP_AES_113.txt This circuit has size 113 and depth 27. In software it is much faster than circuits which are considered faster for hardware purposes (where circuit depth is the critical constraint), because unlike in hardware, on common CPUs we can only execute - at best - 3 or 4 logic operations per cycle. So a smaller circuit is superior. On an x86-64 machine this circuit is about 15% faster than the circuit of size 128 and depth 16 given in "A depth-16 circuit for the AES S-box". Another circuit for AES Sbox of size 102 and depth 24 is describted in "New Circuit Minimization Techniques for Smaller and Faster AES SBoxes" [https://eprint.iacr.org/2019/802] however it relies on "non-standard" gates like MUX, NOR, NAND, etc and so in practice in bitsliced software, its size is actually a bit larger than this circuit, as few CPUs have such instructions and otherwise they must be emulated using a sequence of available bit operations. */ void AES_SBOX(uint32_t V[8]) { const uint32_t U0 = V[0]; const uint32_t U1 = V[1]; const uint32_t U2 = V[2]; const uint32_t U3 = V[3]; const uint32_t U4 = V[4]; const uint32_t U5 = V[5]; const uint32_t U6 = V[6]; const uint32_t U7 = V[7]; const uint32_t y14 = U3 ^ U5; const uint32_t y13 = U0 ^ U6; const uint32_t y9 = U0 ^ U3; const uint32_t y8 = U0 ^ U5; const uint32_t t0 = U1 ^ U2; const uint32_t y1 = t0 ^ U7; const uint32_t y4 = y1 ^ U3; const uint32_t y12 = y13 ^ y14; const uint32_t y2 = y1 ^ U0; const uint32_t y5 = y1 ^ U6; const uint32_t y3 = y5 ^ y8; const uint32_t t1 = U4 ^ y12; const uint32_t y15 = t1 ^ U5; const uint32_t y20 = t1 ^ U1; const uint32_t y6 = y15 ^ U7; const uint32_t y10 = y15 ^ t0; const uint32_t y11 = y20 ^ y9; const uint32_t y7 = U7 ^ y11; const uint32_t y17 = y10 ^ y11; const uint32_t y19 = y10 ^ y8; const uint32_t y16 = t0 ^ y11; const uint32_t y21 = y13 ^ y16; const uint32_t y18 = U0 ^ y16; const uint32_t t2 = y12 & y15; const uint32_t t3 = y3 & y6; const uint32_t t4 = t3 ^ t2; const uint32_t t5 = y4 & U7; const uint32_t t6 = t5 ^ t2; const uint32_t t7 = y13 & y16; const uint32_t t8 = y5 & y1; const uint32_t t9 = t8 ^ t7; const uint32_t t10 = y2 & y7; const uint32_t t11 = t10 ^ t7; const uint32_t t12 = y9 & y11; const uint32_t t13 = y14 & y17; const uint32_t t14 = t13 ^ t12; const uint32_t t15 = y8 & y10; const uint32_t t16 = t15 ^ t12; const uint32_t t17 = t4 ^ y20; const uint32_t t18 = t6 ^ t16; const uint32_t t19 = t9 ^ t14; const uint32_t t20 = t11 ^ t16; const uint32_t t21 = t17 ^ t14; const uint32_t t22 = t18 ^ y19; const uint32_t t23 = t19 ^ y21; const uint32_t t24 = t20 ^ y18; const uint32_t t25 = t21 ^ t22; const uint32_t t26 = t21 & t23; const uint32_t t27 = t24 ^ t26; const uint32_t t28 = t25 & t27; const uint32_t t29 = t28 ^ t22; const uint32_t t30 = t23 ^ t24; const uint32_t t31 = t22 ^ t26; const uint32_t t32 = t31 & t30; const uint32_t t33 = t32 ^ t24; const uint32_t t34 = t23 ^ t33; const uint32_t t35 = t27 ^ t33; const uint32_t t36 = t24 & t35; const uint32_t t37 = t36 ^ t34; const uint32_t t38 = t27 ^ t36; const uint32_t t39 = t29 & t38; const uint32_t t40 = t25 ^ t39; const uint32_t t41 = t40 ^ t37; const uint32_t t42 = t29 ^ t33; const uint32_t t43 = t29 ^ t40; const uint32_t t44 = t33 ^ t37; const uint32_t t45 = t42 ^ t41; const uint32_t z0 = t44 & y15; const uint32_t z1 = t37 & y6; const uint32_t z2 = t33 & U7; const uint32_t z3 = t43 & y16; const uint32_t z4 = t40 & y1; const uint32_t z5 = t29 & y7; const uint32_t z6 = t42 & y11; const uint32_t z7 = t45 & y17; const uint32_t z8 = t41 & y10; const uint32_t z9 = t44 & y12; const uint32_t z10 = t37 & y3; const uint32_t z11 = t33 & y4; const uint32_t z12 = t43 & y13; const uint32_t z13 = t40 & y5; const uint32_t z14 = t29 & y2; const uint32_t z15 = t42 & y9; const uint32_t z16 = t45 & y14; const uint32_t z17 = t41 & y8; const uint32_t tc1 = z15 ^ z16; const uint32_t tc2 = z10 ^ tc1; const uint32_t tc3 = z9 ^ tc2; const uint32_t tc4 = z0 ^ z2; const uint32_t tc5 = z1 ^ z0; const uint32_t tc6 = z3 ^ z4; const uint32_t tc7 = z12 ^ tc4; const uint32_t tc8 = z7 ^ tc6; const uint32_t tc9 = z8 ^ tc7; const uint32_t tc10 = tc8 ^ tc9; const uint32_t tc11 = tc6 ^ tc5; const uint32_t tc12 = z3 ^ z5; const uint32_t tc13 = z13 ^ tc1; const uint32_t tc14 = tc4 ^ tc12; const uint32_t S3 = tc3 ^ tc11; const uint32_t tc16 = z6 ^ tc8; const uint32_t tc17 = z14 ^ tc10; const uint32_t tc18 = ~tc13 ^ tc14; const uint32_t S7 = z12 ^ tc18; const uint32_t tc20 = z15 ^ tc16; const uint32_t tc21 = tc2 ^ z11; const uint32_t S0 = tc3 ^ tc16; const uint32_t S6 = tc10 ^ tc18; const uint32_t S4 = tc14 ^ S3; const uint32_t S1 = ~(S3 ^ tc16); const uint32_t tc26 = tc17 ^ tc20; const uint32_t S2 = ~(tc26 ^ z17); const uint32_t S5 = tc21 ^ tc17; V[0] = S0; V[1] = S1; V[2] = S2; V[3] = S3; V[4] = S4; V[5] = S5; V[6] = S6; V[7] = S7; } /* A circuit for inverse AES Sbox of size 121 and depth 21 from http://www.cs.yale.edu/homes/peralta/CircuitStuff/CMT.html http://www.cs.yale.edu/homes/peralta/CircuitStuff/Sinv.txt */ void AES_INV_SBOX(uint32_t V[8]) { const uint32_t U0 = V[0]; const uint32_t U1 = V[1]; const uint32_t U2 = V[2]; const uint32_t U3 = V[3]; const uint32_t U4 = V[4]; const uint32_t U5 = V[5]; const uint32_t U6 = V[6]; const uint32_t U7 = V[7]; const uint32_t Y0 = U0 ^ U3; const uint32_t Y2 = ~(U1 ^ U3); const uint32_t Y4 = U0 ^ Y2; const uint32_t RTL0 = U6 ^ U7; const uint32_t Y1 = Y2 ^ RTL0; const uint32_t Y7 = ~(U2 ^ Y1); const uint32_t RTL1 = U3 ^ U4; const uint32_t Y6 = ~(U7 ^ RTL1); const uint32_t Y3 = Y1 ^ RTL1; const uint32_t RTL2 = ~(U0 ^ U2); const uint32_t Y5 = U5 ^ RTL2; const uint32_t sa1 = Y0 ^ Y2; const uint32_t sa0 = Y1 ^ Y3; const uint32_t sb1 = Y4 ^ Y6; const uint32_t sb0 = Y5 ^ Y7; const uint32_t ah = Y0 ^ Y1; const uint32_t al = Y2 ^ Y3; const uint32_t aa = sa0 ^ sa1; const uint32_t bh = Y4 ^ Y5; const uint32_t bl = Y6 ^ Y7; const uint32_t bb = sb0 ^ sb1; const uint32_t ab20 = sa0 ^ sb0; const uint32_t ab22 = al ^ bl; const uint32_t ab23 = Y3 ^ Y7; const uint32_t ab21 = sa1 ^ sb1; const uint32_t abcd1 = ah & bh; const uint32_t rr1 = Y0 & Y4; const uint32_t ph11 = ab20 ^ abcd1; const uint32_t t01 = Y1 & Y5; const uint32_t ph01 = t01 ^ abcd1; const uint32_t abcd2 = al & bl; const uint32_t r1 = Y2 & Y6; const uint32_t pl11 = ab22 ^ abcd2; const uint32_t r2 = Y3 & Y7; const uint32_t pl01 = r2 ^ abcd2; const uint32_t r3 = sa0 & sb0; const uint32_t vr1 = aa & bb; const uint32_t pr1 = vr1 ^ r3; const uint32_t wr1 = sa1 & sb1; const uint32_t qr1 = wr1 ^ r3; const uint32_t ab0 = ph11 ^ rr1; const uint32_t ab1 = ph01 ^ ab21; const uint32_t ab2 = pl11 ^ r1; const uint32_t ab3 = pl01 ^ qr1; const uint32_t cp1 = ab0 ^ pr1; const uint32_t cp2 = ab1 ^ qr1; const uint32_t cp3 = ab2 ^ pr1; const uint32_t cp4 = ab3 ^ ab23; const uint32_t tinv1 = cp3 ^ cp4; const uint32_t tinv2 = cp3 & cp1; const uint32_t tinv3 = cp2 ^ tinv2; const uint32_t tinv4 = cp1 ^ cp2; const uint32_t tinv5 = cp4 ^ tinv2; const uint32_t tinv6 = tinv5 & tinv4; const uint32_t tinv7 = tinv3 & tinv1; const uint32_t d2 = cp4 ^ tinv7; const uint32_t d0 = cp2 ^ tinv6; const uint32_t tinv8 = cp1 & cp4; const uint32_t tinv9 = tinv4 & tinv8; const uint32_t tinv10 = tinv4 ^ tinv2; const uint32_t d1 = tinv9 ^ tinv10; const uint32_t tinv11 = cp2 & cp3; const uint32_t tinv12 = tinv1 & tinv11; const uint32_t tinv13 = tinv1 ^ tinv2; const uint32_t d3 = tinv12 ^ tinv13; const uint32_t sd1 = d1 ^ d3; const uint32_t sd0 = d0 ^ d2; const uint32_t dl = d0 ^ d1; const uint32_t dh = d2 ^ d3; const uint32_t dd = sd0 ^ sd1; const uint32_t abcd3 = dh & bh; const uint32_t rr2 = d3 & Y4; const uint32_t t02 = d2 & Y5; const uint32_t abcd4 = dl & bl; const uint32_t r4 = d1 & Y6; const uint32_t r5 = d0 & Y7; const uint32_t r6 = sd0 & sb0; const uint32_t vr2 = dd & bb; const uint32_t wr2 = sd1 & sb1; const uint32_t abcd5 = dh & ah; const uint32_t r7 = d3 & Y0; const uint32_t r8 = d2 & Y1; const uint32_t abcd6 = dl & al; const uint32_t r9 = d1 & Y2; const uint32_t r10 = d0 & Y3; const uint32_t r11 = sd0 & sa0; const uint32_t vr3 = dd & aa; const uint32_t wr3 = sd1 & sa1; const uint32_t ph12 = rr2 ^ abcd3; const uint32_t ph02 = t02 ^ abcd3; const uint32_t pl12 = r4 ^ abcd4; const uint32_t pl02 = r5 ^ abcd4; const uint32_t pr2 = vr2 ^ r6; const uint32_t qr2 = wr2 ^ r6; const uint32_t p0 = ph12 ^ pr2; const uint32_t p1 = ph02 ^ qr2; const uint32_t p2 = pl12 ^ pr2; const uint32_t p3 = pl02 ^ qr2; const uint32_t ph13 = r7 ^ abcd5; const uint32_t ph03 = r8 ^ abcd5; const uint32_t pl13 = r9 ^ abcd6; const uint32_t pl03 = r10 ^ abcd6; const uint32_t pr3 = vr3 ^ r11; const uint32_t qr3 = wr3 ^ r11; const uint32_t p4 = ph13 ^ pr3; const uint32_t S7 = ph03 ^ qr3; const uint32_t p6 = pl13 ^ pr3; const uint32_t p7 = pl03 ^ qr3; const uint32_t S3 = p1 ^ p6; const uint32_t S6 = p2 ^ p6; const uint32_t S0 = p3 ^ p6; const uint32_t X11 = p0 ^ p2; const uint32_t S5 = S0 ^ X11; const uint32_t X13 = p4 ^ p7; const uint32_t X14 = X11 ^ X13; const uint32_t S1 = S3 ^ X14; const uint32_t X16 = p1 ^ S7; const uint32_t S2 = X14 ^ X16; const uint32_t X18 = p0 ^ p4; const uint32_t X19 = S5 ^ X16; const uint32_t S4 = X18 ^ X19; V[0] = S0; V[1] = S1; V[2] = S2; V[3] = S3; V[4] = S4; V[5] = S5; V[6] = S6; V[7] = S7; } inline void bit_transpose(uint32_t B[8]) { swap_bits(B[1], B[0], 0x55555555, 1); swap_bits(B[3], B[2], 0x55555555, 1); swap_bits(B[5], B[4], 0x55555555, 1); swap_bits(B[7], B[6], 0x55555555, 1); swap_bits(B[2], B[0], 0x33333333, 2); swap_bits(B[3], B[1], 0x33333333, 2); swap_bits(B[6], B[4], 0x33333333, 2); swap_bits(B[7], B[5], 0x33333333, 2); swap_bits(B[4], B[0], 0x0F0F0F0F, 4); swap_bits(B[5], B[1], 0x0F0F0F0F, 4); swap_bits(B[6], B[2], 0x0F0F0F0F, 4); swap_bits(B[7], B[3], 0x0F0F0F0F, 4); } inline void ks_expand(uint32_t B[8], const uint32_t K[], size_t r) { /* This is bit_transpose of K[r..r+4] || K[r..r+4], we can save some computation due to knowing the first and second halves are the same data. */ for(size_t i = 0; i != 4; ++i) B[i] = K[r + i]; swap_bits(B[1], B[0], 0x55555555, 1); swap_bits(B[3], B[2], 0x55555555, 1); swap_bits(B[2], B[0], 0x33333333, 2); swap_bits(B[3], B[1], 0x33333333, 2); B[4] = B[0]; B[5] = B[1]; B[6] = B[2]; B[7] = B[3]; swap_bits(B[4], B[0], 0x0F0F0F0F, 4); swap_bits(B[5], B[1], 0x0F0F0F0F, 4); swap_bits(B[6], B[2], 0x0F0F0F0F, 4); swap_bits(B[7], B[3], 0x0F0F0F0F, 4); } inline void shift_rows(uint32_t B[8]) { // 3 0 1 2 7 4 5 6 10 11 8 9 14 15 12 13 17 18 19 16 21 22 23 20 24 25 26 27 28 29 30 31 #if defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) for(size_t i = 0; i != 8; i += 2) { uint64_t x = (static_cast(B[i]) << 32) | B[i+1]; x = bit_permute_step(x, 0x0022331100223311, 2); x = bit_permute_step(x, 0x0055005500550055, 1); B[i] = static_cast(x >> 32); B[i+1] = static_cast(x); } #else for(size_t i = 0; i != 8; ++i) { uint32_t x = B[i]; x = bit_permute_step(x, 0x00223311, 2); x = bit_permute_step(x, 0x00550055, 1); B[i] = x; } #endif } inline void inv_shift_rows(uint32_t B[8]) { // Inverse of shift_rows, just inverting the steps #if defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) for(size_t i = 0; i != 8; i += 2) { uint64_t x = (static_cast(B[i]) << 32) | B[i+1]; x = bit_permute_step(x, 0x0055005500550055, 1); x = bit_permute_step(x, 0x0022331100223311, 2); B[i] = static_cast(x >> 32); B[i+1] = static_cast(x); } #else for(size_t i = 0; i != 8; ++i) { uint32_t x = B[i]; x = bit_permute_step(x, 0x00550055, 1); x = bit_permute_step(x, 0x00223311, 2); B[i] = x; } #endif } inline void mix_columns(uint32_t B[8]) { // carry high bits in B[0] to positions in 0x1b == 0b11011 const uint32_t X2[8] = { B[1], B[2], B[3], B[4] ^ B[0], B[5] ^ B[0], B[6], B[7] ^ B[0], B[0], }; for(size_t i = 0; i != 8; i++) { const uint32_t X3 = B[i] ^ X2[i]; B[i] = X2[i] ^ rotr<8>(B[i]) ^ rotr<16>(B[i]) ^ rotr<24>(X3); } } void inv_mix_columns(uint32_t B[8]) { /* OpenSSL's bsaes implementation credits Jussi Kivilinna with the lovely matrix decomposition | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 | | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 | | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 | | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 | Notice the first component is simply the MixColumns matrix. So we can multiply first by (05,00,04,00) then perform MixColumns to get the equivalent of InvMixColumn. */ const uint32_t X4[8] = { B[2], B[3], B[4] ^ B[0], B[5] ^ B[0] ^ B[1], B[6] ^ B[1], B[7] ^ B[0], B[0] ^ B[1], B[1], }; for(size_t i = 0; i != 8; i++) { const uint32_t X5 = X4[i] ^ B[i]; B[i] = X5 ^ rotr<16>(X4[i]); } mix_columns(B); } /* * AES Encryption */ void aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks, const secure_vector& EK) { BOTAN_ASSERT(EK.size() == 44 || EK.size() == 52 || EK.size() == 60, "Key was set"); const size_t rounds = (EK.size() - 4) / 4; uint32_t KS[13*8] = { 0 }; // actual maximum is (rounds - 1) * 8 for(size_t i = 0; i < rounds - 1; i += 1) { ks_expand(&KS[8*i], EK.data(), 4*i + 4); } const size_t BLOCK_SIZE = 16; const size_t BITSLICED_BLOCKS = 8*sizeof(uint32_t) / BLOCK_SIZE; while(blocks > 0) { const size_t this_loop = std::min(blocks, BITSLICED_BLOCKS); uint32_t B[8] = { 0 }; load_be(B, in, this_loop*4); for(size_t i = 0; i != 8; ++i) B[i] ^= EK[i % 4]; bit_transpose(B); for(size_t r = 0; r != rounds - 1; ++r) { AES_SBOX(B); shift_rows(B); mix_columns(B); for(size_t i = 0; i != 8; ++i) B[i] ^= KS[8*r + i]; } // Final round: AES_SBOX(B); shift_rows(B); bit_transpose(B); for(size_t i = 0; i != 8; ++i) B[i] ^= EK[4*rounds + i % 4]; copy_out_be(out, this_loop*4*sizeof(uint32_t), B); in += this_loop * BLOCK_SIZE; out += this_loop * BLOCK_SIZE; blocks -= this_loop; } } /* * AES Decryption */ void aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks, const secure_vector& DK) { BOTAN_ASSERT(DK.size() == 44 || DK.size() == 52 || DK.size() == 60, "Key was set"); const size_t rounds = (DK.size() - 4) / 4; uint32_t KS[13*8] = { 0 }; // actual maximum is (rounds - 1) * 8 for(size_t i = 0; i < rounds - 1; i += 1) { ks_expand(&KS[8*i], DK.data(), 4*i + 4); } const size_t BLOCK_SIZE = 16; const size_t BITSLICED_BLOCKS = 8*sizeof(uint32_t) / BLOCK_SIZE; while(blocks > 0) { const size_t this_loop = std::min(blocks, BITSLICED_BLOCKS); uint32_t B[8] = { 0 }; load_be(B, in, this_loop*4); for(size_t i = 0; i != 8; ++i) B[i] ^= DK[i % 4]; bit_transpose(B); for(size_t r = 0; r != rounds - 1; ++r) { AES_INV_SBOX(B); inv_shift_rows(B); inv_mix_columns(B); for(size_t i = 0; i != 8; ++i) B[i] ^= KS[8*r + i]; } // Final round: AES_INV_SBOX(B); inv_shift_rows(B); bit_transpose(B); for(size_t i = 0; i != 8; ++i) B[i] ^= DK[4*rounds + i % 4]; copy_out_be(out, this_loop*4*sizeof(uint32_t), B); in += this_loop * BLOCK_SIZE; out += this_loop * BLOCK_SIZE; blocks -= this_loop; } } inline uint32_t xtime32(uint32_t s) { const uint32_t lo_bit = 0x01010101; const uint32_t mask = 0x7F7F7F7F; const uint32_t poly = 0x1B; return ((s & mask) << 1) ^ (((s >> 7) & lo_bit) * poly); } inline uint32_t InvMixColumn(uint32_t s1) { const uint32_t s2 = xtime32(s1); const uint32_t s4 = xtime32(s2); const uint32_t s8 = xtime32(s4); const uint32_t s9 = s8 ^ s1; const uint32_t s11 = s9 ^ s2; const uint32_t s13 = s9 ^ s4; const uint32_t s14 = s8 ^ s4 ^ s2; return s14 ^ rotr<8>(s9) ^ rotr<16>(s13) ^ rotr<24>(s11); } void InvMixColumn_x4(uint32_t x[4]) { x[0] = InvMixColumn(x[0]); x[1] = InvMixColumn(x[1]); x[2] = InvMixColumn(x[2]); x[3] = InvMixColumn(x[3]); } uint32_t SE_word(uint32_t x) { uint32_t I[8] = { 0 }; for(size_t i = 0; i != 8; ++i) I[i] = (x >> (7-i)) & 0x01010101; AES_SBOX(I); x = 0; for(size_t i = 0; i != 8; ++i) x |= ((I[i] & 0x01010101) << (7-i)); return x; } void aes_key_schedule(const uint8_t key[], size_t length, secure_vector& EK, secure_vector& DK, bool bswap_keys = false) { static const uint32_t RC[10] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; const size_t X = length / 4; // Can't happen, but make static analyzers happy BOTAN_ASSERT_NOMSG(X == 4 || X == 6 || X == 8); const size_t rounds = (length / 4) + 6; // Help the optimizer BOTAN_ASSERT_NOMSG(rounds == 10 || rounds == 12 || rounds == 14); CT::poison(key, length); EK.resize(length + 28); DK.resize(length + 28); for(size_t i = 0; i != X; ++i) EK[i] = load_be(key, i); for(size_t i = X; i < 4*(rounds+1); i += X) { EK[i] = EK[i-X] ^ RC[(i-X)/X] ^ rotl<8>(SE_word(EK[i-1])); for(size_t j = 1; j != X && (i+j) < EK.size(); ++j) { EK[i+j] = EK[i+j-X]; if(X == 8 && j == 4) EK[i+j] ^= SE_word(EK[i+j-1]); else EK[i+j] ^= EK[i+j-1]; } } for(size_t i = 0; i != 4*(rounds+1); i += 4) { DK[i ] = EK[4*rounds - i ]; DK[i+1] = EK[4*rounds - i+1]; DK[i+2] = EK[4*rounds - i+2]; DK[i+3] = EK[4*rounds - i+3]; } for(size_t i = 4; i != 4*rounds; i += 4) { InvMixColumn_x4(&DK[i]); } if(bswap_keys) { // HW AES on little endian needs the subkeys to be byte reversed for(size_t i = 0; i != EK.size(); ++i) EK[i] = reverse_bytes(EK[i]); for(size_t i = 0; i != DK.size(); ++i) DK[i] = reverse_bytes(DK[i]); } CT::unpoison(EK.data(), EK.size()); CT::unpoison(DK.data(), DK.size()); CT::unpoison(key, length); } size_t aes_parallelism() { #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return 4; // pipelined } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return 2; // pipelined } #endif // bitsliced: return 2; } const char* aes_provider() { #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return "cpu"; } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return "vperm"; } #endif return "base"; } } std::string AES_128::provider() const { return aes_provider(); } std::string AES_192::provider() const { return aes_provider(); } std::string AES_256::provider() const { return aes_provider(); } size_t AES_128::parallelism() const { return aes_parallelism(); } size_t AES_192::parallelism() const { return aes_parallelism(); } size_t AES_256::parallelism() const { return aes_parallelism(); } void AES_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return hw_aes_encrypt_n(in, out, blocks); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_encrypt_n(in, out, blocks); } #endif aes_encrypt_n(in, out, blocks, m_EK); } void AES_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DK.empty() == false); #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return hw_aes_decrypt_n(in, out, blocks); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_decrypt_n(in, out, blocks); } #endif aes_decrypt_n(in, out, blocks, m_DK); } void AES_128::key_schedule(const uint8_t key[], size_t length) { #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { return aesni_key_schedule(key, length); } #endif #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return aes_key_schedule(key, length, m_EK, m_DK, CPUID::is_little_endian()); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_key_schedule(key, length); } #endif aes_key_schedule(key, length, m_EK, m_DK); } void AES_128::clear() { zap(m_EK); zap(m_DK); } void AES_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return hw_aes_encrypt_n(in, out, blocks); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_encrypt_n(in, out, blocks); } #endif aes_encrypt_n(in, out, blocks, m_EK); } void AES_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DK.empty() == false); #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return hw_aes_decrypt_n(in, out, blocks); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_decrypt_n(in, out, blocks); } #endif aes_decrypt_n(in, out, blocks, m_DK); } void AES_192::key_schedule(const uint8_t key[], size_t length) { #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { return aesni_key_schedule(key, length); } #endif #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return aes_key_schedule(key, length, m_EK, m_DK, CPUID::is_little_endian()); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_key_schedule(key, length); } #endif aes_key_schedule(key, length, m_EK, m_DK); } void AES_192::clear() { zap(m_EK); zap(m_DK); } void AES_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return hw_aes_encrypt_n(in, out, blocks); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_encrypt_n(in, out, blocks); } #endif aes_encrypt_n(in, out, blocks, m_EK); } void AES_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DK.empty() == false); #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return hw_aes_decrypt_n(in, out, blocks); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_decrypt_n(in, out, blocks); } #endif aes_decrypt_n(in, out, blocks, m_DK); } void AES_256::key_schedule(const uint8_t key[], size_t length) { #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { return aesni_key_schedule(key, length); } #endif #if defined(BOTAN_HAS_HW_AES_SUPPORT) if(CPUID::has_hw_aes()) { return aes_key_schedule(key, length, m_EK, m_DK, CPUID::is_little_endian()); } #endif #if defined(BOTAN_HAS_AES_VPERM) if(CPUID::has_vperm()) { return vperm_key_schedule(key, length); } #endif aes_key_schedule(key, length, m_EK, m_DK); } void AES_256::clear() { zap(m_EK); zap(m_DK); } } /* * AES using AES-NI instructions * (C) 2009,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace { BOTAN_FUNC_ISA("ssse3") __m128i aes_128_key_expansion(__m128i key, __m128i key_with_rcon) { key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(3,3,3,3)); key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); return _mm_xor_si128(key, key_with_rcon); } BOTAN_FUNC_ISA("ssse3") void aes_192_key_expansion(__m128i* K1, __m128i* K2, __m128i key2_with_rcon, uint32_t out[], bool last) { __m128i key1 = *K1; __m128i key2 = *K2; key2_with_rcon = _mm_shuffle_epi32(key2_with_rcon, _MM_SHUFFLE(1,1,1,1)); key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); key1 = _mm_xor_si128(key1, key2_with_rcon); *K1 = key1; _mm_storeu_si128(reinterpret_cast<__m128i*>(out), key1); if(last) return; key2 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4)); key2 = _mm_xor_si128(key2, _mm_shuffle_epi32(key1, _MM_SHUFFLE(3,3,3,3))); *K2 = key2; out[4] = _mm_cvtsi128_si32(key2); out[5] = _mm_cvtsi128_si32(_mm_srli_si128(key2, 4)); } /* * The second half of the AES-256 key expansion (other half same as AES-128) */ BOTAN_FUNC_ISA("ssse3,aes") __m128i aes_256_key_expansion(__m128i key, __m128i key2) { __m128i key_with_rcon = _mm_aeskeygenassist_si128(key2, 0x00); key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(2,2,2,2)); key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); return _mm_xor_si128(key, key_with_rcon); } } #define AES_ENC_4_ROUNDS(K) \ do \ { \ B0 = _mm_aesenc_si128(B0, K); \ B1 = _mm_aesenc_si128(B1, K); \ B2 = _mm_aesenc_si128(B2, K); \ B3 = _mm_aesenc_si128(B3, K); \ } while(0) #define AES_ENC_4_LAST_ROUNDS(K) \ do \ { \ B0 = _mm_aesenclast_si128(B0, K); \ B1 = _mm_aesenclast_si128(B1, K); \ B2 = _mm_aesenclast_si128(B2, K); \ B3 = _mm_aesenclast_si128(B3, K); \ } while(0) #define AES_DEC_4_ROUNDS(K) \ do \ { \ B0 = _mm_aesdec_si128(B0, K); \ B1 = _mm_aesdec_si128(B1, K); \ B2 = _mm_aesdec_si128(B2, K); \ B3 = _mm_aesdec_si128(B3, K); \ } while(0) #define AES_DEC_4_LAST_ROUNDS(K) \ do \ { \ B0 = _mm_aesdeclast_si128(B0, K); \ B1 = _mm_aesdeclast_si128(B1, K); \ B2 = _mm_aesdeclast_si128(B2, K); \ B3 = _mm_aesdeclast_si128(B3, K); \ } while(0) /* * AES-128 Encryption */ BOTAN_FUNC_ISA("ssse3,aes") void AES_128::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); const __m128i* key_mm = reinterpret_cast(m_EK.data()); const __m128i K0 = _mm_loadu_si128(key_mm); const __m128i K1 = _mm_loadu_si128(key_mm + 1); const __m128i K2 = _mm_loadu_si128(key_mm + 2); const __m128i K3 = _mm_loadu_si128(key_mm + 3); const __m128i K4 = _mm_loadu_si128(key_mm + 4); const __m128i K5 = _mm_loadu_si128(key_mm + 5); const __m128i K6 = _mm_loadu_si128(key_mm + 6); const __m128i K7 = _mm_loadu_si128(key_mm + 7); const __m128i K8 = _mm_loadu_si128(key_mm + 8); const __m128i K9 = _mm_loadu_si128(key_mm + 9); const __m128i K10 = _mm_loadu_si128(key_mm + 10); while(blocks >= 4) { __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); B0 = _mm_xor_si128(B0, K0); B1 = _mm_xor_si128(B1, K0); B2 = _mm_xor_si128(B2, K0); B3 = _mm_xor_si128(B3, K0); AES_ENC_4_ROUNDS(K1); AES_ENC_4_ROUNDS(K2); AES_ENC_4_ROUNDS(K3); AES_ENC_4_ROUNDS(K4); AES_ENC_4_ROUNDS(K5); AES_ENC_4_ROUNDS(K6); AES_ENC_4_ROUNDS(K7); AES_ENC_4_ROUNDS(K8); AES_ENC_4_ROUNDS(K9); AES_ENC_4_LAST_ROUNDS(K10); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B1); _mm_storeu_si128(out_mm + 2, B2); _mm_storeu_si128(out_mm + 3, B3); blocks -= 4; in_mm += 4; out_mm += 4; } for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); B = _mm_xor_si128(B, K0); B = _mm_aesenc_si128(B, K1); B = _mm_aesenc_si128(B, K2); B = _mm_aesenc_si128(B, K3); B = _mm_aesenc_si128(B, K4); B = _mm_aesenc_si128(B, K5); B = _mm_aesenc_si128(B, K6); B = _mm_aesenc_si128(B, K7); B = _mm_aesenc_si128(B, K8); B = _mm_aesenc_si128(B, K9); B = _mm_aesenclast_si128(B, K10); _mm_storeu_si128(out_mm + i, B); } } /* * AES-128 Decryption */ BOTAN_FUNC_ISA("ssse3,aes") void AES_128::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); const __m128i* key_mm = reinterpret_cast(m_DK.data()); const __m128i K0 = _mm_loadu_si128(key_mm); const __m128i K1 = _mm_loadu_si128(key_mm + 1); const __m128i K2 = _mm_loadu_si128(key_mm + 2); const __m128i K3 = _mm_loadu_si128(key_mm + 3); const __m128i K4 = _mm_loadu_si128(key_mm + 4); const __m128i K5 = _mm_loadu_si128(key_mm + 5); const __m128i K6 = _mm_loadu_si128(key_mm + 6); const __m128i K7 = _mm_loadu_si128(key_mm + 7); const __m128i K8 = _mm_loadu_si128(key_mm + 8); const __m128i K9 = _mm_loadu_si128(key_mm + 9); const __m128i K10 = _mm_loadu_si128(key_mm + 10); while(blocks >= 4) { __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); B0 = _mm_xor_si128(B0, K0); B1 = _mm_xor_si128(B1, K0); B2 = _mm_xor_si128(B2, K0); B3 = _mm_xor_si128(B3, K0); AES_DEC_4_ROUNDS(K1); AES_DEC_4_ROUNDS(K2); AES_DEC_4_ROUNDS(K3); AES_DEC_4_ROUNDS(K4); AES_DEC_4_ROUNDS(K5); AES_DEC_4_ROUNDS(K6); AES_DEC_4_ROUNDS(K7); AES_DEC_4_ROUNDS(K8); AES_DEC_4_ROUNDS(K9); AES_DEC_4_LAST_ROUNDS(K10); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B1); _mm_storeu_si128(out_mm + 2, B2); _mm_storeu_si128(out_mm + 3, B3); blocks -= 4; in_mm += 4; out_mm += 4; } for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); B = _mm_xor_si128(B, K0); B = _mm_aesdec_si128(B, K1); B = _mm_aesdec_si128(B, K2); B = _mm_aesdec_si128(B, K3); B = _mm_aesdec_si128(B, K4); B = _mm_aesdec_si128(B, K5); B = _mm_aesdec_si128(B, K6); B = _mm_aesdec_si128(B, K7); B = _mm_aesdec_si128(B, K8); B = _mm_aesdec_si128(B, K9); B = _mm_aesdeclast_si128(B, K10); _mm_storeu_si128(out_mm + i, B); } } /* * AES-128 Key Schedule */ BOTAN_FUNC_ISA("ssse3,aes") void AES_128::aesni_key_schedule(const uint8_t key[], size_t) { m_EK.resize(44); m_DK.resize(44); #define AES_128_key_exp(K, RCON) \ aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON)) const __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); const __m128i K1 = AES_128_key_exp(K0, 0x01); const __m128i K2 = AES_128_key_exp(K1, 0x02); const __m128i K3 = AES_128_key_exp(K2, 0x04); const __m128i K4 = AES_128_key_exp(K3, 0x08); const __m128i K5 = AES_128_key_exp(K4, 0x10); const __m128i K6 = AES_128_key_exp(K5, 0x20); const __m128i K7 = AES_128_key_exp(K6, 0x40); const __m128i K8 = AES_128_key_exp(K7, 0x80); const __m128i K9 = AES_128_key_exp(K8, 0x1B); const __m128i K10 = AES_128_key_exp(K9, 0x36); __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); _mm_storeu_si128(EK_mm , K0); _mm_storeu_si128(EK_mm + 1, K1); _mm_storeu_si128(EK_mm + 2, K2); _mm_storeu_si128(EK_mm + 3, K3); _mm_storeu_si128(EK_mm + 4, K4); _mm_storeu_si128(EK_mm + 5, K5); _mm_storeu_si128(EK_mm + 6, K6); _mm_storeu_si128(EK_mm + 7, K7); _mm_storeu_si128(EK_mm + 8, K8); _mm_storeu_si128(EK_mm + 9, K9); _mm_storeu_si128(EK_mm + 10, K10); // Now generate decryption keys __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); _mm_storeu_si128(DK_mm , K10); _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K9)); _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K8)); _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K7)); _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K6)); _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K5)); _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K4)); _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K3)); _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K2)); _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K1)); _mm_storeu_si128(DK_mm + 10, K0); } /* * AES-192 Encryption */ BOTAN_FUNC_ISA("ssse3,aes") void AES_192::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); const __m128i* key_mm = reinterpret_cast(m_EK.data()); const __m128i K0 = _mm_loadu_si128(key_mm); const __m128i K1 = _mm_loadu_si128(key_mm + 1); const __m128i K2 = _mm_loadu_si128(key_mm + 2); const __m128i K3 = _mm_loadu_si128(key_mm + 3); const __m128i K4 = _mm_loadu_si128(key_mm + 4); const __m128i K5 = _mm_loadu_si128(key_mm + 5); const __m128i K6 = _mm_loadu_si128(key_mm + 6); const __m128i K7 = _mm_loadu_si128(key_mm + 7); const __m128i K8 = _mm_loadu_si128(key_mm + 8); const __m128i K9 = _mm_loadu_si128(key_mm + 9); const __m128i K10 = _mm_loadu_si128(key_mm + 10); const __m128i K11 = _mm_loadu_si128(key_mm + 11); const __m128i K12 = _mm_loadu_si128(key_mm + 12); while(blocks >= 4) { __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); B0 = _mm_xor_si128(B0, K0); B1 = _mm_xor_si128(B1, K0); B2 = _mm_xor_si128(B2, K0); B3 = _mm_xor_si128(B3, K0); AES_ENC_4_ROUNDS(K1); AES_ENC_4_ROUNDS(K2); AES_ENC_4_ROUNDS(K3); AES_ENC_4_ROUNDS(K4); AES_ENC_4_ROUNDS(K5); AES_ENC_4_ROUNDS(K6); AES_ENC_4_ROUNDS(K7); AES_ENC_4_ROUNDS(K8); AES_ENC_4_ROUNDS(K9); AES_ENC_4_ROUNDS(K10); AES_ENC_4_ROUNDS(K11); AES_ENC_4_LAST_ROUNDS(K12); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B1); _mm_storeu_si128(out_mm + 2, B2); _mm_storeu_si128(out_mm + 3, B3); blocks -= 4; in_mm += 4; out_mm += 4; } for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); B = _mm_xor_si128(B, K0); B = _mm_aesenc_si128(B, K1); B = _mm_aesenc_si128(B, K2); B = _mm_aesenc_si128(B, K3); B = _mm_aesenc_si128(B, K4); B = _mm_aesenc_si128(B, K5); B = _mm_aesenc_si128(B, K6); B = _mm_aesenc_si128(B, K7); B = _mm_aesenc_si128(B, K8); B = _mm_aesenc_si128(B, K9); B = _mm_aesenc_si128(B, K10); B = _mm_aesenc_si128(B, K11); B = _mm_aesenclast_si128(B, K12); _mm_storeu_si128(out_mm + i, B); } } /* * AES-192 Decryption */ BOTAN_FUNC_ISA("ssse3,aes") void AES_192::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); const __m128i* key_mm = reinterpret_cast(m_DK.data()); const __m128i K0 = _mm_loadu_si128(key_mm); const __m128i K1 = _mm_loadu_si128(key_mm + 1); const __m128i K2 = _mm_loadu_si128(key_mm + 2); const __m128i K3 = _mm_loadu_si128(key_mm + 3); const __m128i K4 = _mm_loadu_si128(key_mm + 4); const __m128i K5 = _mm_loadu_si128(key_mm + 5); const __m128i K6 = _mm_loadu_si128(key_mm + 6); const __m128i K7 = _mm_loadu_si128(key_mm + 7); const __m128i K8 = _mm_loadu_si128(key_mm + 8); const __m128i K9 = _mm_loadu_si128(key_mm + 9); const __m128i K10 = _mm_loadu_si128(key_mm + 10); const __m128i K11 = _mm_loadu_si128(key_mm + 11); const __m128i K12 = _mm_loadu_si128(key_mm + 12); while(blocks >= 4) { __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); B0 = _mm_xor_si128(B0, K0); B1 = _mm_xor_si128(B1, K0); B2 = _mm_xor_si128(B2, K0); B3 = _mm_xor_si128(B3, K0); AES_DEC_4_ROUNDS(K1); AES_DEC_4_ROUNDS(K2); AES_DEC_4_ROUNDS(K3); AES_DEC_4_ROUNDS(K4); AES_DEC_4_ROUNDS(K5); AES_DEC_4_ROUNDS(K6); AES_DEC_4_ROUNDS(K7); AES_DEC_4_ROUNDS(K8); AES_DEC_4_ROUNDS(K9); AES_DEC_4_ROUNDS(K10); AES_DEC_4_ROUNDS(K11); AES_DEC_4_LAST_ROUNDS(K12); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B1); _mm_storeu_si128(out_mm + 2, B2); _mm_storeu_si128(out_mm + 3, B3); blocks -= 4; in_mm += 4; out_mm += 4; } for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); B = _mm_xor_si128(B, K0); B = _mm_aesdec_si128(B, K1); B = _mm_aesdec_si128(B, K2); B = _mm_aesdec_si128(B, K3); B = _mm_aesdec_si128(B, K4); B = _mm_aesdec_si128(B, K5); B = _mm_aesdec_si128(B, K6); B = _mm_aesdec_si128(B, K7); B = _mm_aesdec_si128(B, K8); B = _mm_aesdec_si128(B, K9); B = _mm_aesdec_si128(B, K10); B = _mm_aesdec_si128(B, K11); B = _mm_aesdeclast_si128(B, K12); _mm_storeu_si128(out_mm + i, B); } } /* * AES-192 Key Schedule */ BOTAN_FUNC_ISA("ssse3,aes") void AES_192::aesni_key_schedule(const uint8_t key[], size_t) { m_EK.resize(52); m_DK.resize(52); __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); __m128i K1 = _mm_loadu_si128(reinterpret_cast(key + 8)); K1 = _mm_srli_si128(K1, 8); load_le(m_EK.data(), key, 6); #define AES_192_key_exp(RCON, EK_OFF) \ aes_192_key_expansion(&K0, &K1, \ _mm_aeskeygenassist_si128(K1, RCON), \ &m_EK[EK_OFF], EK_OFF == 48) AES_192_key_exp(0x01, 6); AES_192_key_exp(0x02, 12); AES_192_key_exp(0x04, 18); AES_192_key_exp(0x08, 24); AES_192_key_exp(0x10, 30); AES_192_key_exp(0x20, 36); AES_192_key_exp(0x40, 42); AES_192_key_exp(0x80, 48); #undef AES_192_key_exp // Now generate decryption keys const __m128i* EK_mm = reinterpret_cast(m_EK.data()); __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); _mm_storeu_si128(DK_mm , _mm_loadu_si128(EK_mm + 12)); _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 11))); _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 10))); _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 9))); _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 8))); _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 7))); _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 6))); _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 5))); _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 4))); _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 3))); _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 2))); _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 1))); _mm_storeu_si128(DK_mm + 12, _mm_loadu_si128(EK_mm + 0)); } /* * AES-256 Encryption */ BOTAN_FUNC_ISA("ssse3,aes") void AES_256::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); const __m128i* key_mm = reinterpret_cast(m_EK.data()); const __m128i K0 = _mm_loadu_si128(key_mm); const __m128i K1 = _mm_loadu_si128(key_mm + 1); const __m128i K2 = _mm_loadu_si128(key_mm + 2); const __m128i K3 = _mm_loadu_si128(key_mm + 3); const __m128i K4 = _mm_loadu_si128(key_mm + 4); const __m128i K5 = _mm_loadu_si128(key_mm + 5); const __m128i K6 = _mm_loadu_si128(key_mm + 6); const __m128i K7 = _mm_loadu_si128(key_mm + 7); const __m128i K8 = _mm_loadu_si128(key_mm + 8); const __m128i K9 = _mm_loadu_si128(key_mm + 9); const __m128i K10 = _mm_loadu_si128(key_mm + 10); const __m128i K11 = _mm_loadu_si128(key_mm + 11); const __m128i K12 = _mm_loadu_si128(key_mm + 12); const __m128i K13 = _mm_loadu_si128(key_mm + 13); const __m128i K14 = _mm_loadu_si128(key_mm + 14); while(blocks >= 4) { __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); B0 = _mm_xor_si128(B0, K0); B1 = _mm_xor_si128(B1, K0); B2 = _mm_xor_si128(B2, K0); B3 = _mm_xor_si128(B3, K0); AES_ENC_4_ROUNDS(K1); AES_ENC_4_ROUNDS(K2); AES_ENC_4_ROUNDS(K3); AES_ENC_4_ROUNDS(K4); AES_ENC_4_ROUNDS(K5); AES_ENC_4_ROUNDS(K6); AES_ENC_4_ROUNDS(K7); AES_ENC_4_ROUNDS(K8); AES_ENC_4_ROUNDS(K9); AES_ENC_4_ROUNDS(K10); AES_ENC_4_ROUNDS(K11); AES_ENC_4_ROUNDS(K12); AES_ENC_4_ROUNDS(K13); AES_ENC_4_LAST_ROUNDS(K14); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B1); _mm_storeu_si128(out_mm + 2, B2); _mm_storeu_si128(out_mm + 3, B3); blocks -= 4; in_mm += 4; out_mm += 4; } for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); B = _mm_xor_si128(B, K0); B = _mm_aesenc_si128(B, K1); B = _mm_aesenc_si128(B, K2); B = _mm_aesenc_si128(B, K3); B = _mm_aesenc_si128(B, K4); B = _mm_aesenc_si128(B, K5); B = _mm_aesenc_si128(B, K6); B = _mm_aesenc_si128(B, K7); B = _mm_aesenc_si128(B, K8); B = _mm_aesenc_si128(B, K9); B = _mm_aesenc_si128(B, K10); B = _mm_aesenc_si128(B, K11); B = _mm_aesenc_si128(B, K12); B = _mm_aesenc_si128(B, K13); B = _mm_aesenclast_si128(B, K14); _mm_storeu_si128(out_mm + i, B); } } /* * AES-256 Decryption */ BOTAN_FUNC_ISA("ssse3,aes") void AES_256::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); const __m128i* key_mm = reinterpret_cast(m_DK.data()); const __m128i K0 = _mm_loadu_si128(key_mm); const __m128i K1 = _mm_loadu_si128(key_mm + 1); const __m128i K2 = _mm_loadu_si128(key_mm + 2); const __m128i K3 = _mm_loadu_si128(key_mm + 3); const __m128i K4 = _mm_loadu_si128(key_mm + 4); const __m128i K5 = _mm_loadu_si128(key_mm + 5); const __m128i K6 = _mm_loadu_si128(key_mm + 6); const __m128i K7 = _mm_loadu_si128(key_mm + 7); const __m128i K8 = _mm_loadu_si128(key_mm + 8); const __m128i K9 = _mm_loadu_si128(key_mm + 9); const __m128i K10 = _mm_loadu_si128(key_mm + 10); const __m128i K11 = _mm_loadu_si128(key_mm + 11); const __m128i K12 = _mm_loadu_si128(key_mm + 12); const __m128i K13 = _mm_loadu_si128(key_mm + 13); const __m128i K14 = _mm_loadu_si128(key_mm + 14); while(blocks >= 4) { __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); B0 = _mm_xor_si128(B0, K0); B1 = _mm_xor_si128(B1, K0); B2 = _mm_xor_si128(B2, K0); B3 = _mm_xor_si128(B3, K0); AES_DEC_4_ROUNDS(K1); AES_DEC_4_ROUNDS(K2); AES_DEC_4_ROUNDS(K3); AES_DEC_4_ROUNDS(K4); AES_DEC_4_ROUNDS(K5); AES_DEC_4_ROUNDS(K6); AES_DEC_4_ROUNDS(K7); AES_DEC_4_ROUNDS(K8); AES_DEC_4_ROUNDS(K9); AES_DEC_4_ROUNDS(K10); AES_DEC_4_ROUNDS(K11); AES_DEC_4_ROUNDS(K12); AES_DEC_4_ROUNDS(K13); AES_DEC_4_LAST_ROUNDS(K14); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B1); _mm_storeu_si128(out_mm + 2, B2); _mm_storeu_si128(out_mm + 3, B3); blocks -= 4; in_mm += 4; out_mm += 4; } for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); B = _mm_xor_si128(B, K0); B = _mm_aesdec_si128(B, K1); B = _mm_aesdec_si128(B, K2); B = _mm_aesdec_si128(B, K3); B = _mm_aesdec_si128(B, K4); B = _mm_aesdec_si128(B, K5); B = _mm_aesdec_si128(B, K6); B = _mm_aesdec_si128(B, K7); B = _mm_aesdec_si128(B, K8); B = _mm_aesdec_si128(B, K9); B = _mm_aesdec_si128(B, K10); B = _mm_aesdec_si128(B, K11); B = _mm_aesdec_si128(B, K12); B = _mm_aesdec_si128(B, K13); B = _mm_aesdeclast_si128(B, K14); _mm_storeu_si128(out_mm + i, B); } } /* * AES-256 Key Schedule */ BOTAN_FUNC_ISA("ssse3,aes") void AES_256::aesni_key_schedule(const uint8_t key[], size_t) { m_EK.resize(60); m_DK.resize(60); const __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); const __m128i K1 = _mm_loadu_si128(reinterpret_cast(key + 16)); const __m128i K2 = aes_128_key_expansion(K0, _mm_aeskeygenassist_si128(K1, 0x01)); const __m128i K3 = aes_256_key_expansion(K1, K2); const __m128i K4 = aes_128_key_expansion(K2, _mm_aeskeygenassist_si128(K3, 0x02)); const __m128i K5 = aes_256_key_expansion(K3, K4); const __m128i K6 = aes_128_key_expansion(K4, _mm_aeskeygenassist_si128(K5, 0x04)); const __m128i K7 = aes_256_key_expansion(K5, K6); const __m128i K8 = aes_128_key_expansion(K6, _mm_aeskeygenassist_si128(K7, 0x08)); const __m128i K9 = aes_256_key_expansion(K7, K8); const __m128i K10 = aes_128_key_expansion(K8, _mm_aeskeygenassist_si128(K9, 0x10)); const __m128i K11 = aes_256_key_expansion(K9, K10); const __m128i K12 = aes_128_key_expansion(K10, _mm_aeskeygenassist_si128(K11, 0x20)); const __m128i K13 = aes_256_key_expansion(K11, K12); const __m128i K14 = aes_128_key_expansion(K12, _mm_aeskeygenassist_si128(K13, 0x40)); __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); _mm_storeu_si128(EK_mm , K0); _mm_storeu_si128(EK_mm + 1, K1); _mm_storeu_si128(EK_mm + 2, K2); _mm_storeu_si128(EK_mm + 3, K3); _mm_storeu_si128(EK_mm + 4, K4); _mm_storeu_si128(EK_mm + 5, K5); _mm_storeu_si128(EK_mm + 6, K6); _mm_storeu_si128(EK_mm + 7, K7); _mm_storeu_si128(EK_mm + 8, K8); _mm_storeu_si128(EK_mm + 9, K9); _mm_storeu_si128(EK_mm + 10, K10); _mm_storeu_si128(EK_mm + 11, K11); _mm_storeu_si128(EK_mm + 12, K12); _mm_storeu_si128(EK_mm + 13, K13); _mm_storeu_si128(EK_mm + 14, K14); // Now generate decryption keys __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); _mm_storeu_si128(DK_mm , K14); _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K13)); _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K12)); _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K11)); _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K10)); _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K9)); _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K8)); _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K7)); _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K6)); _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K5)); _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(K4)); _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(K3)); _mm_storeu_si128(DK_mm + 12, _mm_aesimc_si128(K2)); _mm_storeu_si128(DK_mm + 13, _mm_aesimc_si128(K1)); _mm_storeu_si128(DK_mm + 14, K0); } #undef AES_ENC_4_ROUNDS #undef AES_ENC_4_LAST_ROUNDS #undef AES_DEC_4_ROUNDS #undef AES_DEC_4_LAST_ROUNDS } /* * Rivest's Package Tranform * * (C) 2009 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void aont_package(RandomNumberGenerator& rng, BlockCipher* cipher, const uint8_t input[], size_t input_len, uint8_t output[]) { if(input_len <= 1) throw Encoding_Error("Package transform cannot encode small inputs"); const size_t BLOCK_SIZE = cipher->block_size(); if(!cipher->valid_keylength(BLOCK_SIZE)) throw Invalid_Argument("AONT::package: Invalid cipher"); // The all-zero string which is used both as the CTR IV and as K0 const std::string all_zeros(BLOCK_SIZE*2, '0'); SymmetricKey package_key(rng, BLOCK_SIZE); Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); pipe.process_msg(input, input_len); const size_t remaining = pipe.remaining(); BOTAN_ASSERT_EQUAL(remaining, pipe.read(output, remaining), "Expected read size"); // Set K0 (the all zero key) cipher->set_key(SymmetricKey(all_zeros)); secure_vector buf(BLOCK_SIZE); const size_t blocks = (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE; uint8_t* final_block = output + input_len; clear_mem(final_block, BLOCK_SIZE); // XOR the hash blocks into the final block for(size_t i = 0; i != blocks; ++i) { const size_t left = std::min(BLOCK_SIZE, input_len - BLOCK_SIZE * i); zeroise(buf); copy_mem(buf.data(), output + (BLOCK_SIZE * i), left); for(size_t j = 0; j != sizeof(i); ++j) buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); cipher->encrypt(buf.data()); xor_buf(final_block, buf.data(), BLOCK_SIZE); } // XOR the random package key into the final block xor_buf(final_block, package_key.begin(), BLOCK_SIZE); } void aont_unpackage(BlockCipher* cipher, const uint8_t input[], size_t input_len, uint8_t output[]) { const size_t BLOCK_SIZE = cipher->block_size(); if(!cipher->valid_keylength(BLOCK_SIZE)) throw Invalid_Argument("AONT::unpackage: Invalid cipher"); if(input_len < BLOCK_SIZE) throw Invalid_Argument("AONT::unpackage: Input too short"); // The all-zero string which is used both as the CTR IV and as K0 const std::string all_zeros(BLOCK_SIZE*2, '0'); cipher->set_key(SymmetricKey(all_zeros)); secure_vector package_key(BLOCK_SIZE); secure_vector buf(BLOCK_SIZE); // Copy the package key (masked with the block hashes) copy_mem(package_key.data(), input + (input_len - BLOCK_SIZE), BLOCK_SIZE); const size_t blocks = ((input_len - 1) / BLOCK_SIZE); // XOR the blocks into the package key bits for(size_t i = 0; i != blocks; ++i) { const size_t left = std::min(BLOCK_SIZE, input_len - BLOCK_SIZE * (i+1)); zeroise(buf); copy_mem(buf.data(), input + (BLOCK_SIZE * i), left); for(size_t j = 0; j != sizeof(i); ++j) buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); cipher->encrypt(buf.data()); xor_buf(package_key.data(), buf.data(), BLOCK_SIZE); } Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); pipe.process_msg(input, input_len - BLOCK_SIZE); const size_t remaining = pipe.remaining(); BOTAN_ASSERT_EQUAL(remaining, pipe.read(output, remaining), "Expected read size"); } } /** * (C) 2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { static const size_t SYNC_POINTS = 4; secure_vector argon2_H0(HashFunction& blake2b, size_t output_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len, const uint8_t key[], size_t key_len, const uint8_t ad[], size_t ad_len, size_t y, size_t p, size_t M, size_t t) { const uint8_t v = 19; // Argon2 version code blake2b.update_le(static_cast(p)); blake2b.update_le(static_cast(output_len)); blake2b.update_le(static_cast(M)); blake2b.update_le(static_cast(t)); blake2b.update_le(static_cast(v)); blake2b.update_le(static_cast(y)); blake2b.update_le(static_cast(password_len)); blake2b.update(cast_char_ptr_to_uint8(password), password_len); blake2b.update_le(static_cast(salt_len)); blake2b.update(salt, salt_len); blake2b.update_le(static_cast(key_len)); blake2b.update(key, key_len); blake2b.update_le(static_cast(ad_len)); blake2b.update(ad, ad_len); return blake2b.final(); } void Htick(secure_vector& T, uint8_t output[], size_t output_len, HashFunction& blake2b, const secure_vector& H0, size_t p0, size_t p1) { BOTAN_ASSERT_NOMSG(output_len % 64 == 0); blake2b.update_le(static_cast(output_len)); blake2b.update(H0); blake2b.update_le(static_cast(p0)); blake2b.update_le(static_cast(p1)); blake2b.final(&T[0]); while(output_len > 64) { copy_mem(output, &T[0], 32); output_len -= 32; output += 32; blake2b.update(T); blake2b.final(&T[0]); } if(output_len > 0) copy_mem(output, &T[0], output_len); } void extract_key(uint8_t output[], size_t output_len, const secure_vector& B, size_t memory, size_t threads) { const size_t lanes = memory / threads; secure_vector sum(128); for(size_t lane = 0; lane != threads; ++lane) { size_t start = 128*(lane * lanes + lanes - 1); size_t end = 128*(lane * lanes + lanes); for(size_t j = start; j != end; ++j) { sum[j % 128] ^= B[j]; } } secure_vector sum8(1024); copy_out_le(sum8.data(), 1024, sum.data()); if(output_len <= 64) { std::unique_ptr blake2b = HashFunction::create_or_throw("BLAKE2b(" + std::to_string(output_len*8) + ")"); blake2b->update_le(static_cast(output_len)); blake2b->update(sum8.data(), sum8.size()); blake2b->final(output); } else { secure_vector T(64); std::unique_ptr blake2b = HashFunction::create_or_throw("BLAKE2b(512)"); blake2b->update_le(static_cast(output_len)); blake2b->update(sum8.data(), sum8.size()); blake2b->final(&T[0]); while(output_len > 64) { copy_mem(output, &T[0], 32); output_len -= 32; output += 32; if(output_len > 64) { blake2b->update(T); blake2b->final(&T[0]); } } if(output_len == 64) { blake2b->update(T); blake2b->final(output); } else { std::unique_ptr blake2b_f = HashFunction::create_or_throw("BLAKE2b(" + std::to_string(output_len*8) + ")"); blake2b_f->update(T); blake2b_f->final(output); } } } void init_blocks(secure_vector& B, HashFunction& blake2b, const secure_vector& H0, size_t memory, size_t threads) { BOTAN_ASSERT_NOMSG(B.size() >= threads*256); secure_vector H(1024); secure_vector T(blake2b.output_length()); for(size_t i = 0; i != threads; ++i) { const size_t B_off = i * (memory / threads); BOTAN_ASSERT_NOMSG(B.size() >= 128*(B_off+2)); Htick(T, &H[0], H.size(), blake2b, H0, 0, i); for(size_t j = 0; j != 128; ++j) { B[128*B_off+j] = load_le(H.data(), j); } Htick(T, &H[0], H.size(), blake2b, H0, 1, i); for(size_t j = 0; j != 128; ++j) { B[128*(B_off+1)+j] = load_le(H.data(), j); } } } inline void blamka_G(uint64_t& A, uint64_t& B, uint64_t& C, uint64_t& D) { A += B + (static_cast(2) * static_cast(A)) * static_cast(B); D = rotr<32>(A ^ D); C += D + (static_cast(2) * static_cast(C)) * static_cast(D); B = rotr<24>(B ^ C); A += B + (static_cast(2) * static_cast(A)) * static_cast(B); D = rotr<16>(A ^ D); C += D + (static_cast(2) * static_cast(C)) * static_cast(D); B = rotr<63>(B ^ C); } inline void blamka(uint64_t& V0, uint64_t& V1, uint64_t& V2, uint64_t& V3, uint64_t& V4, uint64_t& V5, uint64_t& V6, uint64_t& V7, uint64_t& V8, uint64_t& V9, uint64_t& VA, uint64_t& VB, uint64_t& VC, uint64_t& VD, uint64_t& VE, uint64_t& VF) { blamka_G(V0, V4, V8, VC); blamka_G(V1, V5, V9, VD); blamka_G(V2, V6, VA, VE); blamka_G(V3, V7, VB, VF); blamka_G(V0, V5, VA, VF); blamka_G(V1, V6, VB, VC); blamka_G(V2, V7, V8, VD); blamka_G(V3, V4, V9, VE); } void process_block_xor(secure_vector& T, secure_vector& B, size_t offset, size_t prev, size_t new_offset) { for(size_t i = 0; i != 128; ++i) T[i] = B[128*prev+i] ^ B[128*new_offset+i]; for(size_t i = 0; i != 128; i += 16) { blamka(T[i+ 0], T[i+ 1], T[i+ 2], T[i+ 3], T[i+ 4], T[i+ 5], T[i+ 6], T[i+ 7], T[i+ 8], T[i+ 9], T[i+10], T[i+11], T[i+12], T[i+13], T[i+14], T[i+15]); } for(size_t i = 0; i != 128 / 8; i += 2) { blamka(T[ i], T[ i+1], T[ 16+i], T[ 16+i+1], T[ 32+i], T[ 32+i+1], T[ 48+i], T[ 48+i+1], T[ 64+i], T[ 64+i+1], T[ 80+i], T[ 80+i+1], T[ 96+i], T[ 96+i+1], T[112+i], T[112+i+1]); } for(size_t i = 0; i != 128; ++i) B[128*offset + i] ^= T[i] ^ B[128*prev+i] ^ B[128*new_offset+i]; } void gen_2i_addresses(secure_vector& T, secure_vector& B, size_t n, size_t lane, size_t slice, size_t memory, size_t time, size_t mode, size_t cnt) { BOTAN_ASSERT_NOMSG(B.size() == 128); BOTAN_ASSERT_NOMSG(T.size() == 128); clear_mem(B.data(), B.size()); B[0] = n; B[1] = lane; B[2] = slice; B[3] = memory; B[4] = time; B[5] = mode; B[6] = cnt; for(size_t r = 0; r != 2; ++r) { copy_mem(T.data(), B.data(), B.size()); for(size_t i = 0; i != 128; i += 16) { blamka(T[i+ 0], T[i+ 1], T[i+ 2], T[i+ 3], T[i+ 4], T[i+ 5], T[i+ 6], T[i+ 7], T[i+ 8], T[i+ 9], T[i+10], T[i+11], T[i+12], T[i+13], T[i+14], T[i+15]); } for(size_t i = 0; i != 128 / 8; i += 2) { blamka(T[ i], T[ i+1], T[ 16+i], T[ 16+i+1], T[ 32+i], T[ 32+i+1], T[ 48+i], T[ 48+i+1], T[ 64+i], T[ 64+i+1], T[ 80+i], T[ 80+i+1], T[ 96+i], T[ 96+i+1], T[112+i], T[112+i+1]); } for(size_t i = 0; i != 128; ++i) B[i] ^= T[i]; } } uint32_t index_alpha(uint64_t random, size_t lanes, size_t segments, size_t threads, size_t n, size_t slice, size_t lane, size_t index) { size_t ref_lane = static_cast(random >> 32) % threads; if(n == 0 && slice == 0) ref_lane = lane; size_t m = 3*segments; size_t s = ((slice+1) % 4)*segments; if(lane == ref_lane) m += index; if(n == 0) { m = slice*segments; s = 0; if(slice == 0 || lane == ref_lane) m += index; } if(index == 0 || lane == ref_lane) m -= 1; uint64_t p = static_cast(random); p = (p * p) >> 32; p = (p * m) >> 32; return static_cast(ref_lane*lanes + (s + m - (p+1)) % lanes); } void process_block_argon2d(secure_vector& T, secure_vector& B, size_t n, size_t slice, size_t lane, size_t lanes, size_t segments, size_t threads) { size_t index = 0; if(n == 0 && slice == 0) index = 2; while(index < segments) { const size_t offset = lane*lanes + slice*segments + index; size_t prev = offset - 1; if(index == 0 && slice == 0) prev += lanes; const uint64_t random = B.at(128*prev); const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index); process_block_xor(T, B, offset, prev, new_offset); index += 1; } } void process_block_argon2i(secure_vector& T, secure_vector& B, size_t n, size_t slice, size_t lane, size_t lanes, size_t segments, size_t threads, uint8_t mode, size_t memory, size_t time) { size_t index = 0; if(n == 0 && slice == 0) index = 2; secure_vector addresses(128); size_t address_counter = 1; gen_2i_addresses(T, addresses, n, lane, slice, memory, time, mode, address_counter); while(index < segments) { const size_t offset = lane*lanes + slice*segments + index; size_t prev = offset - 1; if(index == 0 && slice == 0) prev += lanes; if(index > 0 && index % 128 == 0) { address_counter += 1; gen_2i_addresses(T, addresses, n, lane, slice, memory, time, mode, address_counter); } const uint64_t random = addresses[index % 128]; const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index); process_block_xor(T, B, offset, prev, new_offset); index += 1; } } void process_blocks(secure_vector& B, size_t t, size_t memory, size_t threads, uint8_t mode) { const size_t lanes = memory / threads; const size_t segments = lanes / SYNC_POINTS; secure_vector T(128); for(size_t n = 0; n != t; ++n) { for(size_t slice = 0; slice != SYNC_POINTS; ++slice) { // TODO can run this in Thread_Pool for(size_t lane = 0; lane != threads; ++lane) { if(mode == 1 || (mode == 2 && n == 0 && slice < SYNC_POINTS/2)) process_block_argon2i(T, B, n, slice, lane, lanes, segments, threads, mode, memory, t); else process_block_argon2d(T, B, n, slice, lane, lanes, segments, threads); } } } } } void argon2(uint8_t output[], size_t output_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len, const uint8_t key[], size_t key_len, const uint8_t ad[], size_t ad_len, uint8_t mode, size_t threads, size_t M, size_t t) { BOTAN_ARG_CHECK(mode == 0 || mode == 1 || mode == 2, "Unknown Argon2 mode parameter"); BOTAN_ARG_CHECK(output_len >= 4, "Invalid Argon2 output length"); BOTAN_ARG_CHECK(threads >= 1 && threads <= 128, "Invalid Argon2 threads parameter"); BOTAN_ARG_CHECK(M >= 8*threads && M <= 8192*1024, "Invalid Argon2 M parameter"); BOTAN_ARG_CHECK(t >= 1, "Invalid Argon2 t parameter"); std::unique_ptr blake2 = HashFunction::create_or_throw("BLAKE2b"); const auto H0 = argon2_H0(*blake2, output_len, password, password_len, salt, salt_len, key, key_len, ad, ad_len, mode, threads, M, t); const size_t memory = (M / (SYNC_POINTS*threads)) * (SYNC_POINTS*threads); secure_vector B(memory * 1024/8); init_blocks(B, *blake2, H0, memory, threads); process_blocks(B, t, memory, threads, mode); clear_mem(output, output_len); extract_key(output, output_len, B, memory, threads); } } /** * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { std::string strip_padding(std::string s) { while(s.size() > 0 && s[s.size()-1] == '=') s.resize(s.size() - 1); return s; } } std::string argon2_generate_pwhash(const char* password, size_t password_len, RandomNumberGenerator& rng, size_t p, size_t M, size_t t, uint8_t y, size_t salt_len, size_t output_len) { std::vector salt(salt_len); rng.randomize(salt.data(), salt.size()); std::vector output(output_len); argon2(output.data(), output.size(), password, password_len, salt.data(), salt.size(), nullptr, 0, nullptr, 0, y, p, M, t); std::ostringstream oss; if(y == 0) oss << "$argon2d$"; else if(y == 1) oss << "$argon2i$"; else oss << "$argon2id$"; oss << "v=19$m=" << M << ",t=" << t << ",p=" << p << "$"; oss << strip_padding(base64_encode(salt)) << "$" << strip_padding(base64_encode(output)); return oss.str(); } bool argon2_check_pwhash(const char* password, size_t password_len, const std::string& input_hash) { const std::vector parts = split_on(input_hash, '$'); if(parts.size() != 5) return false; uint8_t family = 0; if(parts[0] == "argon2d") family = 0; else if(parts[0] == "argon2i") family = 1; else if(parts[0] == "argon2id") family = 2; else return false; if(parts[1] != "v=19") return false; const std::vector params = split_on(parts[2], ','); if(params.size() != 3) return false; size_t M = 0, t = 0, p = 0; for(auto param_str : params) { const std::vector param = split_on(param_str, '='); if(param.size() != 2) return false; const std::string key = param[0]; const size_t val = to_u32bit(param[1]); if(key == "m") M = val; else if(key == "t") t = val; else if(key == "p") p = val; else return false; } std::vector salt(base64_decode_max_output(parts[3].size())); salt.resize(base64_decode(salt.data(), parts[3], false)); std::vector hash(base64_decode_max_output(parts[4].size())); hash.resize(base64_decode(hash.data(), parts[4], false)); if(hash.size() < 4) return false; std::vector generated(hash.size()); argon2(generated.data(), generated.size(), password, password_len, salt.data(), salt.size(), nullptr, 0, nullptr, 0, family, p, M, t); return constant_time_compare(generated.data(), hash.data(), generated.size()); } } /** * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { Argon2::Argon2(uint8_t family, size_t M, size_t t, size_t p) : m_family(family), m_M(M), m_t(t), m_p(p) {} void Argon2::derive_key(uint8_t output[], size_t output_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) const { argon2(output, output_len, password, password_len, salt, salt_len, nullptr, 0, nullptr, 0, m_family, m_p, m_M, m_t); } namespace { std::string argon2_family_name(uint8_t f) { switch(f) { case 0: return "Argon2d"; case 1: return "Argon2i"; case 2: return "Argon2id"; default: throw Invalid_Argument("Unknown Argon2 parameter"); } } } std::string Argon2::to_string() const { return argon2_family_name(m_family) + "(" + std::to_string(m_M) + "," + std::to_string(m_t) + "," + std::to_string(m_p) + ")"; } Argon2_Family::Argon2_Family(uint8_t family) : m_family(family) { if(m_family != 0 && m_family != 1 && m_family != 2) throw Invalid_Argument("Unknown Argon2 family identifier"); } std::string Argon2_Family::name() const { return argon2_family_name(m_family); } std::unique_ptr Argon2_Family::tune(size_t /*output_length*/, std::chrono::milliseconds msec, size_t max_memory) const { const size_t max_kib = (max_memory == 0) ? 256*1024 : max_memory*1024; // Tune with a large memory otherwise we measure cache vs RAM speeds and underestimate // costs for larger params. Default is 36 MiB, or use 128 for long times. const size_t tune_M = (msec >= std::chrono::milliseconds(500) ? 128 : 36) * 1024; const size_t p = 1; size_t t = 1; Timer timer("Argon2"); const auto tune_time = BOTAN_PBKDF_TUNING_TIME; timer.run_until_elapsed(tune_time, [&]() { uint8_t output[64] = { 0 }; argon2(output, sizeof(output), "test", 4, nullptr, 0, nullptr, 0, nullptr, 0, m_family, p, tune_M, t); }); if(timer.events() == 0 || timer.value() == 0) return default_params(); size_t M = 4*1024; const uint64_t measured_time = timer.value() / (timer.events() * (tune_M / M)); const uint64_t target_nsec = msec.count() * static_cast(1000000); /* * Argon2 scaling rules: * k*M, k*t, k*p all increase cost by about k * * Since we don't even take advantage of p > 1, we prefer increasing * t or M instead. * * If possible to increase M, prefer that. */ uint64_t est_nsec = measured_time; if(est_nsec < target_nsec && M < max_kib) { const uint64_t desired_cost_increase = (target_nsec + est_nsec - 1) / est_nsec; const uint64_t mem_headroom = max_kib / M; const uint64_t M_mult = std::min(desired_cost_increase, mem_headroom); M *= static_cast(M_mult); est_nsec *= M_mult; } if(est_nsec < target_nsec) { const uint64_t desired_cost_increase = (target_nsec + est_nsec - 1) / est_nsec; t *= static_cast(desired_cost_increase); } return this->from_params(M, t, p); } std::unique_ptr Argon2_Family::default_params() const { return this->from_params(128*1024, 1, 1); } std::unique_ptr Argon2_Family::from_iterations(size_t iter) const { /* These choices are arbitrary, but should not change in future releases since they will break applications expecting deterministic mapping from iteration count to params */ const size_t M = iter; const size_t t = 1; const size_t p = 1; return this->from_params(M, t, p); } std::unique_ptr Argon2_Family::from_params(size_t M, size_t t, size_t p) const { return std::unique_ptr(new Argon2(m_family, M, t, p)); } } /* * ARIA * Adapted for Botan by Jeffrey Walton, public domain * * Further changes * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) * * This ARIA implementation is based on the 32-bit implementation by Aaram Yun from the * National Security Research Institute, KOREA. Aaram Yun's implementation is based on * the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from * the Korea Internet & Security Agency website. * RFC 5794, A Description of the ARIA Encryption Algorithm, * Korea * Internet & Security Agency homepage */ namespace Botan { namespace { namespace ARIA_F { alignas(64) const uint32_t S1[256]={ 0x00636363,0x007c7c7c,0x00777777,0x007b7b7b,0x00f2f2f2,0x006b6b6b,0x006f6f6f,0x00c5c5c5, 0x00303030,0x00010101,0x00676767,0x002b2b2b,0x00fefefe,0x00d7d7d7,0x00ababab,0x00767676, 0x00cacaca,0x00828282,0x00c9c9c9,0x007d7d7d,0x00fafafa,0x00595959,0x00474747,0x00f0f0f0, 0x00adadad,0x00d4d4d4,0x00a2a2a2,0x00afafaf,0x009c9c9c,0x00a4a4a4,0x00727272,0x00c0c0c0, 0x00b7b7b7,0x00fdfdfd,0x00939393,0x00262626,0x00363636,0x003f3f3f,0x00f7f7f7,0x00cccccc, 0x00343434,0x00a5a5a5,0x00e5e5e5,0x00f1f1f1,0x00717171,0x00d8d8d8,0x00313131,0x00151515, 0x00040404,0x00c7c7c7,0x00232323,0x00c3c3c3,0x00181818,0x00969696,0x00050505,0x009a9a9a, 0x00070707,0x00121212,0x00808080,0x00e2e2e2,0x00ebebeb,0x00272727,0x00b2b2b2,0x00757575, 0x00090909,0x00838383,0x002c2c2c,0x001a1a1a,0x001b1b1b,0x006e6e6e,0x005a5a5a,0x00a0a0a0, 0x00525252,0x003b3b3b,0x00d6d6d6,0x00b3b3b3,0x00292929,0x00e3e3e3,0x002f2f2f,0x00848484, 0x00535353,0x00d1d1d1,0x00000000,0x00ededed,0x00202020,0x00fcfcfc,0x00b1b1b1,0x005b5b5b, 0x006a6a6a,0x00cbcbcb,0x00bebebe,0x00393939,0x004a4a4a,0x004c4c4c,0x00585858,0x00cfcfcf, 0x00d0d0d0,0x00efefef,0x00aaaaaa,0x00fbfbfb,0x00434343,0x004d4d4d,0x00333333,0x00858585, 0x00454545,0x00f9f9f9,0x00020202,0x007f7f7f,0x00505050,0x003c3c3c,0x009f9f9f,0x00a8a8a8, 0x00515151,0x00a3a3a3,0x00404040,0x008f8f8f,0x00929292,0x009d9d9d,0x00383838,0x00f5f5f5, 0x00bcbcbc,0x00b6b6b6,0x00dadada,0x00212121,0x00101010,0x00ffffff,0x00f3f3f3,0x00d2d2d2, 0x00cdcdcd,0x000c0c0c,0x00131313,0x00ececec,0x005f5f5f,0x00979797,0x00444444,0x00171717, 0x00c4c4c4,0x00a7a7a7,0x007e7e7e,0x003d3d3d,0x00646464,0x005d5d5d,0x00191919,0x00737373, 0x00606060,0x00818181,0x004f4f4f,0x00dcdcdc,0x00222222,0x002a2a2a,0x00909090,0x00888888, 0x00464646,0x00eeeeee,0x00b8b8b8,0x00141414,0x00dedede,0x005e5e5e,0x000b0b0b,0x00dbdbdb, 0x00e0e0e0,0x00323232,0x003a3a3a,0x000a0a0a,0x00494949,0x00060606,0x00242424,0x005c5c5c, 0x00c2c2c2,0x00d3d3d3,0x00acacac,0x00626262,0x00919191,0x00959595,0x00e4e4e4,0x00797979, 0x00e7e7e7,0x00c8c8c8,0x00373737,0x006d6d6d,0x008d8d8d,0x00d5d5d5,0x004e4e4e,0x00a9a9a9, 0x006c6c6c,0x00565656,0x00f4f4f4,0x00eaeaea,0x00656565,0x007a7a7a,0x00aeaeae,0x00080808, 0x00bababa,0x00787878,0x00252525,0x002e2e2e,0x001c1c1c,0x00a6a6a6,0x00b4b4b4,0x00c6c6c6, 0x00e8e8e8,0x00dddddd,0x00747474,0x001f1f1f,0x004b4b4b,0x00bdbdbd,0x008b8b8b,0x008a8a8a, 0x00707070,0x003e3e3e,0x00b5b5b5,0x00666666,0x00484848,0x00030303,0x00f6f6f6,0x000e0e0e, 0x00616161,0x00353535,0x00575757,0x00b9b9b9,0x00868686,0x00c1c1c1,0x001d1d1d,0x009e9e9e, 0x00e1e1e1,0x00f8f8f8,0x00989898,0x00111111,0x00696969,0x00d9d9d9,0x008e8e8e,0x00949494, 0x009b9b9b,0x001e1e1e,0x00878787,0x00e9e9e9,0x00cecece,0x00555555,0x00282828,0x00dfdfdf, 0x008c8c8c,0x00a1a1a1,0x00898989,0x000d0d0d,0x00bfbfbf,0x00e6e6e6,0x00424242,0x00686868, 0x00414141,0x00999999,0x002d2d2d,0x000f0f0f,0x00b0b0b0,0x00545454,0x00bbbbbb,0x00161616 }; alignas(64) const uint32_t S2[256]={ 0xe200e2e2,0x4e004e4e,0x54005454,0xfc00fcfc,0x94009494,0xc200c2c2,0x4a004a4a,0xcc00cccc, 0x62006262,0x0d000d0d,0x6a006a6a,0x46004646,0x3c003c3c,0x4d004d4d,0x8b008b8b,0xd100d1d1, 0x5e005e5e,0xfa00fafa,0x64006464,0xcb00cbcb,0xb400b4b4,0x97009797,0xbe00bebe,0x2b002b2b, 0xbc00bcbc,0x77007777,0x2e002e2e,0x03000303,0xd300d3d3,0x19001919,0x59005959,0xc100c1c1, 0x1d001d1d,0x06000606,0x41004141,0x6b006b6b,0x55005555,0xf000f0f0,0x99009999,0x69006969, 0xea00eaea,0x9c009c9c,0x18001818,0xae00aeae,0x63006363,0xdf00dfdf,0xe700e7e7,0xbb00bbbb, 0x00000000,0x73007373,0x66006666,0xfb00fbfb,0x96009696,0x4c004c4c,0x85008585,0xe400e4e4, 0x3a003a3a,0x09000909,0x45004545,0xaa00aaaa,0x0f000f0f,0xee00eeee,0x10001010,0xeb00ebeb, 0x2d002d2d,0x7f007f7f,0xf400f4f4,0x29002929,0xac00acac,0xcf00cfcf,0xad00adad,0x91009191, 0x8d008d8d,0x78007878,0xc800c8c8,0x95009595,0xf900f9f9,0x2f002f2f,0xce00cece,0xcd00cdcd, 0x08000808,0x7a007a7a,0x88008888,0x38003838,0x5c005c5c,0x83008383,0x2a002a2a,0x28002828, 0x47004747,0xdb00dbdb,0xb800b8b8,0xc700c7c7,0x93009393,0xa400a4a4,0x12001212,0x53005353, 0xff00ffff,0x87008787,0x0e000e0e,0x31003131,0x36003636,0x21002121,0x58005858,0x48004848, 0x01000101,0x8e008e8e,0x37003737,0x74007474,0x32003232,0xca00caca,0xe900e9e9,0xb100b1b1, 0xb700b7b7,0xab00abab,0x0c000c0c,0xd700d7d7,0xc400c4c4,0x56005656,0x42004242,0x26002626, 0x07000707,0x98009898,0x60006060,0xd900d9d9,0xb600b6b6,0xb900b9b9,0x11001111,0x40004040, 0xec00ecec,0x20002020,0x8c008c8c,0xbd00bdbd,0xa000a0a0,0xc900c9c9,0x84008484,0x04000404, 0x49004949,0x23002323,0xf100f1f1,0x4f004f4f,0x50005050,0x1f001f1f,0x13001313,0xdc00dcdc, 0xd800d8d8,0xc000c0c0,0x9e009e9e,0x57005757,0xe300e3e3,0xc300c3c3,0x7b007b7b,0x65006565, 0x3b003b3b,0x02000202,0x8f008f8f,0x3e003e3e,0xe800e8e8,0x25002525,0x92009292,0xe500e5e5, 0x15001515,0xdd00dddd,0xfd00fdfd,0x17001717,0xa900a9a9,0xbf00bfbf,0xd400d4d4,0x9a009a9a, 0x7e007e7e,0xc500c5c5,0x39003939,0x67006767,0xfe00fefe,0x76007676,0x9d009d9d,0x43004343, 0xa700a7a7,0xe100e1e1,0xd000d0d0,0xf500f5f5,0x68006868,0xf200f2f2,0x1b001b1b,0x34003434, 0x70007070,0x05000505,0xa300a3a3,0x8a008a8a,0xd500d5d5,0x79007979,0x86008686,0xa800a8a8, 0x30003030,0xc600c6c6,0x51005151,0x4b004b4b,0x1e001e1e,0xa600a6a6,0x27002727,0xf600f6f6, 0x35003535,0xd200d2d2,0x6e006e6e,0x24002424,0x16001616,0x82008282,0x5f005f5f,0xda00dada, 0xe600e6e6,0x75007575,0xa200a2a2,0xef00efef,0x2c002c2c,0xb200b2b2,0x1c001c1c,0x9f009f9f, 0x5d005d5d,0x6f006f6f,0x80008080,0x0a000a0a,0x72007272,0x44004444,0x9b009b9b,0x6c006c6c, 0x90009090,0x0b000b0b,0x5b005b5b,0x33003333,0x7d007d7d,0x5a005a5a,0x52005252,0xf300f3f3, 0x61006161,0xa100a1a1,0xf700f7f7,0xb000b0b0,0xd600d6d6,0x3f003f3f,0x7c007c7c,0x6d006d6d, 0xed00eded,0x14001414,0xe000e0e0,0xa500a5a5,0x3d003d3d,0x22002222,0xb300b3b3,0xf800f8f8, 0x89008989,0xde00dede,0x71007171,0x1a001a1a,0xaf00afaf,0xba00baba,0xb500b5b5,0x81008181 }; alignas(64) const uint32_t X1[256]={ 0x52520052,0x09090009,0x6a6a006a,0xd5d500d5,0x30300030,0x36360036,0xa5a500a5,0x38380038, 0xbfbf00bf,0x40400040,0xa3a300a3,0x9e9e009e,0x81810081,0xf3f300f3,0xd7d700d7,0xfbfb00fb, 0x7c7c007c,0xe3e300e3,0x39390039,0x82820082,0x9b9b009b,0x2f2f002f,0xffff00ff,0x87870087, 0x34340034,0x8e8e008e,0x43430043,0x44440044,0xc4c400c4,0xdede00de,0xe9e900e9,0xcbcb00cb, 0x54540054,0x7b7b007b,0x94940094,0x32320032,0xa6a600a6,0xc2c200c2,0x23230023,0x3d3d003d, 0xeeee00ee,0x4c4c004c,0x95950095,0x0b0b000b,0x42420042,0xfafa00fa,0xc3c300c3,0x4e4e004e, 0x08080008,0x2e2e002e,0xa1a100a1,0x66660066,0x28280028,0xd9d900d9,0x24240024,0xb2b200b2, 0x76760076,0x5b5b005b,0xa2a200a2,0x49490049,0x6d6d006d,0x8b8b008b,0xd1d100d1,0x25250025, 0x72720072,0xf8f800f8,0xf6f600f6,0x64640064,0x86860086,0x68680068,0x98980098,0x16160016, 0xd4d400d4,0xa4a400a4,0x5c5c005c,0xcccc00cc,0x5d5d005d,0x65650065,0xb6b600b6,0x92920092, 0x6c6c006c,0x70700070,0x48480048,0x50500050,0xfdfd00fd,0xeded00ed,0xb9b900b9,0xdada00da, 0x5e5e005e,0x15150015,0x46460046,0x57570057,0xa7a700a7,0x8d8d008d,0x9d9d009d,0x84840084, 0x90900090,0xd8d800d8,0xabab00ab,0x00000000,0x8c8c008c,0xbcbc00bc,0xd3d300d3,0x0a0a000a, 0xf7f700f7,0xe4e400e4,0x58580058,0x05050005,0xb8b800b8,0xb3b300b3,0x45450045,0x06060006, 0xd0d000d0,0x2c2c002c,0x1e1e001e,0x8f8f008f,0xcaca00ca,0x3f3f003f,0x0f0f000f,0x02020002, 0xc1c100c1,0xafaf00af,0xbdbd00bd,0x03030003,0x01010001,0x13130013,0x8a8a008a,0x6b6b006b, 0x3a3a003a,0x91910091,0x11110011,0x41410041,0x4f4f004f,0x67670067,0xdcdc00dc,0xeaea00ea, 0x97970097,0xf2f200f2,0xcfcf00cf,0xcece00ce,0xf0f000f0,0xb4b400b4,0xe6e600e6,0x73730073, 0x96960096,0xacac00ac,0x74740074,0x22220022,0xe7e700e7,0xadad00ad,0x35350035,0x85850085, 0xe2e200e2,0xf9f900f9,0x37370037,0xe8e800e8,0x1c1c001c,0x75750075,0xdfdf00df,0x6e6e006e, 0x47470047,0xf1f100f1,0x1a1a001a,0x71710071,0x1d1d001d,0x29290029,0xc5c500c5,0x89890089, 0x6f6f006f,0xb7b700b7,0x62620062,0x0e0e000e,0xaaaa00aa,0x18180018,0xbebe00be,0x1b1b001b, 0xfcfc00fc,0x56560056,0x3e3e003e,0x4b4b004b,0xc6c600c6,0xd2d200d2,0x79790079,0x20200020, 0x9a9a009a,0xdbdb00db,0xc0c000c0,0xfefe00fe,0x78780078,0xcdcd00cd,0x5a5a005a,0xf4f400f4, 0x1f1f001f,0xdddd00dd,0xa8a800a8,0x33330033,0x88880088,0x07070007,0xc7c700c7,0x31310031, 0xb1b100b1,0x12120012,0x10100010,0x59590059,0x27270027,0x80800080,0xecec00ec,0x5f5f005f, 0x60600060,0x51510051,0x7f7f007f,0xa9a900a9,0x19190019,0xb5b500b5,0x4a4a004a,0x0d0d000d, 0x2d2d002d,0xe5e500e5,0x7a7a007a,0x9f9f009f,0x93930093,0xc9c900c9,0x9c9c009c,0xefef00ef, 0xa0a000a0,0xe0e000e0,0x3b3b003b,0x4d4d004d,0xaeae00ae,0x2a2a002a,0xf5f500f5,0xb0b000b0, 0xc8c800c8,0xebeb00eb,0xbbbb00bb,0x3c3c003c,0x83830083,0x53530053,0x99990099,0x61610061, 0x17170017,0x2b2b002b,0x04040004,0x7e7e007e,0xbaba00ba,0x77770077,0xd6d600d6,0x26260026, 0xe1e100e1,0x69690069,0x14140014,0x63630063,0x55550055,0x21210021,0x0c0c000c,0x7d7d007d }; alignas(64) const uint32_t X2[256]={ 0x30303000,0x68686800,0x99999900,0x1b1b1b00,0x87878700,0xb9b9b900,0x21212100,0x78787800, 0x50505000,0x39393900,0xdbdbdb00,0xe1e1e100,0x72727200,0x09090900,0x62626200,0x3c3c3c00, 0x3e3e3e00,0x7e7e7e00,0x5e5e5e00,0x8e8e8e00,0xf1f1f100,0xa0a0a000,0xcccccc00,0xa3a3a300, 0x2a2a2a00,0x1d1d1d00,0xfbfbfb00,0xb6b6b600,0xd6d6d600,0x20202000,0xc4c4c400,0x8d8d8d00, 0x81818100,0x65656500,0xf5f5f500,0x89898900,0xcbcbcb00,0x9d9d9d00,0x77777700,0xc6c6c600, 0x57575700,0x43434300,0x56565600,0x17171700,0xd4d4d400,0x40404000,0x1a1a1a00,0x4d4d4d00, 0xc0c0c000,0x63636300,0x6c6c6c00,0xe3e3e300,0xb7b7b700,0xc8c8c800,0x64646400,0x6a6a6a00, 0x53535300,0xaaaaaa00,0x38383800,0x98989800,0x0c0c0c00,0xf4f4f400,0x9b9b9b00,0xededed00, 0x7f7f7f00,0x22222200,0x76767600,0xafafaf00,0xdddddd00,0x3a3a3a00,0x0b0b0b00,0x58585800, 0x67676700,0x88888800,0x06060600,0xc3c3c300,0x35353500,0x0d0d0d00,0x01010100,0x8b8b8b00, 0x8c8c8c00,0xc2c2c200,0xe6e6e600,0x5f5f5f00,0x02020200,0x24242400,0x75757500,0x93939300, 0x66666600,0x1e1e1e00,0xe5e5e500,0xe2e2e200,0x54545400,0xd8d8d800,0x10101000,0xcecece00, 0x7a7a7a00,0xe8e8e800,0x08080800,0x2c2c2c00,0x12121200,0x97979700,0x32323200,0xababab00, 0xb4b4b400,0x27272700,0x0a0a0a00,0x23232300,0xdfdfdf00,0xefefef00,0xcacaca00,0xd9d9d900, 0xb8b8b800,0xfafafa00,0xdcdcdc00,0x31313100,0x6b6b6b00,0xd1d1d100,0xadadad00,0x19191900, 0x49494900,0xbdbdbd00,0x51515100,0x96969600,0xeeeeee00,0xe4e4e400,0xa8a8a800,0x41414100, 0xdadada00,0xffffff00,0xcdcdcd00,0x55555500,0x86868600,0x36363600,0xbebebe00,0x61616100, 0x52525200,0xf8f8f800,0xbbbbbb00,0x0e0e0e00,0x82828200,0x48484800,0x69696900,0x9a9a9a00, 0xe0e0e000,0x47474700,0x9e9e9e00,0x5c5c5c00,0x04040400,0x4b4b4b00,0x34343400,0x15151500, 0x79797900,0x26262600,0xa7a7a700,0xdedede00,0x29292900,0xaeaeae00,0x92929200,0xd7d7d700, 0x84848400,0xe9e9e900,0xd2d2d200,0xbababa00,0x5d5d5d00,0xf3f3f300,0xc5c5c500,0xb0b0b000, 0xbfbfbf00,0xa4a4a400,0x3b3b3b00,0x71717100,0x44444400,0x46464600,0x2b2b2b00,0xfcfcfc00, 0xebebeb00,0x6f6f6f00,0xd5d5d500,0xf6f6f600,0x14141400,0xfefefe00,0x7c7c7c00,0x70707000, 0x5a5a5a00,0x7d7d7d00,0xfdfdfd00,0x2f2f2f00,0x18181800,0x83838300,0x16161600,0xa5a5a500, 0x91919100,0x1f1f1f00,0x05050500,0x95959500,0x74747400,0xa9a9a900,0xc1c1c100,0x5b5b5b00, 0x4a4a4a00,0x85858500,0x6d6d6d00,0x13131300,0x07070700,0x4f4f4f00,0x4e4e4e00,0x45454500, 0xb2b2b200,0x0f0f0f00,0xc9c9c900,0x1c1c1c00,0xa6a6a600,0xbcbcbc00,0xececec00,0x73737300, 0x90909000,0x7b7b7b00,0xcfcfcf00,0x59595900,0x8f8f8f00,0xa1a1a100,0xf9f9f900,0x2d2d2d00, 0xf2f2f200,0xb1b1b100,0x00000000,0x94949400,0x37373700,0x9f9f9f00,0xd0d0d000,0x2e2e2e00, 0x9c9c9c00,0x6e6e6e00,0x28282800,0x3f3f3f00,0x80808000,0xf0f0f000,0x3d3d3d00,0xd3d3d300, 0x25252500,0x8a8a8a00,0xb5b5b500,0xe7e7e700,0x42424200,0xb3b3b300,0xc7c7c700,0xeaeaea00, 0xf7f7f700,0x4c4c4c00,0x11111100,0x33333300,0x03030300,0xa2a2a200,0xacacac00,0x60606000 }; inline void ARIA_FO(uint32_t& T0, uint32_t& T1, uint32_t& T2, uint32_t& T3) { T0 = S1[get_byte(0,T0)] ^ S2[get_byte(1,T0)] ^ X1[get_byte(2,T0)] ^ X2[get_byte(3,T0)]; T1 = S1[get_byte(0,T1)] ^ S2[get_byte(1,T1)] ^ X1[get_byte(2,T1)] ^ X2[get_byte(3,T1)]; T2 = S1[get_byte(0,T2)] ^ S2[get_byte(1,T2)] ^ X1[get_byte(2,T2)] ^ X2[get_byte(3,T2)]; T3 = S1[get_byte(0,T3)] ^ S2[get_byte(1,T3)] ^ X1[get_byte(2,T3)] ^ X2[get_byte(3,T3)]; T1 ^= T2; T2 ^= T3; T0 ^= T1; T3 ^= T1; T2 ^= T0; T1 ^= T2; T1 = ((T1 << 8) & 0xFF00FF00) | ((T1 >> 8) & 0x00FF00FF); T2 = rotr<16>(T2); T3 = reverse_bytes(T3); T1 ^= T2; T2 ^= T3; T0 ^= T1; T3 ^= T1; T2 ^= T0; T1 ^= T2; } inline void ARIA_FE(uint32_t& T0, uint32_t& T1, uint32_t& T2, uint32_t& T3) { T0 = X1[get_byte(0,T0)] ^ X2[get_byte(1,T0)] ^ S1[get_byte(2,T0)] ^ S2[get_byte(3,T0)]; T1 = X1[get_byte(0,T1)] ^ X2[get_byte(1,T1)] ^ S1[get_byte(2,T1)] ^ S2[get_byte(3,T1)]; T2 = X1[get_byte(0,T2)] ^ X2[get_byte(1,T2)] ^ S1[get_byte(2,T2)] ^ S2[get_byte(3,T2)]; T3 = X1[get_byte(0,T3)] ^ X2[get_byte(1,T3)] ^ S1[get_byte(2,T3)] ^ S2[get_byte(3,T3)]; T1 ^= T2; T2 ^= T3; T0 ^= T1; T3 ^= T1; T2 ^= T0; T1 ^= T2; T3 = ((T3 << 8) & 0xFF00FF00) | ((T3 >> 8) & 0x00FF00FF); T0 = rotr<16>(T0); T1 = reverse_bytes(T1); T1 ^= T2; T2 ^= T3; T0 ^= T1; T3 ^= T1; T2 ^= T0; T1 ^= T2; } /* * ARIA encryption and decryption */ void transform(const uint8_t in[], uint8_t out[], size_t blocks, const secure_vector& KS) { /* * Hit every cache line of S1, S2, X1, X2 * * The initializer of Z ensures Z == 0xFFFFFFFF for any cache line * size that is a power of 2 and <= 512 */ const size_t cache_line_size = CPUID::cache_line_size(); volatile uint32_t Z = 0x11101010; for(size_t i = 0; i < 256; i += cache_line_size / sizeof(uint32_t)) { Z |= S1[i] | S2[i] | X1[i] | X2[i]; } const size_t ROUNDS = (KS.size() / 4) - 1; for(size_t i = 0; i != blocks; ++i) { uint32_t t0, t1, t2, t3; load_be(in + 16*i, t0, t1, t2, t3); t0 &= Z; for(size_t r = 0; r < ROUNDS; r += 2) { t0 ^= KS[4*r]; t1 ^= KS[4*r+1]; t2 ^= KS[4*r+2]; t3 ^= KS[4*r+3]; ARIA_FO(t0,t1,t2,t3); t0 ^= KS[4*r+4]; t1 ^= KS[4*r+5]; t2 ^= KS[4*r+6]; t3 ^= KS[4*r+7]; if(r != ROUNDS-2) ARIA_FE(t0,t1,t2,t3); } out[16*i+ 0] = static_cast(X1[get_byte(0,t0)] ) ^ get_byte(0, KS[4*ROUNDS]); out[16*i+ 1] = static_cast(X2[get_byte(1,t0)]>>8) ^ get_byte(1, KS[4*ROUNDS]); out[16*i+ 2] = static_cast(S1[get_byte(2,t0)] ) ^ get_byte(2, KS[4*ROUNDS]); out[16*i+ 3] = static_cast(S2[get_byte(3,t0)] ) ^ get_byte(3, KS[4*ROUNDS]); out[16*i+ 4] = static_cast(X1[get_byte(0,t1)] ) ^ get_byte(0, KS[4*ROUNDS+1]); out[16*i+ 5] = static_cast(X2[get_byte(1,t1)]>>8) ^ get_byte(1, KS[4*ROUNDS+1]); out[16*i+ 6] = static_cast(S1[get_byte(2,t1)] ) ^ get_byte(2, KS[4*ROUNDS+1]); out[16*i+ 7] = static_cast(S2[get_byte(3,t1)] ) ^ get_byte(3, KS[4*ROUNDS+1]); out[16*i+ 8] = static_cast(X1[get_byte(0,t2)] ) ^ get_byte(0, KS[4*ROUNDS+2]); out[16*i+ 9] = static_cast(X2[get_byte(1,t2)]>>8) ^ get_byte(1, KS[4*ROUNDS+2]); out[16*i+10] = static_cast(S1[get_byte(2,t2)] ) ^ get_byte(2, KS[4*ROUNDS+2]); out[16*i+11] = static_cast(S2[get_byte(3,t2)] ) ^ get_byte(3, KS[4*ROUNDS+2]); out[16*i+12] = static_cast(X1[get_byte(0,t3)] ) ^ get_byte(0, KS[4*ROUNDS+3]); out[16*i+13] = static_cast(X2[get_byte(1,t3)]>>8) ^ get_byte(1, KS[4*ROUNDS+3]); out[16*i+14] = static_cast(S1[get_byte(2,t3)] ) ^ get_byte(2, KS[4*ROUNDS+3]); out[16*i+15] = static_cast(S2[get_byte(3,t3)] ) ^ get_byte(3, KS[4*ROUNDS+3]); } } // n-bit right shift of Y XORed to X template inline void ARIA_ROL128(const uint32_t X[4], const uint32_t Y[4], uint32_t KS[4]) { // MSVC is not generating a "rotate immediate". Constify to help it along. static const size_t Q = 4 - (N / 32); static const size_t R = N % 32; static_assert(R > 0 && R < 32, "Rotation in range for type"); KS[0] = (X[0]) ^ ((Y[(Q )%4])>>R) ^ ((Y[(Q+3)%4])<<(32-R)); KS[1] = (X[1]) ^ ((Y[(Q+1)%4])>>R) ^ ((Y[(Q )%4])<<(32-R)); KS[2] = (X[2]) ^ ((Y[(Q+2)%4])>>R) ^ ((Y[(Q+1)%4])<<(32-R)); KS[3] = (X[3]) ^ ((Y[(Q+3)%4])>>R) ^ ((Y[(Q+2)%4])<<(32-R)); } /* * ARIA Key Schedule */ void key_schedule(secure_vector& ERK, secure_vector& DRK, const uint8_t key[], size_t length) { const uint32_t KRK[3][4] = { {0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0}, {0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0}, {0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e} }; const size_t CK0 = (length / 8) - 2; const size_t CK1 = (CK0 + 1) % 3; const size_t CK2 = (CK1 + 1) % 3; uint32_t w0[4]; uint32_t w1[4]; uint32_t w2[4]; uint32_t w3[4]; w0[0] = load_be(key,0); w0[1] = load_be(key,1); w0[2] = load_be(key,2); w0[3] = load_be(key,3); w1[0] = w0[0] ^ KRK[CK0][0]; w1[1] = w0[1] ^ KRK[CK0][1]; w1[2] = w0[2] ^ KRK[CK0][2]; w1[3] = w0[3] ^ KRK[CK0][3]; ARIA_FO(w1[0], w1[1], w1[2], w1[3]); if(length == 24 || length == 32) { w1[0] ^= load_be(key,4); w1[1] ^= load_be(key,5); } if(length == 32) { w1[2] ^= load_be(key,6); w1[3] ^= load_be(key,7); } w2[0] = w1[0] ^ KRK[CK1][0]; w2[1] = w1[1] ^ KRK[CK1][1]; w2[2] = w1[2] ^ KRK[CK1][2]; w2[3] = w1[3] ^ KRK[CK1][3]; ARIA_FE(w2[0], w2[1], w2[2], w2[3]); w2[0] ^= w0[0]; w2[1] ^= w0[1]; w2[2] ^= w0[2]; w2[3] ^= w0[3]; w3[0] = w2[0] ^ KRK[CK2][0]; w3[1] = w2[1] ^ KRK[CK2][1]; w3[2] = w2[2] ^ KRK[CK2][2]; w3[3] = w2[3] ^ KRK[CK2][3]; ARIA_FO(w3[0], w3[1], w3[2], w3[3]); w3[0] ^= w1[0]; w3[1] ^= w1[1]; w3[2] ^= w1[2]; w3[3] ^= w1[3]; if(length == 16) ERK.resize(4*13); else if(length == 24) ERK.resize(4*15); else if(length == 32) ERK.resize(4*17); ARIA_ROL128<19>(w0, w1, &ERK[ 0]); ARIA_ROL128<19>(w1, w2, &ERK[ 4]); ARIA_ROL128<19>(w2, w3, &ERK[ 8]); ARIA_ROL128<19>(w3, w0, &ERK[12]); ARIA_ROL128<31>(w0, w1, &ERK[16]); ARIA_ROL128<31>(w1, w2, &ERK[20]); ARIA_ROL128<31>(w2, w3, &ERK[24]); ARIA_ROL128<31>(w3, w0, &ERK[28]); ARIA_ROL128<67>(w0, w1, &ERK[32]); ARIA_ROL128<67>(w1, w2, &ERK[36]); ARIA_ROL128<67>(w2, w3, &ERK[40]); ARIA_ROL128<67>(w3, w0, &ERK[44]); ARIA_ROL128<97>(w0, w1, &ERK[48]); if(length == 24 || length == 32) { ARIA_ROL128<97>(w1, w2, &ERK[52]); ARIA_ROL128<97>(w2, w3, &ERK[56]); if(length == 32) { ARIA_ROL128< 97>(w3, w0, &ERK[60]); ARIA_ROL128<109>(w0, w1, &ERK[64]); } } // Now create the decryption key schedule DRK.resize(ERK.size()); for(size_t i = 0; i != DRK.size(); i += 4) { DRK[i ] = ERK[ERK.size()-4-i]; DRK[i+1] = ERK[ERK.size()-3-i]; DRK[i+2] = ERK[ERK.size()-2-i]; DRK[i+3] = ERK[ERK.size()-1-i]; } for(size_t i = 4; i != DRK.size() - 4; i += 4) { for(size_t j = 0; j != 4; ++j) { DRK[i+j] = rotr<8>(DRK[i+j]) ^ rotr<16>(DRK[i+j]) ^ rotr<24>(DRK[i+j]); } DRK[i+1] ^= DRK[i+2]; DRK[i+2] ^= DRK[i+3]; DRK[i+0] ^= DRK[i+1]; DRK[i+3] ^= DRK[i+1]; DRK[i+2] ^= DRK[i+0]; DRK[i+1] ^= DRK[i+2]; DRK[i+1] = ((DRK[i+1] << 8) & 0xFF00FF00) | ((DRK[i+1] >> 8) & 0x00FF00FF); DRK[i+2] = rotr<16>(DRK[i+2]); DRK[i+3] = reverse_bytes(DRK[i+3]); DRK[i+1] ^= DRK[i+2]; DRK[i+2] ^= DRK[i+3]; DRK[i+0] ^= DRK[i+1]; DRK[i+3] ^= DRK[i+1]; DRK[i+2] ^= DRK[i+0]; DRK[i+1] ^= DRK[i+2]; } } } } void ARIA_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_ERK.size() > 0); ARIA_F::transform(in, out, blocks, m_ERK); } void ARIA_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_ERK.size() > 0); ARIA_F::transform(in, out, blocks, m_ERK); } void ARIA_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_ERK.size() > 0); ARIA_F::transform(in, out, blocks, m_ERK); } void ARIA_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DRK.size() > 0); ARIA_F::transform(in, out, blocks, m_DRK); } void ARIA_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DRK.size() > 0); ARIA_F::transform(in, out, blocks, m_DRK); } void ARIA_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DRK.size() > 0); ARIA_F::transform(in, out, blocks, m_DRK); } void ARIA_128::key_schedule(const uint8_t key[], size_t length) { ARIA_F::key_schedule(m_ERK, m_DRK, key, length); } void ARIA_192::key_schedule(const uint8_t key[], size_t length) { ARIA_F::key_schedule(m_ERK, m_DRK, key, length); } void ARIA_256::key_schedule(const uint8_t key[], size_t length) { ARIA_F::key_schedule(m_ERK, m_DRK, key, length); } void ARIA_128::clear() { zap(m_ERK); zap(m_DRK); } void ARIA_192::clear() { zap(m_ERK); zap(m_DRK); } void ARIA_256::clear() { zap(m_ERK); zap(m_DRK); } } /* * Algorithm Identifier * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Create an AlgorithmIdentifier */ AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, const std::vector& param) : oid(alg_id), parameters(param) {} /* * Create an AlgorithmIdentifier */ AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, const std::vector& param) : AlgorithmIdentifier(OID::from_string(alg_id), param) {} /* * Create an AlgorithmIdentifier */ AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, Encoding_Option option) : oid(alg_id), parameters() { const uint8_t DER_NULL[] = { 0x05, 0x00 }; if(option == USE_NULL_PARAM) parameters.assign(DER_NULL, DER_NULL + 2); } /* * Create an AlgorithmIdentifier */ AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, Encoding_Option option) : oid(OID::from_string(alg_id)), parameters() { const uint8_t DER_NULL[] = { 0x05, 0x00 }; if(option == USE_NULL_PARAM) parameters.assign(DER_NULL, DER_NULL + 2); } bool AlgorithmIdentifier::parameters_are_null() const { return (parameters.size() == 2 && (parameters[0] == 0x05) && (parameters[1] == 0x00)); } bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) { if(a1.get_oid() != a2.get_oid()) return false; /* * Treat NULL and empty as equivalent */ if(a1.parameters_are_null_or_empty() && a2.parameters_are_null_or_empty()) { return true; } return (a1.get_parameters() == a2.get_parameters()); } bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) { return !(a1 == a2); } /* * DER encode an AlgorithmIdentifier */ void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const { codec.start_cons(SEQUENCE) .encode(get_oid()) .raw_bytes(get_parameters()) .end_cons(); } /* * Decode a BER encoded AlgorithmIdentifier */ void AlgorithmIdentifier::decode_from(BER_Decoder& codec) { codec.start_cons(SEQUENCE) .decode(oid) .raw_bytes(parameters) .end_cons(); } } /* * ASN.1 Internals * (C) 1999-2007,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::vector ASN1_Object::BER_encode() const { std::vector output; DER_Encoder der(output); this->encode_into(der); return output; } /* * Check a type invariant on BER data */ void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_, const std::string& descr) const { if(this->is_a(type_tag_, class_tag_) == false) { std::stringstream msg; msg << "Tag mismatch when decoding " << descr << " got "; if(class_tag == NO_OBJECT && type_tag == NO_OBJECT) { msg << "EOF"; } else { if(class_tag == UNIVERSAL || class_tag == CONSTRUCTED) { msg << asn1_tag_to_string(type_tag); } else { msg << std::to_string(type_tag); } msg << "/" << asn1_class_to_string(class_tag); } msg << " expected "; if(class_tag_ == UNIVERSAL || class_tag_ == CONSTRUCTED) { msg << asn1_tag_to_string(type_tag_); } else { msg << std::to_string(type_tag_); } msg << "/" << asn1_class_to_string(class_tag_); throw BER_Decoding_Error(msg.str()); } } bool BER_Object::is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const { return (type_tag == type_tag_ && class_tag == class_tag_); } bool BER_Object::is_a(int type_tag_, ASN1_Tag class_tag_) const { return is_a(ASN1_Tag(type_tag_), class_tag_); } void BER_Object::set_tagging(ASN1_Tag t, ASN1_Tag c) { type_tag = t; class_tag = c; } std::string asn1_class_to_string(ASN1_Tag type) { switch(type) { case UNIVERSAL: return "UNIVERSAL"; case CONSTRUCTED: return "CONSTRUCTED"; case CONTEXT_SPECIFIC: return "CONTEXT_SPECIFIC"; case APPLICATION: return "APPLICATION"; case CONSTRUCTED | CONTEXT_SPECIFIC: return "PRIVATE"; case Botan::NO_OBJECT: return "NO_OBJECT"; default: return "CLASS(" + std::to_string(static_cast(type)) + ")"; } } std::string asn1_tag_to_string(ASN1_Tag type) { switch(type) { case Botan::SEQUENCE: return "SEQUENCE"; case Botan::SET: return "SET"; case Botan::PRINTABLE_STRING: return "PRINTABLE STRING"; case Botan::NUMERIC_STRING: return "NUMERIC STRING"; case Botan::IA5_STRING: return "IA5 STRING"; case Botan::T61_STRING: return "T61 STRING"; case Botan::UTF8_STRING: return "UTF8 STRING"; case Botan::VISIBLE_STRING: return "VISIBLE STRING"; case Botan::BMP_STRING: return "BMP STRING"; case Botan::UNIVERSAL_STRING: return "UNIVERSAL STRING"; case Botan::UTC_TIME: return "UTC TIME"; case Botan::GENERALIZED_TIME: return "GENERALIZED TIME"; case Botan::OCTET_STRING: return "OCTET STRING"; case Botan::BIT_STRING: return "BIT STRING"; case Botan::ENUMERATED: return "ENUMERATED"; case Botan::INTEGER: return "INTEGER"; case Botan::NULL_TAG: return "NULL"; case Botan::OBJECT_ID: return "OBJECT"; case Botan::BOOLEAN: return "BOOLEAN"; case Botan::NO_OBJECT: return "NO_OBJECT"; default: return "TAG(" + std::to_string(static_cast(type)) + ")"; } } /* * BER Decoding Exceptions */ BER_Decoding_Error::BER_Decoding_Error(const std::string& str) : Decoding_Error("BER: " + str) {} BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) : BER_Decoding_Error(str + ": " + std::to_string(tag)) {} BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag1, ASN1_Tag tag2) : BER_Decoding_Error(str + ": " + std::to_string(tag1) + "/" + std::to_string(tag2)) {} namespace ASN1 { /* * Put some arbitrary bytes into a SEQUENCE */ std::vector put_in_sequence(const std::vector& contents) { return ASN1::put_in_sequence(contents.data(), contents.size()); } std::vector put_in_sequence(const uint8_t bits[], size_t len) { std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .raw_bytes(bits, len) .end_cons(); return output; } /* * Convert a BER object into a string object */ std::string to_string(const BER_Object& obj) { return std::string(cast_uint8_ptr_to_char(obj.bits()), obj.length()); } /* * Do heuristic tests for BER data */ bool maybe_BER(DataSource& source) { uint8_t first_u8; if(!source.peek_byte(first_u8)) { BOTAN_ASSERT_EQUAL(source.read_byte(first_u8), 0, "Expected EOF"); throw Stream_IO_Error("ASN1::maybe_BER: Source was empty"); } if(first_u8 == (SEQUENCE | CONSTRUCTED)) return true; return false; } } } /* * ASN.1 OID * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { // returns empty on invalid std::vector parse_oid_str(const std::string& oid) { try { std::string elem; std::vector oid_elems; for(char c : oid) { if(c == '.') { if(elem.empty()) return std::vector(); oid_elems.push_back(to_u32bit(elem)); elem.clear(); } else { elem += c; } } if(elem.empty()) return std::vector(); oid_elems.push_back(to_u32bit(elem)); if(oid_elems.size() < 2) return std::vector(); return oid_elems; } catch(Invalid_Argument&) // thrown by to_u32bit { return std::vector(); } } } //static OID OID::from_string(const std::string& str) { if(str.empty()) throw Invalid_Argument("OID::from_string argument must be non-empty"); const OID o = OIDS::str2oid_or_empty(str); if(o.has_value()) return o; std::vector raw = parse_oid_str(str); if(raw.size() > 0) return OID(std::move(raw)); throw Lookup_Error("No OID associated with name " + str); } /* * ASN.1 OID Constructor */ OID::OID(const std::string& oid_str) { if(!oid_str.empty()) { m_id = parse_oid_str(oid_str); if(m_id.size() < 2 || m_id[0] > 2) throw Invalid_OID(oid_str); if((m_id[0] == 0 || m_id[0] == 1) && m_id[1] > 39) throw Invalid_OID(oid_str); } } /* * Return this OID as a string */ std::string OID::to_string() const { std::ostringstream oss; oss.imbue(std::locale("C")); for(size_t i = 0; i != m_id.size(); ++i) { oss << m_id[i]; if(i != m_id.size() - 1) oss << "."; } return oss.str(); } std::string OID::to_formatted_string() const { const std::string s = OIDS::oid2str_or_empty(*this); if(!s.empty()) return s; return this->to_string(); } /* * Append another component to the OID */ OID operator+(const OID& oid, uint32_t new_component) { std::vector val = oid.get_components(); val.push_back(new_component); return OID(std::move(val)); } /* * Compare two OIDs */ bool operator<(const OID& a, const OID& b) { const std::vector& oid1 = a.get_components(); const std::vector& oid2 = b.get_components(); return std::lexicographical_compare(oid1.begin(), oid1.end(), oid2.begin(), oid2.end()); } /* * DER encode an OBJECT IDENTIFIER */ void OID::encode_into(DER_Encoder& der) const { if(m_id.size() < 2) throw Invalid_Argument("OID::encode_into: OID is invalid"); std::vector encoding; if(m_id[0] > 2 || m_id[1] >= 40) throw Encoding_Error("Invalid OID prefix, cannot encode"); encoding.push_back(static_cast(40 * m_id[0] + m_id[1])); for(size_t i = 2; i != m_id.size(); ++i) { if(m_id[i] == 0) encoding.push_back(0); else { size_t blocks = high_bit(m_id[i]) + 6; blocks = (blocks - (blocks % 7)) / 7; BOTAN_ASSERT(blocks > 0, "Math works"); for(size_t j = 0; j != blocks - 1; ++j) encoding.push_back(0x80 | ((m_id[i] >> 7*(blocks-j-1)) & 0x7F)); encoding.push_back(m_id[i] & 0x7F); } } der.add_object(OBJECT_ID, UNIVERSAL, encoding); } /* * Decode a BER encoded OBJECT IDENTIFIER */ void OID::decode_from(BER_Decoder& decoder) { BER_Object obj = decoder.get_next_object(); if(obj.tagging() != OBJECT_ID) throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging()); const size_t length = obj.length(); const uint8_t* bits = obj.bits(); if(length < 2 && !(length == 1 && bits[0] == 0)) { throw BER_Decoding_Error("OID encoding is too short"); } m_id.clear(); m_id.push_back(bits[0] / 40); m_id.push_back(bits[0] % 40); size_t i = 0; while(i != length - 1) { uint32_t component = 0; while(i != length - 1) { ++i; if(component >> (32-7)) throw Decoding_Error("OID component overflow"); component = (component << 7) + (bits[i] & 0x7F); if(!(bits[i] & 0x80)) break; } m_id.push_back(component); } } } /* * (C) 2014,2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include namespace Botan { namespace { bool all_printable_chars(const uint8_t bits[], size_t bits_len) { for(size_t i = 0; i != bits_len; ++i) { int c = bits[i]; if(c > 127) return false; if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false) return false; } return true; } /* * Special hack to handle GeneralName [2] and [6] (DNS name and URI) */ bool possibly_a_general_name(const uint8_t bits[], size_t bits_len) { if(bits_len <= 2) return false; if(bits[0] != 0x82 && bits[0] != 0x86) return false; if(bits[1] != bits_len - 2) return false; if(all_printable_chars(bits + 2, bits_len - 2) == false) return false; return true; } } std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const { std::ostringstream output; print_to_stream(output, in, len); return output.str(); } void ASN1_Formatter::print_to_stream(std::ostream& output, const uint8_t in[], size_t len) const { BER_Decoder dec(in, len); decode(output, dec, 0); } void ASN1_Formatter::decode(std::ostream& output, BER_Decoder& decoder, size_t level) const { BER_Object obj = decoder.get_next_object(); const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth); while(obj.is_set()) { const ASN1_Tag type_tag = obj.type(); const ASN1_Tag class_tag = obj.get_class(); const size_t length = obj.length(); /* hack to insert the tag+length back in front of the stuff now that we've gotten the type info */ std::vector bits; DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length()); BER_Decoder data(bits); if(class_tag & CONSTRUCTED) { BER_Decoder cons_info(obj.bits(), obj.length()); if(recurse_deeper) { output << format(type_tag, class_tag, level, length, ""); decode(output, cons_info, level + 1); // recurse } else { output << format(type_tag, class_tag, level, length, format_bin(type_tag, class_tag, bits)); } } else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC)) { bool success_parsing_cs = false; if(m_print_context_specific) { try { if(possibly_a_general_name(bits.data(), bits.size())) { output << format(type_tag, class_tag, level, level, std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2)); success_parsing_cs = true; } else if(recurse_deeper) { std::vector inner_bits; data.decode(inner_bits, type_tag); BER_Decoder inner(inner_bits); std::ostringstream inner_data; decode(inner_data, inner, level + 1); // recurse output << inner_data.str(); success_parsing_cs = true; } } catch(...) { } } if(success_parsing_cs == false) { output << format(type_tag, class_tag, level, length, format_bin(type_tag, class_tag, bits)); } } else if(type_tag == OBJECT_ID) { OID oid; data.decode(oid); std::string out = OIDS::oid2str_or_empty(oid); if(out.empty()) { out = oid.to_string(); } else { out += " [" + oid.to_string() + "]"; } output << format(type_tag, class_tag, level, length, out); } else if(type_tag == INTEGER || type_tag == ENUMERATED) { BigInt number; if(type_tag == INTEGER) { data.decode(number); } else if(type_tag == ENUMERATED) { data.decode(number, ENUMERATED, class_tag); } std::vector rep = BigInt::encode(number); if(rep.empty()) // if zero rep.resize(1); output << format(type_tag, class_tag, level, length, hex_encode(rep)); } else if(type_tag == BOOLEAN) { bool boolean; data.decode(boolean); output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false")); } else if(type_tag == NULL_TAG) { output << format(type_tag, class_tag, level, length, ""); } else if(type_tag == OCTET_STRING || type_tag == BIT_STRING) { std::vector decoded_bits; data.decode(decoded_bits, type_tag); bool printing_octet_string_worked = false; if(recurse_deeper) { try { BER_Decoder inner(decoded_bits); std::ostringstream inner_data; decode(inner_data, inner, level + 1); // recurse output << format(type_tag, class_tag, level, length, ""); output << inner_data.str(); printing_octet_string_worked = true; } catch(...) { } } if(!printing_octet_string_worked) { output << format(type_tag, class_tag, level, length, format_bin(type_tag, class_tag, decoded_bits)); } } else if(ASN1_String::is_string_type(type_tag)) { ASN1_String str; data.decode(str); output << format(type_tag, class_tag, level, length, str.value()); } else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME) { ASN1_Time time; data.decode(time); output << format(type_tag, class_tag, level, length, time.readable_string()); } else { output << "Unknown ASN.1 tag class=" << static_cast(class_tag) << " type=" << static_cast(type_tag) << "\n"; } obj = decoder.get_next_object(); } } namespace { std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag) { if(class_tag == UNIVERSAL) return asn1_tag_to_string(type_tag); if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET)) return asn1_tag_to_string(type_tag); std::string name; if(class_tag & CONSTRUCTED) name += "cons "; name += "[" + std::to_string(type_tag) + "]"; if(class_tag & APPLICATION) { name += " appl"; } if(class_tag & CONTEXT_SPECIFIC) { name += " context"; } return name; } } std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag, ASN1_Tag class_tag, size_t level, size_t length, const std::string& value) const { bool should_skip = false; if(value.length() > m_print_limit) { should_skip = true; } if((type_tag == OCTET_STRING || type_tag == BIT_STRING) && value.length() > m_print_binary_limit) { should_skip = true; } level += m_initial_level; std::ostringstream oss; oss << " d=" << std::setw(2) << level << ", l=" << std::setw(4) << length << ":" << std::string(level + 1, ' ') << format_type(type_tag, class_tag); if(value != "" && !should_skip) { const size_t current_pos = static_cast(oss.tellp()); const size_t spaces_to_align = (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos); oss << std::string(spaces_to_align, ' ') << value; } oss << "\n"; return oss.str(); } std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/, ASN1_Tag /*class_tag*/, const std::vector& vec) const { if(all_printable_chars(vec.data(), vec.size())) { return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size()); } else return hex_encode(vec); } } /* * Simple ASN.1 String Types * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Choose an encoding for the string */ ASN1_Tag choose_encoding(const std::string& str) { static const uint8_t IS_PRINTABLE[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; for(size_t i = 0; i != str.size(); ++i) { if(!IS_PRINTABLE[static_cast(str[i])]) { return UTF8_STRING; } } return PRINTABLE_STRING; } void assert_is_string_type(ASN1_Tag tag) { if(!ASN1_String::is_string_type(tag)) { throw Invalid_Argument("ASN1_String: Unknown string type " + std::to_string(tag)); } } } //static bool ASN1_String::is_string_type(ASN1_Tag tag) { return (tag == NUMERIC_STRING || tag == PRINTABLE_STRING || tag == VISIBLE_STRING || tag == T61_STRING || tag == IA5_STRING || tag == UTF8_STRING || tag == BMP_STRING || tag == UNIVERSAL_STRING); } /* * Create an ASN1_String */ ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : m_utf8_str(str), m_tag(t) { if(m_tag == DIRECTORY_STRING) { m_tag = choose_encoding(m_utf8_str); } assert_is_string_type(m_tag); } /* * Create an ASN1_String */ ASN1_String::ASN1_String(const std::string& str) : m_utf8_str(str), m_tag(choose_encoding(m_utf8_str)) {} /* * Return this string in ISO 8859-1 encoding */ std::string ASN1_String::iso_8859() const { return utf8_to_latin1(m_utf8_str); } /* * DER encode an ASN1_String */ void ASN1_String::encode_into(DER_Encoder& encoder) const { if(m_data.empty()) { encoder.add_object(tagging(), UNIVERSAL, m_utf8_str); } else { // If this string was decoded, reserialize using original encoding encoder.add_object(tagging(), UNIVERSAL, m_data.data(), m_data.size()); } } /* * Decode a BER encoded ASN1_String */ void ASN1_String::decode_from(BER_Decoder& source) { BER_Object obj = source.get_next_object(); assert_is_string_type(obj.type()); m_tag = obj.type(); m_data.assign(obj.bits(), obj.bits() + obj.length()); if(m_tag == BMP_STRING) { m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size()); } else if(m_tag == UNIVERSAL_STRING) { m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size()); } else { // All other supported string types are UTF-8 or some subset thereof m_utf8_str = ASN1::to_string(obj); } } } /* * X.509 Time Types * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { ASN1_Time::ASN1_Time(const std::chrono::system_clock::time_point& time) { calendar_point cal = calendar_value(time); m_year = cal.get_year(); m_month = cal.get_month(); m_day = cal.get_day(); m_hour = cal.get_hour(); m_minute = cal.get_minutes(); m_second = cal.get_seconds(); m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME; } ASN1_Time::ASN1_Time(const std::string& t_spec, ASN1_Tag tag) { set_to(t_spec, tag); } void ASN1_Time::encode_into(DER_Encoder& der) const { BOTAN_ARG_CHECK(m_tag == UTC_TIME || m_tag == GENERALIZED_TIME, "ASN1_Time: Bad encoding tag"); der.add_object(m_tag, UNIVERSAL, to_string()); } void ASN1_Time::decode_from(BER_Decoder& source) { BER_Object ber_time = source.get_next_object(); set_to(ASN1::to_string(ber_time), ber_time.type()); } std::string ASN1_Time::to_string() const { if(time_is_set() == false) throw Invalid_State("ASN1_Time::to_string: No time set"); uint32_t full_year = m_year; if(m_tag == UTC_TIME) { if(m_year < 1950 || m_year >= 2050) throw Encoding_Error("ASN1_Time: The time " + readable_string() + " cannot be encoded as a UTCTime"); full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900); } const uint64_t YEAR_FACTOR = 10000000000ULL; const uint64_t MON_FACTOR = 100000000; const uint64_t DAY_FACTOR = 1000000; const uint64_t HOUR_FACTOR = 10000; const uint64_t MIN_FACTOR = 100; const uint64_t int_repr = YEAR_FACTOR * full_year + MON_FACTOR * m_month + DAY_FACTOR * m_day + HOUR_FACTOR * m_hour + MIN_FACTOR * m_minute + m_second; std::string repr = std::to_string(int_repr) + "Z"; uint32_t desired_size = (m_tag == UTC_TIME) ? 13 : 15; while(repr.size() < desired_size) repr = "0" + repr; return repr; } std::string ASN1_Time::readable_string() const { if(time_is_set() == false) throw Invalid_State("ASN1_Time::readable_string: No time set"); // desired format: "%04d/%02d/%02d %02d:%02d:%02d UTC" std::stringstream output; output << std::setfill('0') << std::setw(4) << m_year << "/" << std::setw(2) << m_month << "/" << std::setw(2) << m_day << " " << std::setw(2) << m_hour << ":" << std::setw(2) << m_minute << ":" << std::setw(2) << m_second << " UTC"; return output.str(); } bool ASN1_Time::time_is_set() const { return (m_year != 0); } int32_t ASN1_Time::cmp(const ASN1_Time& other) const { if(time_is_set() == false) throw Invalid_State("ASN1_Time::cmp: No time set"); const int32_t EARLIER = -1, LATER = 1, SAME_TIME = 0; if(m_year < other.m_year) return EARLIER; if(m_year > other.m_year) return LATER; if(m_month < other.m_month) return EARLIER; if(m_month > other.m_month) return LATER; if(m_day < other.m_day) return EARLIER; if(m_day > other.m_day) return LATER; if(m_hour < other.m_hour) return EARLIER; if(m_hour > other.m_hour) return LATER; if(m_minute < other.m_minute) return EARLIER; if(m_minute > other.m_minute) return LATER; if(m_second < other.m_second) return EARLIER; if(m_second > other.m_second) return LATER; return SAME_TIME; } void ASN1_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) { if(spec_tag == UTC_OR_GENERALIZED_TIME) { try { set_to(t_spec, GENERALIZED_TIME); return; } catch(Invalid_Argument&) {} // Not a generalized time. Continue try { set_to(t_spec, UTC_TIME); return; } catch(Invalid_Argument&) {} // Not a UTC time. Continue throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime."); } BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag."); BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty."); BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z"); if(spec_tag == GENERALIZED_TIME) { BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string"); } else if(spec_tag == UTC_TIME) { BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string"); } const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4; std::vector params; std::string current; for(size_t j = 0; j != YEAR_SIZE; ++j) current += t_spec[j]; params.push_back(current); current.clear(); for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j) { current += t_spec[j]; if(current.size() == 2) { params.push_back(current); current.clear(); } } m_year = to_u32bit(params[0]); m_month = to_u32bit(params[1]); m_day = to_u32bit(params[2]); m_hour = to_u32bit(params[3]); m_minute = to_u32bit(params[4]); m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0; m_tag = spec_tag; if(spec_tag == UTC_TIME) { if(m_year >= 50) m_year += 1900; else m_year += 2000; } if(!passes_sanity_check()) throw Invalid_Argument("Time " + t_spec + " does not seem to be valid"); } /* * Do a general sanity check on the time */ bool ASN1_Time::passes_sanity_check() const { // AppVeyor's trust store includes a cert with expiration date in 3016 ... if(m_year < 1950 || m_year > 3100) return false; if(m_month == 0 || m_month > 12) return false; const uint32_t days_in_month[12] = { 31, 28+1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if(m_day == 0 || m_day > days_in_month[m_month-1]) return false; if(m_month == 2 && m_day == 29) { if(m_year % 4 != 0) return false; // not a leap year if(m_year % 100 == 0 && m_year % 400 != 0) return false; } if(m_hour >= 24 || m_minute >= 60 || m_second > 60) return false; if (m_tag == UTC_TIME) { /* UTCTime limits the value of components such that leap seconds are not covered. See "UNIVERSAL 23" in "Information technology Abstract Syntax Notation One (ASN.1): Specification of basic notation" http://www.itu.int/ITU-T/studygroups/com17/languages/ */ if(m_second > 59) { return false; } } return true; } std::chrono::system_clock::time_point ASN1_Time::to_std_timepoint() const { return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint(); } uint64_t ASN1_Time::time_since_epoch() const { auto tp = this->to_std_timepoint(); return std::chrono::duration_cast(tp.time_since_epoch()).count(); } /* * Compare two ASN1_Times for in various ways */ bool operator==(const ASN1_Time& t1, const ASN1_Time& t2) { return (t1.cmp(t2) == 0); } bool operator!=(const ASN1_Time& t1, const ASN1_Time& t2) { return (t1.cmp(t2) != 0); } bool operator<=(const ASN1_Time& t1, const ASN1_Time& t2) { return (t1.cmp(t2) <= 0); } bool operator>=(const ASN1_Time& t1, const ASN1_Time& t2) { return (t1.cmp(t2) >= 0); } bool operator<(const ASN1_Time& t1, const ASN1_Time& t2) { return (t1.cmp(t2) < 0); } bool operator>(const ASN1_Time& t1, const ASN1_Time& t2) { return (t1.cmp(t2) > 0); } } /* * BER Decoder * (C) 1999-2008,2015,2017,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * This value is somewhat arbitrary. OpenSSL allows up to 128 nested * indefinite length sequences. If you increase this, also increase the * limit in the test in test_asn1.cpp */ const size_t ALLOWED_EOC_NESTINGS = 16; /* * BER decode an ASN.1 type tag */ size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag) { uint8_t b; if(!ber->read_byte(b)) { class_tag = type_tag = NO_OBJECT; return 0; } if((b & 0x1F) != 0x1F) { type_tag = ASN1_Tag(b & 0x1F); class_tag = ASN1_Tag(b & 0xE0); return 1; } size_t tag_bytes = 1; class_tag = ASN1_Tag(b & 0xE0); size_t tag_buf = 0; while(true) { if(!ber->read_byte(b)) throw BER_Decoding_Error("Long-form tag truncated"); if(tag_buf & 0xFF000000) throw BER_Decoding_Error("Long-form tag overflowed 32 bits"); ++tag_bytes; tag_buf = (tag_buf << 7) | (b & 0x7F); if((b & 0x80) == 0) break; } type_tag = ASN1_Tag(tag_buf); return tag_bytes; } /* * Find the EOC marker */ size_t find_eoc(DataSource* src, size_t allow_indef); /* * BER decode an ASN.1 length field */ size_t decode_length(DataSource* ber, size_t& field_size, size_t allow_indef) { uint8_t b; if(!ber->read_byte(b)) throw BER_Decoding_Error("Length field not found"); field_size = 1; if((b & 0x80) == 0) return b; field_size += (b & 0x7F); if(field_size > 5) throw BER_Decoding_Error("Length field is too large"); if(field_size == 1) { if(allow_indef == 0) { throw BER_Decoding_Error("Nested EOC markers too deep, rejecting to avoid stack exhaustion"); } else { return find_eoc(ber, allow_indef - 1); } } size_t length = 0; for(size_t i = 0; i != field_size - 1; ++i) { if(get_byte(0, length) != 0) throw BER_Decoding_Error("Field length overflow"); if(!ber->read_byte(b)) throw BER_Decoding_Error("Corrupted length field"); length = (length << 8) | b; } return length; } /* * Find the EOC marker */ size_t find_eoc(DataSource* ber, size_t allow_indef) { secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE), data; while(true) { const size_t got = ber->peek(buffer.data(), buffer.size(), data.size()); if(got == 0) break; data += std::make_pair(buffer.data(), got); } DataSource_Memory source(data); data.clear(); size_t length = 0; while(true) { ASN1_Tag type_tag, class_tag; size_t tag_size = decode_tag(&source, type_tag, class_tag); if(type_tag == NO_OBJECT) break; size_t length_size = 0; size_t item_size = decode_length(&source, length_size, allow_indef); source.discard_next(item_size); length = BOTAN_CHECKED_ADD(length, item_size); length = BOTAN_CHECKED_ADD(length, tag_size); length = BOTAN_CHECKED_ADD(length, length_size); if(type_tag == EOC && class_tag == UNIVERSAL) break; } return length; } class DataSource_BERObject final : public DataSource { public: size_t read(uint8_t out[], size_t length) override { BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); const size_t got = std::min(m_obj.length() - m_offset, length); copy_mem(out, m_obj.bits() + m_offset, got); m_offset += got; return got; } size_t peek(uint8_t out[], size_t length, size_t peek_offset) const override { BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); const size_t bytes_left = m_obj.length() - m_offset; if(peek_offset >= bytes_left) return 0; const size_t got = std::min(bytes_left - peek_offset, length); copy_mem(out, m_obj.bits() + peek_offset, got); return got; } bool check_available(size_t n) override { BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); return (n <= (m_obj.length() - m_offset)); } bool end_of_data() const override { return get_bytes_read() == m_obj.length(); } size_t get_bytes_read() const override { return m_offset; } explicit DataSource_BERObject(BER_Object&& obj) : m_obj(std::move(obj)), m_offset(0) {} private: BER_Object m_obj; size_t m_offset; }; } /* * Check if more objects are there */ bool BER_Decoder::more_items() const { if(m_source->end_of_data() && !m_pushed.is_set()) return false; return true; } /* * Verify that no bytes remain in the source */ BER_Decoder& BER_Decoder::verify_end() { return verify_end("BER_Decoder::verify_end called, but data remains"); } /* * Verify that no bytes remain in the source */ BER_Decoder& BER_Decoder::verify_end(const std::string& err) { if(!m_source->end_of_data() || m_pushed.is_set()) throw Decoding_Error(err); return (*this); } /* * Discard all the bytes remaining in the source */ BER_Decoder& BER_Decoder::discard_remaining() { uint8_t buf; while(m_source->read_byte(buf)) {} return (*this); } /* * Return the BER encoding of the next object */ BER_Object BER_Decoder::get_next_object() { BER_Object next; if(m_pushed.is_set()) { std::swap(next, m_pushed); return next; } for(;;) { ASN1_Tag type_tag, class_tag; decode_tag(m_source, type_tag, class_tag); next.set_tagging(type_tag, class_tag); if(next.is_set() == false) // no more objects return next; size_t field_size; const size_t length = decode_length(m_source, field_size, ALLOWED_EOC_NESTINGS); if(!m_source->check_available(length)) throw BER_Decoding_Error("Value truncated"); uint8_t* out = next.mutable_bits(length); if(m_source->read(out, length) != length) throw BER_Decoding_Error("Value truncated"); if(next.tagging() == EOC) continue; else break; } return next; } /* * Push a object back into the stream */ void BER_Decoder::push_back(const BER_Object& obj) { if(m_pushed.is_set()) throw Invalid_State("BER_Decoder: Only one push back is allowed"); m_pushed = obj; } void BER_Decoder::push_back(BER_Object&& obj) { if(m_pushed.is_set()) throw Invalid_State("BER_Decoder: Only one push back is allowed"); m_pushed = std::move(obj); } BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag) { BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); return BER_Decoder(std::move(obj), this); } /* * Finish decoding a CONSTRUCTED type */ BER_Decoder& BER_Decoder::end_cons() { if(!m_parent) throw Invalid_State("BER_Decoder::end_cons called with null parent"); if(!m_source->end_of_data()) throw Decoding_Error("BER_Decoder::end_cons called with data left"); return (*m_parent); } BER_Decoder::BER_Decoder(BER_Object&& obj, BER_Decoder* parent) { m_data_src.reset(new DataSource_BERObject(std::move(obj))); m_source = m_data_src.get(); m_parent = parent; } /* * BER_Decoder Constructor */ BER_Decoder::BER_Decoder(DataSource& src) { m_source = &src; } /* * BER_Decoder Constructor */ BER_Decoder::BER_Decoder(const uint8_t data[], size_t length) { m_data_src.reset(new DataSource_Memory(data, length)); m_source = m_data_src.get(); } /* * BER_Decoder Constructor */ BER_Decoder::BER_Decoder(const secure_vector& data) { m_data_src.reset(new DataSource_Memory(data)); m_source = m_data_src.get(); } /* * BER_Decoder Constructor */ BER_Decoder::BER_Decoder(const std::vector& data) { m_data_src.reset(new DataSource_Memory(data.data(), data.size())); m_source = m_data_src.get(); } /* * BER_Decoder Copy Constructor */ BER_Decoder::BER_Decoder(const BER_Decoder& other) { m_source = other.m_source; // take ownership std::swap(m_data_src, other.m_data_src); m_parent = other.m_parent; } /* * Request for an object to decode itself */ BER_Decoder& BER_Decoder::decode(ASN1_Object& obj, ASN1_Tag, ASN1_Tag) { obj.decode_from(*this); return (*this); } /* * Decode a BER encoded NULL */ BER_Decoder& BER_Decoder::decode_null() { BER_Object obj = get_next_object(); obj.assert_is_a(NULL_TAG, UNIVERSAL); if(obj.length() > 0) throw BER_Decoding_Error("NULL object had nonzero size"); return (*this); } BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) { secure_vector out_vec; decode(out_vec, OCTET_STRING); out = BigInt::decode(out_vec.data(), out_vec.size()); return (*this); } /* * Decode a BER encoded BOOLEAN */ BER_Decoder& BER_Decoder::decode(bool& out, ASN1_Tag type_tag, ASN1_Tag class_tag) { BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, class_tag); if(obj.length() != 1) throw BER_Decoding_Error("BER boolean value had invalid size"); out = (obj.bits()[0]) ? true : false; return (*this); } /* * Decode a small BER encoded INTEGER */ BER_Decoder& BER_Decoder::decode(size_t& out, ASN1_Tag type_tag, ASN1_Tag class_tag) { BigInt integer; decode(integer, type_tag, class_tag); if(integer.is_negative()) throw BER_Decoding_Error("Decoded small integer value was negative"); if(integer.bits() > 32) throw BER_Decoding_Error("Decoded integer value larger than expected"); out = 0; for(size_t i = 0; i != 4; ++i) out = (out << 8) | integer.byte_at(3-i); return (*this); } /* * Decode a small BER encoded INTEGER */ uint64_t BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag, ASN1_Tag class_tag, size_t T_bytes) { if(T_bytes > 8) throw BER_Decoding_Error("Can't decode small integer over 8 bytes"); BigInt integer; decode(integer, type_tag, class_tag); if(integer.bits() > 8*T_bytes) throw BER_Decoding_Error("Decoded integer value larger than expected"); uint64_t out = 0; for(size_t i = 0; i != 8; ++i) out = (out << 8) | integer.byte_at(7-i); return out; } /* * Decode a BER encoded INTEGER */ BER_Decoder& BER_Decoder::decode(BigInt& out, ASN1_Tag type_tag, ASN1_Tag class_tag) { BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, class_tag); if(obj.length() == 0) { out = 0; } else { const bool negative = (obj.bits()[0] & 0x80) ? true : false; if(negative) { secure_vector vec(obj.bits(), obj.bits() + obj.length()); for(size_t i = obj.length(); i > 0; --i) if(vec[i-1]--) break; for(size_t i = 0; i != obj.length(); ++i) vec[i] = ~vec[i]; out = BigInt(vec.data(), vec.size()); out.flip_sign(); } else { out = BigInt(obj.bits(), obj.length()); } } return (*this); } namespace { template void asn1_decode_binary_string(std::vector& buffer, const BER_Object& obj, ASN1_Tag real_type, ASN1_Tag type_tag, ASN1_Tag class_tag) { obj.assert_is_a(type_tag, class_tag); if(real_type == OCTET_STRING) { buffer.assign(obj.bits(), obj.bits() + obj.length()); } else { if(obj.length() == 0) throw BER_Decoding_Error("Invalid BIT STRING"); if(obj.bits()[0] >= 8) throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); buffer.resize(obj.length() - 1); if(obj.length() > 1) copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1); } } } /* * BER decode a BIT STRING or OCTET STRING */ BER_Decoder& BER_Decoder::decode(secure_vector& buffer, ASN1_Tag real_type, ASN1_Tag type_tag, ASN1_Tag class_tag) { if(real_type != OCTET_STRING && real_type != BIT_STRING) throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag); return (*this); } BER_Decoder& BER_Decoder::decode(std::vector& buffer, ASN1_Tag real_type, ASN1_Tag type_tag, ASN1_Tag class_tag) { if(real_type != OCTET_STRING && real_type != BIT_STRING) throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag); return (*this); } } /* * DER Encoder * (C) 1999-2007,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * DER encode an ASN.1 type tag */ void encode_tag(std::vector& encoded_tag, ASN1_Tag type_tag, ASN1_Tag class_tag) { if((class_tag | 0xE0) != 0xE0) throw Encoding_Error("DER_Encoder: Invalid class tag " + std::to_string(class_tag)); if(type_tag <= 30) { encoded_tag.push_back(static_cast(type_tag | class_tag)); } else { size_t blocks = high_bit(static_cast(type_tag)) + 6; blocks = (blocks - (blocks % 7)) / 7; BOTAN_ASSERT_NOMSG(blocks > 0); encoded_tag.push_back(static_cast(class_tag | 0x1F)); for(size_t i = 0; i != blocks - 1; ++i) encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F)); encoded_tag.push_back(type_tag & 0x7F); } } /* * DER encode an ASN.1 length field */ void encode_length(std::vector& encoded_length, size_t length) { if(length <= 127) { encoded_length.push_back(static_cast(length)); } else { const size_t bytes_needed = significant_bytes(length); encoded_length.push_back(static_cast(0x80 | bytes_needed)); for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i) encoded_length.push_back(get_byte(i, length)); } } } DER_Encoder::DER_Encoder(secure_vector& vec) { m_append_output = [&vec](const uint8_t b[], size_t l) { vec.insert(vec.end(), b, b + l); }; } DER_Encoder::DER_Encoder(std::vector& vec) { m_append_output = [&vec](const uint8_t b[], size_t l) { vec.insert(vec.end(), b, b + l); }; } /* * Push the encoded SEQUENCE/SET to the encoder stream */ void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der) { const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag | CONSTRUCTED); if(m_type_tag == SET) { std::sort(m_set_contents.begin(), m_set_contents.end()); for(size_t i = 0; i != m_set_contents.size(); ++i) m_contents += m_set_contents[i]; m_set_contents.clear(); } der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size()); m_contents.clear(); } /* * Add an encoded value to the SEQUENCE/SET */ void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length) { if(m_type_tag == SET) m_set_contents.push_back(secure_vector(data, data + length)); else m_contents += std::make_pair(data, length); } void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len, const uint8_t val[], size_t val_len) { if(m_type_tag == SET) { secure_vector m; m.reserve(hdr_len + val_len); m += std::make_pair(hdr, hdr_len); m += std::make_pair(val, val_len); m_set_contents.push_back(std::move(m)); } else { m_contents += std::make_pair(hdr, hdr_len); m_contents += std::make_pair(val, val_len); } } /* * Return the type and class taggings */ ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const { return ASN1_Tag(m_type_tag | m_class_tag); } /* * DER_Sequence Constructor */ DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) : m_type_tag(t1), m_class_tag(t2) { } /* * Return the encoded contents */ secure_vector DER_Encoder::get_contents() { if(m_subsequences.size() != 0) throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); if(m_append_output) throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); secure_vector output; std::swap(output, m_default_outbuf); return output; } std::vector DER_Encoder::get_contents_unlocked() { if(m_subsequences.size() != 0) throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); if(m_append_output) throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); std::vector output(m_default_outbuf.begin(), m_default_outbuf.end()); m_default_outbuf.clear(); return output; } /* * Start a new ASN.1 SEQUENCE/SET/EXPLICIT */ DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag) { m_subsequences.push_back(DER_Sequence(type_tag, class_tag)); return (*this); } /* * Finish the current ASN.1 SEQUENCE/SET/EXPLICIT */ DER_Encoder& DER_Encoder::end_cons() { if(m_subsequences.empty()) throw Invalid_State("DER_Encoder::end_cons: No such sequence"); DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size()-1]); m_subsequences.pop_back(); last_seq.push_contents(*this); return (*this); } /* * Start a new ASN.1 EXPLICIT encoding */ DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no) { ASN1_Tag type_tag = static_cast(type_no); // This would confuse DER_Sequence if(type_tag == SET) throw Internal_Error("DER_Encoder.start_explicit(SET) not supported"); return start_cons(type_tag, CONTEXT_SPECIFIC); } /* * Finish the current ASN.1 EXPLICIT encoding */ DER_Encoder& DER_Encoder::end_explicit() { return end_cons(); } /* * Write raw bytes into the stream */ DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length) { if(m_subsequences.size()) { m_subsequences[m_subsequences.size()-1].add_bytes(bytes, length); } else if(m_append_output) { m_append_output(bytes, length); } else { m_default_outbuf += std::make_pair(bytes, length); } return (*this); } /* * Write the encoding of the byte(s) */ DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const uint8_t rep[], size_t length) { std::vector hdr; encode_tag(hdr, type_tag, class_tag); encode_length(hdr, length); if(m_subsequences.size()) { m_subsequences[m_subsequences.size()-1].add_bytes(hdr.data(), hdr.size(), rep, length); } else if(m_append_output) { m_append_output(hdr.data(), hdr.size()); m_append_output(rep, length); } else { m_default_outbuf += hdr; m_default_outbuf += std::make_pair(rep, length); } return (*this); } /* * Encode a NULL object */ DER_Encoder& DER_Encoder::encode_null() { return add_object(NULL_TAG, UNIVERSAL, nullptr, 0); } /* * DER encode a BOOLEAN */ DER_Encoder& DER_Encoder::encode(bool is_true) { return encode(is_true, BOOLEAN, UNIVERSAL); } /* * DER encode a small INTEGER */ DER_Encoder& DER_Encoder::encode(size_t n) { return encode(BigInt(n), INTEGER, UNIVERSAL); } /* * DER encode a small INTEGER */ DER_Encoder& DER_Encoder::encode(const BigInt& n) { return encode(n, INTEGER, UNIVERSAL); } /* * Encode this object */ DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, ASN1_Tag real_type) { return encode(bytes, length, real_type, real_type, UNIVERSAL); } /* * DER encode a BOOLEAN */ DER_Encoder& DER_Encoder::encode(bool is_true, ASN1_Tag type_tag, ASN1_Tag class_tag) { uint8_t val = is_true ? 0xFF : 0x00; return add_object(type_tag, class_tag, &val, 1); } /* * DER encode a small INTEGER */ DER_Encoder& DER_Encoder::encode(size_t n, ASN1_Tag type_tag, ASN1_Tag class_tag) { return encode(BigInt(n), type_tag, class_tag); } /* * DER encode an INTEGER */ DER_Encoder& DER_Encoder::encode(const BigInt& n, ASN1_Tag type_tag, ASN1_Tag class_tag) { if(n == 0) return add_object(type_tag, class_tag, 0); const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0; secure_vector contents(extra_zero + n.bytes()); n.binary_encode(&contents[extra_zero]); if(n < 0) { for(size_t i = 0; i != contents.size(); ++i) contents[i] = ~contents[i]; for(size_t i = contents.size(); i > 0; --i) if(++contents[i-1]) break; } return add_object(type_tag, class_tag, contents); } /* * DER encode an OCTET STRING or BIT STRING */ DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, ASN1_Tag real_type, ASN1_Tag type_tag, ASN1_Tag class_tag) { if(real_type != OCTET_STRING && real_type != BIT_STRING) throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string"); if(real_type == BIT_STRING) { secure_vector encoded; encoded.push_back(0); encoded += std::make_pair(bytes, length); return add_object(type_tag, class_tag, encoded); } else return add_object(type_tag, class_tag, bytes, length); } DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) { obj.encode_into(*this); return (*this); } /* * Write the encoding of the byte(s) */ DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const std::string& rep_str) { const uint8_t* rep = cast_char_ptr_to_uint8(rep_str.data()); const size_t rep_len = rep_str.size(); return add_object(type_tag, class_tag, rep, rep_len); } /* * Write the encoding of the byte */ DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, uint8_t rep) { return add_object(type_tag, class_tag, &rep, 1); } } /* * OID maps * * This file was automatically generated by ./src/scripts/oids.py on 2019-10-21 * * All manual edits to this file will be lost. Edit the script * then regenerate this source file. * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { std::unordered_map OIDS::load_oid2str_map() { return std::unordered_map{ { "0.3.4401.5.3.1.9.26", "Camellia-192/GCM" }, { "0.3.4401.5.3.1.9.46", "Camellia-256/GCM" }, { "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" }, { "0.4.0.127.0.15.1.1.13.0", "XMSS" }, { "1.0.14888.3.0.5", "ECKCDSA" }, { "1.2.156.10197.1.104.100", "SM4/OCB" }, { "1.2.156.10197.1.104.2", "SM4/CBC" }, { "1.2.156.10197.1.104.8", "SM4/GCM" }, { "1.2.156.10197.1.301", "sm2p256v1" }, { "1.2.156.10197.1.301.1", "SM2" }, { "1.2.156.10197.1.301.2", "SM2_Kex" }, { "1.2.156.10197.1.301.3", "SM2_Enc" }, { "1.2.156.10197.1.401", "SM3" }, { "1.2.156.10197.1.501", "SM2_Sig/SM3" }, { "1.2.156.10197.1.504", "RSA/EMSA3(SM3)" }, { "1.2.250.1.223.101.256.1", "frp256v1" }, { "1.2.392.200011.61.1.1.1.2", "Camellia-128/CBC" }, { "1.2.392.200011.61.1.1.1.3", "Camellia-192/CBC" }, { "1.2.392.200011.61.1.1.1.4", "Camellia-256/CBC" }, { "1.2.410.200004.1.100.4.3", "ECKCDSA/EMSA1(SHA-1)" }, { "1.2.410.200004.1.100.4.4", "ECKCDSA/EMSA1(SHA-224)" }, { "1.2.410.200004.1.100.4.5", "ECKCDSA/EMSA1(SHA-256)" }, { "1.2.410.200004.1.4", "SEED/CBC" }, { "1.2.643.100.1", "GOST.OGRN" }, { "1.2.643.100.111", "GOST.SubjectSigningTool" }, { "1.2.643.100.112", "GOST.IssuerSigningTool" }, { "1.2.643.2.2.19", "GOST-34.10" }, { "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)" }, { "1.2.643.2.2.35.1", "gost_256A" }, { "1.2.643.2.2.36.0", "gost_256A" }, { "1.2.643.3.131.1.1", "GOST.INN" }, { "1.2.643.7.1.1.1.1", "GOST-34.10-2012-256" }, { "1.2.643.7.1.1.1.2", "GOST-34.10-2012-512" }, { "1.2.643.7.1.1.2.2", "Streebog-256" }, { "1.2.643.7.1.1.2.3", "Streebog-512" }, { "1.2.643.7.1.1.3.2", "GOST-34.10-2012-256/EMSA1(Streebog-256)" }, { "1.2.643.7.1.1.3.3", "GOST-34.10-2012-512/EMSA1(Streebog-512)" }, { "1.2.643.7.1.2.1.1.1", "gost_256A" }, { "1.2.643.7.1.2.1.1.2", "gost_256B" }, { "1.2.643.7.1.2.1.2.1", "gost_512A" }, { "1.2.643.7.1.2.1.2.2", "gost_512B" }, { "1.2.840.10040.4.1", "DSA" }, { "1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)" }, { "1.2.840.10045.2.1", "ECDSA" }, { "1.2.840.10045.3.1.1", "secp192r1" }, { "1.2.840.10045.3.1.2", "x962_p192v2" }, { "1.2.840.10045.3.1.3", "x962_p192v3" }, { "1.2.840.10045.3.1.4", "x962_p239v1" }, { "1.2.840.10045.3.1.5", "x962_p239v2" }, { "1.2.840.10045.3.1.6", "x962_p239v3" }, { "1.2.840.10045.3.1.7", "secp256r1" }, { "1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)" }, { "1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)" }, { "1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)" }, { "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)" }, { "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)" }, { "1.2.840.10046.2.1", "DH" }, { "1.2.840.113533.7.66.10", "CAST-128/CBC" }, { "1.2.840.113533.7.66.15", "KeyWrap.CAST-128" }, { "1.2.840.113549.1.1.1", "RSA" }, { "1.2.840.113549.1.1.10", "RSA/EMSA4" }, { "1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)" }, { "1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)" }, { "1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)" }, { "1.2.840.113549.1.1.14", "RSA/EMSA3(SHA-224)" }, { "1.2.840.113549.1.1.16", "RSA/EMSA3(SHA-512-256)" }, { "1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)" }, { "1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)" }, { "1.2.840.113549.1.1.7", "RSA/OAEP" }, { "1.2.840.113549.1.1.8", "MGF1" }, { "1.2.840.113549.1.5.12", "PKCS5.PBKDF2" }, { "1.2.840.113549.1.5.13", "PBE-PKCS5v20" }, { "1.2.840.113549.1.9.1", "PKCS9.EmailAddress" }, { "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest" }, { "1.2.840.113549.1.9.16.3.18", "ChaCha20Poly1305" }, { "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES" }, { "1.2.840.113549.1.9.16.3.8", "Compression.Zlib" }, { "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" }, { "1.2.840.113549.1.9.3", "PKCS9.ContentType" }, { "1.2.840.113549.1.9.4", "PKCS9.MessageDigest" }, { "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword" }, { "1.2.840.113549.2.10", "HMAC(SHA-384)" }, { "1.2.840.113549.2.11", "HMAC(SHA-512)" }, { "1.2.840.113549.2.13", "HMAC(SHA-512-256)" }, { "1.2.840.113549.2.5", "MD5" }, { "1.2.840.113549.2.7", "HMAC(SHA-160)" }, { "1.2.840.113549.2.8", "HMAC(SHA-224)" }, { "1.2.840.113549.2.9", "HMAC(SHA-256)" }, { "1.2.840.113549.3.7", "TripleDES/CBC" }, { "1.3.101.110", "Curve25519" }, { "1.3.101.112", "Ed25519" }, { "1.3.132.0.10", "secp256k1" }, { "1.3.132.0.30", "secp160r2" }, { "1.3.132.0.31", "secp192k1" }, { "1.3.132.0.32", "secp224k1" }, { "1.3.132.0.33", "secp224r1" }, { "1.3.132.0.34", "secp384r1" }, { "1.3.132.0.35", "secp521r1" }, { "1.3.132.0.8", "secp160r1" }, { "1.3.132.0.9", "secp160k1" }, { "1.3.132.1.12", "ECDH" }, { "1.3.14.3.2.26", "SHA-160" }, { "1.3.14.3.2.7", "DES/CBC" }, { "1.3.36.3.2.1", "RIPEMD-160" }, { "1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)" }, { "1.3.36.3.3.2.5.2.1", "ECGDSA" }, { "1.3.36.3.3.2.5.4.1", "ECGDSA/EMSA1(RIPEMD-160)" }, { "1.3.36.3.3.2.5.4.2", "ECGDSA/EMSA1(SHA-160)" }, { "1.3.36.3.3.2.5.4.3", "ECGDSA/EMSA1(SHA-224)" }, { "1.3.36.3.3.2.5.4.4", "ECGDSA/EMSA1(SHA-256)" }, { "1.3.36.3.3.2.5.4.5", "ECGDSA/EMSA1(SHA-384)" }, { "1.3.36.3.3.2.5.4.6", "ECGDSA/EMSA1(SHA-512)" }, { "1.3.36.3.3.2.8.1.1.1", "brainpool160r1" }, { "1.3.36.3.3.2.8.1.1.11", "brainpool384r1" }, { "1.3.36.3.3.2.8.1.1.13", "brainpool512r1" }, { "1.3.36.3.3.2.8.1.1.3", "brainpool192r1" }, { "1.3.36.3.3.2.8.1.1.5", "brainpool224r1" }, { "1.3.36.3.3.2.8.1.1.7", "brainpool256r1" }, { "1.3.36.3.3.2.8.1.1.9", "brainpool320r1" }, { "1.3.6.1.4.1.11591.12.2", "Tiger(24,3)" }, { "1.3.6.1.4.1.11591.15.1", "OpenPGP.Ed25519" }, { "1.3.6.1.4.1.11591.4.11", "Scrypt" }, { "1.3.6.1.4.1.25258.1.3", "McEliece" }, { "1.3.6.1.4.1.25258.1.5", "XMSS-draft6" }, { "1.3.6.1.4.1.25258.1.6.1", "GOST-34.10-2012-256/EMSA1(SHA-256)" }, { "1.3.6.1.4.1.25258.1.8", "XMSS-draft12" }, { "1.3.6.1.4.1.25258.3.1", "Serpent/CBC" }, { "1.3.6.1.4.1.25258.3.101", "Serpent/GCM" }, { "1.3.6.1.4.1.25258.3.102", "Twofish/GCM" }, { "1.3.6.1.4.1.25258.3.2", "Threefish-512/CBC" }, { "1.3.6.1.4.1.25258.3.2.1", "AES-128/OCB" }, { "1.3.6.1.4.1.25258.3.2.2", "AES-192/OCB" }, { "1.3.6.1.4.1.25258.3.2.3", "AES-256/OCB" }, { "1.3.6.1.4.1.25258.3.2.4", "Serpent/OCB" }, { "1.3.6.1.4.1.25258.3.2.5", "Twofish/OCB" }, { "1.3.6.1.4.1.25258.3.2.6", "Camellia-128/OCB" }, { "1.3.6.1.4.1.25258.3.2.7", "Camellia-192/OCB" }, { "1.3.6.1.4.1.25258.3.2.8", "Camellia-256/OCB" }, { "1.3.6.1.4.1.25258.3.3", "Twofish/CBC" }, { "1.3.6.1.4.1.25258.3.4.1", "AES-128/SIV" }, { "1.3.6.1.4.1.25258.3.4.2", "AES-192/SIV" }, { "1.3.6.1.4.1.25258.3.4.3", "AES-256/SIV" }, { "1.3.6.1.4.1.25258.3.4.4", "Serpent/SIV" }, { "1.3.6.1.4.1.25258.3.4.5", "Twofish/SIV" }, { "1.3.6.1.4.1.25258.3.4.6", "Camellia-128/SIV" }, { "1.3.6.1.4.1.25258.3.4.7", "Camellia-192/SIV" }, { "1.3.6.1.4.1.25258.3.4.8", "Camellia-256/SIV" }, { "1.3.6.1.4.1.25258.3.4.9", "SM4/SIV" }, { "1.3.6.1.4.1.3029.1.2.1", "ElGamal" }, { "1.3.6.1.4.1.3029.1.5.1", "OpenPGP.Curve25519" }, { "1.3.6.1.4.1.311.20.2.2", "Microsoft SmartcardLogon" }, { "1.3.6.1.4.1.311.20.2.3", "Microsoft UPN" }, { "1.3.6.1.4.1.8301.3.1.2.9.0.38", "secp521r1" }, { "1.3.6.1.5.5.7.1.1", "PKIX.AuthorityInformationAccess" }, { "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth" }, { "1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth" }, { "1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning" }, { "1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection" }, { "1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem" }, { "1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel" }, { "1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser" }, { "1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping" }, { "1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning" }, { "1.3.6.1.5.5.7.48.1", "PKIX.OCSP" }, { "1.3.6.1.5.5.7.48.1.1", "PKIX.OCSP.BasicResponse" }, { "1.3.6.1.5.5.7.48.2", "PKIX.CertificateAuthorityIssuers" }, { "1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr" }, { "2.16.840.1.101.3.4.1.2", "AES-128/CBC" }, { "2.16.840.1.101.3.4.1.22", "AES-192/CBC" }, { "2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192" }, { "2.16.840.1.101.3.4.1.26", "AES-192/GCM" }, { "2.16.840.1.101.3.4.1.27", "AES-192/CCM" }, { "2.16.840.1.101.3.4.1.42", "AES-256/CBC" }, { "2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256" }, { "2.16.840.1.101.3.4.1.46", "AES-256/GCM" }, { "2.16.840.1.101.3.4.1.47", "AES-256/CCM" }, { "2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128" }, { "2.16.840.1.101.3.4.1.6", "AES-128/GCM" }, { "2.16.840.1.101.3.4.1.7", "AES-128/CCM" }, { "2.16.840.1.101.3.4.2.1", "SHA-256" }, { "2.16.840.1.101.3.4.2.10", "SHA-3(512)" }, { "2.16.840.1.101.3.4.2.11", "SHAKE-128" }, { "2.16.840.1.101.3.4.2.12", "SHAKE-256" }, { "2.16.840.1.101.3.4.2.2", "SHA-384" }, { "2.16.840.1.101.3.4.2.3", "SHA-512" }, { "2.16.840.1.101.3.4.2.4", "SHA-224" }, { "2.16.840.1.101.3.4.2.6", "SHA-512-256" }, { "2.16.840.1.101.3.4.2.7", "SHA-3(224)" }, { "2.16.840.1.101.3.4.2.8", "SHA-3(256)" }, { "2.16.840.1.101.3.4.2.9", "SHA-3(384)" }, { "2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)" }, { "2.16.840.1.101.3.4.3.10", "ECDSA/EMSA1(SHA-3(256))" }, { "2.16.840.1.101.3.4.3.11", "ECDSA/EMSA1(SHA-3(384))" }, { "2.16.840.1.101.3.4.3.12", "ECDSA/EMSA1(SHA-3(512))" }, { "2.16.840.1.101.3.4.3.13", "RSA/EMSA3(SHA-3(224))" }, { "2.16.840.1.101.3.4.3.14", "RSA/EMSA3(SHA-3(256))" }, { "2.16.840.1.101.3.4.3.15", "RSA/EMSA3(SHA-3(384))" }, { "2.16.840.1.101.3.4.3.16", "RSA/EMSA3(SHA-3(512))" }, { "2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)" }, { "2.16.840.1.101.3.4.3.3", "DSA/EMSA1(SHA-384)" }, { "2.16.840.1.101.3.4.3.4", "DSA/EMSA1(SHA-512)" }, { "2.16.840.1.101.3.4.3.5", "DSA/EMSA1(SHA-3(224))" }, { "2.16.840.1.101.3.4.3.6", "DSA/EMSA1(SHA-3(256))" }, { "2.16.840.1.101.3.4.3.7", "DSA/EMSA1(SHA-3(384))" }, { "2.16.840.1.101.3.4.3.8", "DSA/EMSA1(SHA-3(512))" }, { "2.16.840.1.101.3.4.3.9", "ECDSA/EMSA1(SHA-3(224))" }, { "2.16.840.1.113730.1.13", "Certificate Comment" }, { "2.5.29.14", "X509v3.SubjectKeyIdentifier" }, { "2.5.29.15", "X509v3.KeyUsage" }, { "2.5.29.16", "X509v3.PrivateKeyUsagePeriod" }, { "2.5.29.17", "X509v3.SubjectAlternativeName" }, { "2.5.29.18", "X509v3.IssuerAlternativeName" }, { "2.5.29.19", "X509v3.BasicConstraints" }, { "2.5.29.20", "X509v3.CRLNumber" }, { "2.5.29.21", "X509v3.ReasonCode" }, { "2.5.29.23", "X509v3.HoldInstructionCode" }, { "2.5.29.24", "X509v3.InvalidityDate" }, { "2.5.29.28", "X509v3.CRLIssuingDistributionPoint" }, { "2.5.29.30", "X509v3.NameConstraints" }, { "2.5.29.31", "X509v3.CRLDistributionPoints" }, { "2.5.29.32", "X509v3.CertificatePolicies" }, { "2.5.29.32.0", "X509v3.AnyPolicy" }, { "2.5.29.35", "X509v3.AuthorityKeyIdentifier" }, { "2.5.29.36", "X509v3.PolicyConstraints" }, { "2.5.29.37", "X509v3.ExtendedKeyUsage" }, { "2.5.4.10", "X520.Organization" }, { "2.5.4.11", "X520.OrganizationalUnit" }, { "2.5.4.12", "X520.Title" }, { "2.5.4.3", "X520.CommonName" }, { "2.5.4.4", "X520.Surname" }, { "2.5.4.42", "X520.GivenName" }, { "2.5.4.43", "X520.Initials" }, { "2.5.4.44", "X520.GenerationalQualifier" }, { "2.5.4.46", "X520.DNQualifier" }, { "2.5.4.5", "X520.SerialNumber" }, { "2.5.4.6", "X520.Country" }, { "2.5.4.65", "X520.Pseudonym" }, { "2.5.4.7", "X520.Locality" }, { "2.5.4.8", "X520.State" }, { "2.5.4.9", "X520.StreetAddress" }, { "2.5.8.1.1", "RSA" } }; } std::unordered_map OIDS::load_str2oid_map() { return std::unordered_map{ { "AES-128/CBC", OID({2,16,840,1,101,3,4,1,2}) }, { "AES-128/CCM", OID({2,16,840,1,101,3,4,1,7}) }, { "AES-128/GCM", OID({2,16,840,1,101,3,4,1,6}) }, { "AES-128/OCB", OID({1,3,6,1,4,1,25258,3,2,1}) }, { "AES-128/SIV", OID({1,3,6,1,4,1,25258,3,4,1}) }, { "AES-192/CBC", OID({2,16,840,1,101,3,4,1,22}) }, { "AES-192/CCM", OID({2,16,840,1,101,3,4,1,27}) }, { "AES-192/GCM", OID({2,16,840,1,101,3,4,1,26}) }, { "AES-192/OCB", OID({1,3,6,1,4,1,25258,3,2,2}) }, { "AES-192/SIV", OID({1,3,6,1,4,1,25258,3,4,2}) }, { "AES-256/CBC", OID({2,16,840,1,101,3,4,1,42}) }, { "AES-256/CCM", OID({2,16,840,1,101,3,4,1,47}) }, { "AES-256/GCM", OID({2,16,840,1,101,3,4,1,46}) }, { "AES-256/OCB", OID({1,3,6,1,4,1,25258,3,2,3}) }, { "AES-256/SIV", OID({1,3,6,1,4,1,25258,3,4,3}) }, { "CAST-128/CBC", OID({1,2,840,113533,7,66,10}) }, { "Camellia-128/CBC", OID({1,2,392,200011,61,1,1,1,2}) }, { "Camellia-128/GCM", OID({0,3,4401,5,3,1,9,6}) }, { "Camellia-128/OCB", OID({1,3,6,1,4,1,25258,3,2,6}) }, { "Camellia-128/SIV", OID({1,3,6,1,4,1,25258,3,4,6}) }, { "Camellia-192/CBC", OID({1,2,392,200011,61,1,1,1,3}) }, { "Camellia-192/GCM", OID({0,3,4401,5,3,1,9,26}) }, { "Camellia-192/OCB", OID({1,3,6,1,4,1,25258,3,2,7}) }, { "Camellia-192/SIV", OID({1,3,6,1,4,1,25258,3,4,7}) }, { "Camellia-256/CBC", OID({1,2,392,200011,61,1,1,1,4}) }, { "Camellia-256/GCM", OID({0,3,4401,5,3,1,9,46}) }, { "Camellia-256/OCB", OID({1,3,6,1,4,1,25258,3,2,8}) }, { "Camellia-256/SIV", OID({1,3,6,1,4,1,25258,3,4,8}) }, { "Certificate Comment", OID({2,16,840,1,113730,1,13}) }, { "ChaCha20Poly1305", OID({1,2,840,113549,1,9,16,3,18}) }, { "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) }, { "Curve25519", OID({1,3,101,110}) }, { "DES/CBC", OID({1,3,14,3,2,7}) }, { "DH", OID({1,2,840,10046,2,1}) }, { "DSA", OID({1,2,840,10040,4,1}) }, { "DSA/EMSA1(SHA-160)", OID({1,2,840,10040,4,3}) }, { "DSA/EMSA1(SHA-224)", OID({2,16,840,1,101,3,4,3,1}) }, { "DSA/EMSA1(SHA-256)", OID({2,16,840,1,101,3,4,3,2}) }, { "DSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,5}) }, { "DSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,6}) }, { "DSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,7}) }, { "DSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,8}) }, { "DSA/EMSA1(SHA-384)", OID({2,16,840,1,101,3,4,3,3}) }, { "DSA/EMSA1(SHA-512)", OID({2,16,840,1,101,3,4,3,4}) }, { "ECDH", OID({1,3,132,1,12}) }, { "ECDSA", OID({1,2,840,10045,2,1}) }, { "ECDSA/EMSA1(SHA-160)", OID({1,2,840,10045,4,1}) }, { "ECDSA/EMSA1(SHA-224)", OID({1,2,840,10045,4,3,1}) }, { "ECDSA/EMSA1(SHA-256)", OID({1,2,840,10045,4,3,2}) }, { "ECDSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,9}) }, { "ECDSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,10}) }, { "ECDSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,11}) }, { "ECDSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,12}) }, { "ECDSA/EMSA1(SHA-384)", OID({1,2,840,10045,4,3,3}) }, { "ECDSA/EMSA1(SHA-512)", OID({1,2,840,10045,4,3,4}) }, { "ECGDSA", OID({1,3,36,3,3,2,5,2,1}) }, { "ECGDSA/EMSA1(RIPEMD-160)", OID({1,3,36,3,3,2,5,4,1}) }, { "ECGDSA/EMSA1(SHA-160)", OID({1,3,36,3,3,2,5,4,2}) }, { "ECGDSA/EMSA1(SHA-224)", OID({1,3,36,3,3,2,5,4,3}) }, { "ECGDSA/EMSA1(SHA-256)", OID({1,3,36,3,3,2,5,4,4}) }, { "ECGDSA/EMSA1(SHA-384)", OID({1,3,36,3,3,2,5,4,5}) }, { "ECGDSA/EMSA1(SHA-512)", OID({1,3,36,3,3,2,5,4,6}) }, { "ECKCDSA", OID({1,0,14888,3,0,5}) }, { "ECKCDSA/EMSA1(SHA-1)", OID({1,2,410,200004,1,100,4,3}) }, { "ECKCDSA/EMSA1(SHA-224)", OID({1,2,410,200004,1,100,4,4}) }, { "ECKCDSA/EMSA1(SHA-256)", OID({1,2,410,200004,1,100,4,5}) }, { "Ed25519", OID({1,3,101,112}) }, { "ElGamal", OID({1,3,6,1,4,1,3029,1,2,1}) }, { "GOST-34.10", OID({1,2,643,2,2,19}) }, { "GOST-34.10-2012-256", OID({1,2,643,7,1,1,1,1}) }, { "GOST-34.10-2012-256/EMSA1(SHA-256)", OID({1,3,6,1,4,1,25258,1,6,1}) }, { "GOST-34.10-2012-256/EMSA1(Streebog-256)", OID({1,2,643,7,1,1,3,2}) }, { "GOST-34.10-2012-512", OID({1,2,643,7,1,1,1,2}) }, { "GOST-34.10-2012-512/EMSA1(Streebog-512)", OID({1,2,643,7,1,1,3,3}) }, { "GOST-34.10/EMSA1(GOST-R-34.11-94)", OID({1,2,643,2,2,3}) }, { "GOST.INN", OID({1,2,643,3,131,1,1}) }, { "GOST.IssuerSigningTool", OID({1,2,643,100,112}) }, { "GOST.OGRN", OID({1,2,643,100,1}) }, { "GOST.SubjectSigningTool", OID({1,2,643,100,111}) }, { "HMAC(SHA-160)", OID({1,2,840,113549,2,7}) }, { "HMAC(SHA-224)", OID({1,2,840,113549,2,8}) }, { "HMAC(SHA-256)", OID({1,2,840,113549,2,9}) }, { "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) }, { "HMAC(SHA-512)", OID({1,2,840,113549,2,11}) }, { "HMAC(SHA-512-256)", OID({1,2,840,113549,2,13}) }, { "KeyWrap.AES-128", OID({2,16,840,1,101,3,4,1,5}) }, { "KeyWrap.AES-192", OID({2,16,840,1,101,3,4,1,25}) }, { "KeyWrap.AES-256", OID({2,16,840,1,101,3,4,1,45}) }, { "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) }, { "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) }, { "MD5", OID({1,2,840,113549,2,5}) }, { "MGF1", OID({1,2,840,113549,1,1,8}) }, { "McEliece", OID({1,3,6,1,4,1,25258,1,3}) }, { "Microsoft SmartcardLogon", OID({1,3,6,1,4,1,311,20,2,2}) }, { "Microsoft UPN", OID({1,3,6,1,4,1,311,20,2,3}) }, { "OpenPGP.Curve25519", OID({1,3,6,1,4,1,3029,1,5,1}) }, { "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) }, { "PBE-PKCS5v20", OID({1,2,840,113549,1,5,13}) }, { "PBES2", OID({1,2,840,113549,1,5,13}) }, { "PKCS5.PBKDF2", OID({1,2,840,113549,1,5,12}) }, { "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) }, { "PKCS9.ContentType", OID({1,2,840,113549,1,9,3}) }, { "PKCS9.EmailAddress", OID({1,2,840,113549,1,9,1}) }, { "PKCS9.ExtensionRequest", OID({1,2,840,113549,1,9,14}) }, { "PKCS9.MessageDigest", OID({1,2,840,113549,1,9,4}) }, { "PKCS9.UnstructuredName", OID({1,2,840,113549,1,9,2}) }, { "PKIX.AuthorityInformationAccess", OID({1,3,6,1,5,5,7,1,1}) }, { "PKIX.CertificateAuthorityIssuers", OID({1,3,6,1,5,5,7,48,2}) }, { "PKIX.ClientAuth", OID({1,3,6,1,5,5,7,3,2}) }, { "PKIX.CodeSigning", OID({1,3,6,1,5,5,7,3,3}) }, { "PKIX.EmailProtection", OID({1,3,6,1,5,5,7,3,4}) }, { "PKIX.IPsecEndSystem", OID({1,3,6,1,5,5,7,3,5}) }, { "PKIX.IPsecTunnel", OID({1,3,6,1,5,5,7,3,6}) }, { "PKIX.IPsecUser", OID({1,3,6,1,5,5,7,3,7}) }, { "PKIX.OCSP", OID({1,3,6,1,5,5,7,48,1}) }, { "PKIX.OCSP.BasicResponse", OID({1,3,6,1,5,5,7,48,1,1}) }, { "PKIX.OCSPSigning", OID({1,3,6,1,5,5,7,3,9}) }, { "PKIX.ServerAuth", OID({1,3,6,1,5,5,7,3,1}) }, { "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) }, { "PKIX.XMPPAddr", OID({1,3,6,1,5,5,7,8,5}) }, { "RIPEMD-160", OID({1,3,36,3,2,1}) }, { "RSA", OID({1,2,840,113549,1,1,1}) }, { "RSA/EMSA3(MD5)", OID({1,2,840,113549,1,1,4}) }, { "RSA/EMSA3(RIPEMD-160)", OID({1,3,36,3,3,1,2}) }, { "RSA/EMSA3(SHA-160)", OID({1,2,840,113549,1,1,5}) }, { "RSA/EMSA3(SHA-224)", OID({1,2,840,113549,1,1,14}) }, { "RSA/EMSA3(SHA-256)", OID({1,2,840,113549,1,1,11}) }, { "RSA/EMSA3(SHA-3(224))", OID({2,16,840,1,101,3,4,3,13}) }, { "RSA/EMSA3(SHA-3(256))", OID({2,16,840,1,101,3,4,3,14}) }, { "RSA/EMSA3(SHA-3(384))", OID({2,16,840,1,101,3,4,3,15}) }, { "RSA/EMSA3(SHA-3(512))", OID({2,16,840,1,101,3,4,3,16}) }, { "RSA/EMSA3(SHA-384)", OID({1,2,840,113549,1,1,12}) }, { "RSA/EMSA3(SHA-512)", OID({1,2,840,113549,1,1,13}) }, { "RSA/EMSA3(SHA-512-256)", OID({1,2,840,113549,1,1,16}) }, { "RSA/EMSA3(SM3)", OID({1,2,156,10197,1,504}) }, { "RSA/EMSA4", OID({1,2,840,113549,1,1,10}) }, { "RSA/OAEP", OID({1,2,840,113549,1,1,7}) }, { "SEED/CBC", OID({1,2,410,200004,1,4}) }, { "SHA-160", OID({1,3,14,3,2,26}) }, { "SHA-224", OID({2,16,840,1,101,3,4,2,4}) }, { "SHA-256", OID({2,16,840,1,101,3,4,2,1}) }, { "SHA-3(224)", OID({2,16,840,1,101,3,4,2,7}) }, { "SHA-3(256)", OID({2,16,840,1,101,3,4,2,8}) }, { "SHA-3(384)", OID({2,16,840,1,101,3,4,2,9}) }, { "SHA-3(512)", OID({2,16,840,1,101,3,4,2,10}) }, { "SHA-384", OID({2,16,840,1,101,3,4,2,2}) }, { "SHA-512", OID({2,16,840,1,101,3,4,2,3}) }, { "SHA-512-256", OID({2,16,840,1,101,3,4,2,6}) }, { "SHAKE-128", OID({2,16,840,1,101,3,4,2,11}) }, { "SHAKE-256", OID({2,16,840,1,101,3,4,2,12}) }, { "SM2", OID({1,2,156,10197,1,301,1}) }, { "SM2_Enc", OID({1,2,156,10197,1,301,3}) }, { "SM2_Kex", OID({1,2,156,10197,1,301,2}) }, { "SM2_Sig", OID({1,2,156,10197,1,301,1}) }, { "SM2_Sig/SM3", OID({1,2,156,10197,1,501}) }, { "SM3", OID({1,2,156,10197,1,401}) }, { "SM4/CBC", OID({1,2,156,10197,1,104,2}) }, { "SM4/GCM", OID({1,2,156,10197,1,104,8}) }, { "SM4/OCB", OID({1,2,156,10197,1,104,100}) }, { "SM4/SIV", OID({1,3,6,1,4,1,25258,3,4,9}) }, { "Scrypt", OID({1,3,6,1,4,1,11591,4,11}) }, { "Serpent/CBC", OID({1,3,6,1,4,1,25258,3,1}) }, { "Serpent/GCM", OID({1,3,6,1,4,1,25258,3,101}) }, { "Serpent/OCB", OID({1,3,6,1,4,1,25258,3,2,4}) }, { "Serpent/SIV", OID({1,3,6,1,4,1,25258,3,4,4}) }, { "Streebog-256", OID({1,2,643,7,1,1,2,2}) }, { "Streebog-512", OID({1,2,643,7,1,1,2,3}) }, { "Threefish-512/CBC", OID({1,3,6,1,4,1,25258,3,2}) }, { "Tiger(24,3)", OID({1,3,6,1,4,1,11591,12,2}) }, { "TripleDES/CBC", OID({1,2,840,113549,3,7}) }, { "Twofish/CBC", OID({1,3,6,1,4,1,25258,3,3}) }, { "Twofish/GCM", OID({1,3,6,1,4,1,25258,3,102}) }, { "Twofish/OCB", OID({1,3,6,1,4,1,25258,3,2,5}) }, { "Twofish/SIV", OID({1,3,6,1,4,1,25258,3,4,5}) }, { "X509v3.AnyPolicy", OID({2,5,29,32,0}) }, { "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) }, { "X509v3.BasicConstraints", OID({2,5,29,19}) }, { "X509v3.CRLDistributionPoints", OID({2,5,29,31}) }, { "X509v3.CRLIssuingDistributionPoint", OID({2,5,29,28}) }, { "X509v3.CRLNumber", OID({2,5,29,20}) }, { "X509v3.CertificatePolicies", OID({2,5,29,32}) }, { "X509v3.ExtendedKeyUsage", OID({2,5,29,37}) }, { "X509v3.HoldInstructionCode", OID({2,5,29,23}) }, { "X509v3.InvalidityDate", OID({2,5,29,24}) }, { "X509v3.IssuerAlternativeName", OID({2,5,29,18}) }, { "X509v3.KeyUsage", OID({2,5,29,15}) }, { "X509v3.NameConstraints", OID({2,5,29,30}) }, { "X509v3.PolicyConstraints", OID({2,5,29,36}) }, { "X509v3.PrivateKeyUsagePeriod", OID({2,5,29,16}) }, { "X509v3.ReasonCode", OID({2,5,29,21}) }, { "X509v3.SubjectAlternativeName", OID({2,5,29,17}) }, { "X509v3.SubjectKeyIdentifier", OID({2,5,29,14}) }, { "X520.CommonName", OID({2,5,4,3}) }, { "X520.Country", OID({2,5,4,6}) }, { "X520.DNQualifier", OID({2,5,4,46}) }, { "X520.GenerationalQualifier", OID({2,5,4,44}) }, { "X520.GivenName", OID({2,5,4,42}) }, { "X520.Initials", OID({2,5,4,43}) }, { "X520.Locality", OID({2,5,4,7}) }, { "X520.Organization", OID({2,5,4,10}) }, { "X520.OrganizationalUnit", OID({2,5,4,11}) }, { "X520.Pseudonym", OID({2,5,4,65}) }, { "X520.SerialNumber", OID({2,5,4,5}) }, { "X520.State", OID({2,5,4,8}) }, { "X520.StreetAddress", OID({2,5,4,9}) }, { "X520.Surname", OID({2,5,4,4}) }, { "X520.Title", OID({2,5,4,12}) }, { "XMSS", OID({0,4,0,127,0,15,1,1,13,0}) }, { "XMSS-draft12", OID({1,3,6,1,4,1,25258,1,8}) }, { "XMSS-draft6", OID({1,3,6,1,4,1,25258,1,5}) }, { "brainpool160r1", OID({1,3,36,3,3,2,8,1,1,1}) }, { "brainpool192r1", OID({1,3,36,3,3,2,8,1,1,3}) }, { "brainpool224r1", OID({1,3,36,3,3,2,8,1,1,5}) }, { "brainpool256r1", OID({1,3,36,3,3,2,8,1,1,7}) }, { "brainpool320r1", OID({1,3,36,3,3,2,8,1,1,9}) }, { "brainpool384r1", OID({1,3,36,3,3,2,8,1,1,11}) }, { "brainpool512r1", OID({1,3,36,3,3,2,8,1,1,13}) }, { "frp256v1", OID({1,2,250,1,223,101,256,1}) }, { "gost_256A", OID({1,2,643,7,1,2,1,1,1}) }, { "gost_256B", OID({1,2,643,7,1,2,1,1,2}) }, { "gost_512A", OID({1,2,643,7,1,2,1,2,1}) }, { "gost_512B", OID({1,2,643,7,1,2,1,2,2}) }, { "secp160k1", OID({1,3,132,0,9}) }, { "secp160r1", OID({1,3,132,0,8}) }, { "secp160r2", OID({1,3,132,0,30}) }, { "secp192k1", OID({1,3,132,0,31}) }, { "secp192r1", OID({1,2,840,10045,3,1,1}) }, { "secp224k1", OID({1,3,132,0,32}) }, { "secp224r1", OID({1,3,132,0,33}) }, { "secp256k1", OID({1,3,132,0,10}) }, { "secp256r1", OID({1,2,840,10045,3,1,7}) }, { "secp384r1", OID({1,3,132,0,34}) }, { "secp521r1", OID({1,3,132,0,35}) }, { "sm2p256v1", OID({1,2,156,10197,1,301}) }, { "x962_p192v2", OID({1,2,840,10045,3,1,2}) }, { "x962_p192v3", OID({1,2,840,10045,3,1,3}) }, { "x962_p239v1", OID({1,2,840,10045,3,1,4}) }, { "x962_p239v2", OID({1,2,840,10045,3,1,5}) }, { "x962_p239v3", OID({1,2,840,10045,3,1,6}) } }; } } /* * OID Registry * (C) 1999-2008,2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { class OID_Map final { public: void add_oid(const OID& oid, const std::string& str) { add_str2oid(oid, str); add_oid2str(oid, str); } void add_str2oid(const OID& oid, const std::string& str) { lock_guard_type lock(m_mutex); auto i = m_str2oid.find(str); if(i == m_str2oid.end()) m_str2oid.insert(std::make_pair(str, oid)); } void add_oid2str(const OID& oid, const std::string& str) { const std::string oid_str = oid.to_string(); lock_guard_type lock(m_mutex); auto i = m_oid2str.find(oid_str); if(i == m_oid2str.end()) m_oid2str.insert(std::make_pair(oid_str, str)); } std::string oid2str(const OID& oid) { const std::string oid_str = oid.to_string(); lock_guard_type lock(m_mutex); auto i = m_oid2str.find(oid_str); if(i != m_oid2str.end()) return i->second; return ""; } OID str2oid(const std::string& str) { lock_guard_type lock(m_mutex); auto i = m_str2oid.find(str); if(i != m_str2oid.end()) return i->second; return OID(); } bool have_oid(const std::string& str) { lock_guard_type lock(m_mutex); return m_str2oid.find(str) != m_str2oid.end(); } static OID_Map& global_registry() { static OID_Map g_map; return g_map; } private: OID_Map() { m_str2oid = OIDS::load_str2oid_map(); m_oid2str = OIDS::load_oid2str_map(); } mutex_type m_mutex; std::unordered_map m_str2oid; std::unordered_map m_oid2str; }; } void OIDS::add_oid(const OID& oid, const std::string& name) { OID_Map::global_registry().add_oid(oid, name); } void OIDS::add_oidstr(const char* oidstr, const char* name) { add_oid(OID(oidstr), name); } void OIDS::add_oid2str(const OID& oid, const std::string& name) { OID_Map::global_registry().add_oid2str(oid, name); } void OIDS::add_str2oid(const OID& oid, const std::string& name) { OID_Map::global_registry().add_str2oid(oid, name); } std::string OIDS::oid2str_or_empty(const OID& oid) { return OID_Map::global_registry().oid2str(oid); } OID OIDS::str2oid_or_empty(const std::string& name) { return OID_Map::global_registry().str2oid(name); } std::string OIDS::oid2str_or_throw(const OID& oid) { const std::string s = OIDS::oid2str_or_empty(oid); if(s.empty()) throw Lookup_Error("No name associated with OID " + oid.to_string()); return s; } bool OIDS::have_oid(const std::string& name) { return OID_Map::global_registry().have_oid(name); } } /* * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_SYSTEM_RNG) #endif #if !defined(BOTAN_AUTO_RNG_HMAC) #error "No hash function defined for AutoSeeded_RNG in build.h (try enabling sha2_32)" #endif namespace Botan { AutoSeeded_RNG::~AutoSeeded_RNG() { // for unique_ptr } AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, size_t reseed_interval) { m_rng.reset(new HMAC_DRBG(MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), underlying_rng, reseed_interval)); force_reseed(); } AutoSeeded_RNG::AutoSeeded_RNG(Entropy_Sources& entropy_sources, size_t reseed_interval) { m_rng.reset(new HMAC_DRBG(MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), entropy_sources, reseed_interval)); force_reseed(); } AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, Entropy_Sources& entropy_sources, size_t reseed_interval) { m_rng.reset(new HMAC_DRBG( MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), underlying_rng, entropy_sources, reseed_interval)); force_reseed(); } AutoSeeded_RNG::AutoSeeded_RNG(size_t reseed_interval) : #if defined(BOTAN_HAS_SYSTEM_RNG) AutoSeeded_RNG(system_rng(), reseed_interval) #else AutoSeeded_RNG(Entropy_Sources::global_sources(), reseed_interval) #endif { } void AutoSeeded_RNG::force_reseed() { m_rng->force_reseed(); m_rng->next_byte(); if(!m_rng->is_seeded()) { throw Internal_Error("AutoSeeded_RNG reseeding failed"); } } bool AutoSeeded_RNG::is_seeded() const { return m_rng->is_seeded(); } void AutoSeeded_RNG::clear() { m_rng->clear(); } std::string AutoSeeded_RNG::name() const { return m_rng->name(); } void AutoSeeded_RNG::add_entropy(const uint8_t in[], size_t len) { m_rng->add_entropy(in, len); } size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs, size_t poll_bits, std::chrono::milliseconds poll_timeout) { return m_rng->reseed(srcs, poll_bits, poll_timeout); } void AutoSeeded_RNG::randomize(uint8_t output[], size_t output_len) { m_rng->randomize_with_ts_input(output, output_len); } void AutoSeeded_RNG::randomize_with_input(uint8_t output[], size_t output_len, const uint8_t ad[], size_t ad_len) { m_rng->randomize_with_input(output, output_len, ad, ad_len); } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Buffered_Computation::update_be(uint16_t val) { uint8_t inb[sizeof(val)]; store_be(val, inb); add_data(inb, sizeof(inb)); } void Buffered_Computation::update_be(uint32_t val) { uint8_t inb[sizeof(val)]; store_be(val, inb); add_data(inb, sizeof(inb)); } void Buffered_Computation::update_be(uint64_t val) { uint8_t inb[sizeof(val)]; store_be(val, inb); add_data(inb, sizeof(inb)); } void Buffered_Computation::update_le(uint16_t val) { uint8_t inb[sizeof(val)]; store_le(val, inb); add_data(inb, sizeof(inb)); } void Buffered_Computation::update_le(uint32_t val) { uint8_t inb[sizeof(val)]; store_le(val, inb); add_data(inb, sizeof(inb)); } void Buffered_Computation::update_le(uint64_t val) { uint8_t inb[sizeof(val)]; store_le(val, inb); add_data(inb, sizeof(inb)); } } /* * SCAN Name Abstraction * (C) 2008-2009,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { std::string make_arg(const std::vector>& name, size_t start) { std::string output = name[start].second; size_t level = name[start].first; size_t paren_depth = 0; for(size_t i = start + 1; i != name.size(); ++i) { if(name[i].first <= name[start].first) break; if(name[i].first > level) { output += "(" + name[i].second; ++paren_depth; } else if(name[i].first < level) { for (size_t j = name[i].first; j < level; j++) { output += ")"; --paren_depth; } output += "," + name[i].second; } else { if(output[output.size() - 1] != '(') output += ","; output += name[i].second; } level = name[i].first; } for(size_t i = 0; i != paren_depth; ++i) output += ")"; return output; } } SCAN_Name::SCAN_Name(const char* algo_spec) : SCAN_Name(std::string(algo_spec)) { } SCAN_Name::SCAN_Name(std::string algo_spec) : m_orig_algo_spec(algo_spec), m_alg_name(), m_args(), m_mode_info() { if(algo_spec.size() == 0) throw Invalid_Argument("Expected algorithm name, got empty string"); std::vector> name; size_t level = 0; std::pair accum = std::make_pair(level, ""); const std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; for(size_t i = 0; i != algo_spec.size(); ++i) { char c = algo_spec[i]; if(c == '/' || c == ',' || c == '(' || c == ')') { if(c == '(') ++level; else if(c == ')') { if(level == 0) throw Decoding_Error(decoding_error + "Mismatched parens"); --level; } if(c == '/' && level > 0) accum.second.push_back(c); else { if(accum.second != "") name.push_back(accum); accum = std::make_pair(level, ""); } } else accum.second.push_back(c); } if(accum.second != "") name.push_back(accum); if(level != 0) throw Decoding_Error(decoding_error + "Missing close paren"); if(name.size() == 0) throw Decoding_Error(decoding_error + "Empty name"); m_alg_name = name[0].second; bool in_modes = false; for(size_t i = 1; i != name.size(); ++i) { if(name[i].first == 0) { m_mode_info.push_back(make_arg(name, i)); in_modes = true; } else if(name[i].first == 1 && !in_modes) m_args.push_back(make_arg(name, i)); } } std::string SCAN_Name::arg(size_t i) const { if(i >= arg_count()) throw Invalid_Argument("SCAN_Name::arg " + std::to_string(i) + " out of range for '" + to_string() + "'"); return m_args[i]; } std::string SCAN_Name::arg(size_t i, const std::string& def_value) const { if(i >= arg_count()) return def_value; return m_args[i]; } size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const { if(i >= arg_count()) return def_value; return to_u32bit(m_args[i]); } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void SymmetricAlgorithm::throw_key_not_set_error() const { throw Key_Not_Set(name()); } void SymmetricAlgorithm::set_key(const uint8_t key[], size_t length) { if(!valid_keylength(length)) throw Invalid_Key_Length(name(), length); key_schedule(key, length); } } /* * OctetString * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Create an OctetString from RNG output */ OctetString::OctetString(RandomNumberGenerator& rng, size_t len) { rng.random_vec(m_data, len); } /* * Create an OctetString from a hex string */ OctetString::OctetString(const std::string& hex_string) { if(!hex_string.empty()) { m_data.resize(1 + hex_string.length() / 2); m_data.resize(hex_decode(m_data.data(), hex_string)); } } /* * Create an OctetString from a byte string */ OctetString::OctetString(const uint8_t in[], size_t n) { m_data.assign(in, in + n); } /* * Set the parity of each key byte to odd */ void OctetString::set_odd_parity() { const uint8_t ODD_PARITY[256] = { 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE }; for(size_t j = 0; j != m_data.size(); ++j) m_data[j] = ODD_PARITY[m_data[j]]; } /* * Hex encode an OctetString */ std::string OctetString::to_string() const { return hex_encode(m_data.data(), m_data.size()); } /* * XOR Operation for OctetStrings */ OctetString& OctetString::operator^=(const OctetString& k) { if(&k == this) { zeroise(m_data); return (*this); } xor_buf(m_data.data(), k.begin(), std::min(length(), k.length())); return (*this); } /* * Equality Operation for OctetStrings */ bool operator==(const OctetString& s1, const OctetString& s2) { return (s1.bits_of() == s2.bits_of()); } /* * Unequality Operation for OctetStrings */ bool operator!=(const OctetString& s1, const OctetString& s2) { return !(s1 == s2); } /* * Append Operation for OctetStrings */ OctetString operator+(const OctetString& k1, const OctetString& k2) { secure_vector out; out += k1.bits_of(); out += k2.bits_of(); return OctetString(out); } /* * XOR Operation for OctetStrings */ OctetString operator^(const OctetString& k1, const OctetString& k2) { secure_vector out(std::max(k1.length(), k2.length())); copy_mem(out.data(), k1.begin(), k1.length()); xor_buf(out.data(), k2.begin(), k2.length()); return OctetString(out); } } /* * Base32 Encoding and Decoding * (C) 2018 Erwan Chaussy * (C) 2018,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { class Base32 final { public: static inline std::string name() noexcept { return "base32"; } static inline size_t encoding_bytes_in() noexcept { return m_encoding_bytes_in; } static inline size_t encoding_bytes_out() noexcept { return m_encoding_bytes_out; } static inline size_t decoding_bytes_in() noexcept { return m_encoding_bytes_out; } static inline size_t decoding_bytes_out() noexcept { return m_encoding_bytes_in; } static inline size_t bits_consumed() noexcept { return m_encoding_bits; } static inline size_t remaining_bits_before_padding() noexcept { return m_remaining_bits_before_padding; } static inline size_t encode_max_output(size_t input_length) { return (round_up(input_length, m_encoding_bytes_in) / m_encoding_bytes_in) * m_encoding_bytes_out; } static inline size_t decode_max_output(size_t input_length) { return (round_up(input_length, m_encoding_bytes_out) * m_encoding_bytes_in) / m_encoding_bytes_out; } static void encode(char out[8], const uint8_t in[5]) noexcept; static uint8_t lookup_binary_value(char input) noexcept; static bool check_bad_char(uint8_t bin, char input, bool ignore_ws); static void decode(uint8_t* out_ptr, const uint8_t decode_buf[8]) { out_ptr[0] = (decode_buf[0] << 3) | (decode_buf[1] >> 2); out_ptr[1] = (decode_buf[1] << 6) | (decode_buf[2] << 1) | (decode_buf[3] >> 4); out_ptr[2] = (decode_buf[3] << 4) | (decode_buf[4] >> 1); out_ptr[3] = (decode_buf[4] << 7) | (decode_buf[5] << 2) | (decode_buf[6] >> 3); out_ptr[4] = (decode_buf[6] << 5) | decode_buf[7]; } static inline size_t bytes_to_remove(size_t final_truncate) { return final_truncate ? (final_truncate / 2) + 1 : 0; } private: static const size_t m_encoding_bits = 5; static const size_t m_remaining_bits_before_padding = 6; static const size_t m_encoding_bytes_in = 5; static const size_t m_encoding_bytes_out = 8; }; namespace { char lookup_base32_char(uint8_t x) { BOTAN_DEBUG_ASSERT(x < 32); const auto in_AZ = CT::Mask::is_lt(x, 26); const char c_AZ = 'A' + x; const char c_27 = '2' + (x - 26); return in_AZ.select(c_AZ, c_27); } } //static void Base32::encode(char out[8], const uint8_t in[5]) noexcept { const uint8_t b0 = (in[0] & 0xF8) >> 3; const uint8_t b1 = ((in[0] & 0x07) << 2) | (in[1] >> 6); const uint8_t b2 = ((in[1] & 0x3E) >> 1); const uint8_t b3 = ((in[1] & 0x01) << 4) | (in[2] >> 4); const uint8_t b4 = ((in[2] & 0x0F) << 1) | (in[3] >> 7); const uint8_t b5 = ((in[3] & 0x7C) >> 2); const uint8_t b6 = ((in[3] & 0x03) << 3) | (in[4] >> 5); const uint8_t b7 = in[4] & 0x1F; out[0] = lookup_base32_char(b0); out[1] = lookup_base32_char(b1); out[2] = lookup_base32_char(b2); out[3] = lookup_base32_char(b3); out[4] = lookup_base32_char(b4); out[5] = lookup_base32_char(b5); out[6] = lookup_base32_char(b6); out[7] = lookup_base32_char(b7); } //static uint8_t Base32::lookup_binary_value(char input) noexcept { const uint8_t c = static_cast(input); const auto is_alpha_upper = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('Z')); const auto is_decimal = CT::Mask::is_within_range(c, uint8_t('2'), uint8_t('7')); const auto is_equal = CT::Mask::is_equal(c, uint8_t('=')); const auto is_whitespace = CT::Mask::is_any_of(c, { uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') }); const uint8_t c_upper = c - uint8_t('A'); const uint8_t c_decim = c - uint8_t('2') + 26; uint8_t ret = 0xFF; // default value ret = is_alpha_upper.select(c_upper, ret); ret = is_decimal.select(c_decim, ret); ret = is_equal.select(0x81, ret); ret = is_whitespace.select(0x80, ret); return ret; } //static bool Base32::check_bad_char(uint8_t bin, char input, bool ignore_ws) { if(bin <= 0x1F) { return true; } else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) { std::string bad_char(1, input); if(bad_char == "\t") { bad_char = "\\t"; } else if(bad_char == "\n") { bad_char = "\\n"; } else if(bad_char == "\r") { bad_char = "\\r"; } throw Invalid_Argument( std::string("base32_decode: invalid base32 character '") + bad_char + "'"); } return false; } } size_t base32_encode(char out[], const uint8_t in[], size_t input_length, size_t& input_consumed, bool final_inputs) { return base_encode(Base32(), out, in, input_length, input_consumed, final_inputs); } std::string base32_encode(const uint8_t input[], size_t input_length) { return base_encode_to_string(Base32(), input, input_length); } size_t base32_decode(uint8_t out[], const char in[], size_t input_length, size_t& input_consumed, bool final_inputs, bool ignore_ws) { return base_decode(Base32(), out, in, input_length, input_consumed, final_inputs, ignore_ws); } size_t base32_decode(uint8_t output[], const char input[], size_t input_length, bool ignore_ws) { return base_decode_full(Base32(), output, input, input_length, ignore_ws); } size_t base32_decode(uint8_t output[], const std::string& input, bool ignore_ws) { return base32_decode(output, input.data(), input.length(), ignore_ws); } secure_vector base32_decode(const char input[], size_t input_length, bool ignore_ws) { return base_decode_to_vec>(Base32(), input, input_length, ignore_ws); } secure_vector base32_decode(const std::string& input, bool ignore_ws) { return base32_decode(input.data(), input.size(), ignore_ws); } } /* * (C) 2018,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { uint32_t sha256_d_checksum(const uint8_t input[], size_t input_length) { std::unique_ptr sha256 = HashFunction::create_or_throw("SHA-256"); std::vector checksum(32); sha256->update(input, input_length); sha256->final(checksum); sha256->update(checksum); sha256->final(checksum); return load_be(checksum.data(), 0); } char lookup_base58_char(uint8_t x) { // "123456789 ABCDEFGH JKLMN PQRSTUVWXYZ abcdefghijk mnopqrstuvwxyz" BOTAN_DEBUG_ASSERT(x < 58); const auto is_dec_19 = CT::Mask::is_lte(x, 8); const auto is_alpha_AH = CT::Mask::is_within_range(x, 9, 16); const auto is_alpha_JN = CT::Mask::is_within_range(x, 17, 21); const auto is_alpha_PZ = CT::Mask::is_within_range(x, 22, 32); const auto is_alpha_ak = CT::Mask::is_within_range(x, 33, 43); // otherwise in 'm'-'z' const char c_19 = '1' + x; const char c_AH = 'A' + (x - 9); const char c_JN = 'J' + (x - 17); const char c_PZ = 'P' + (x - 22); const char c_ak = 'a' + (x - 33); const char c_mz = 'm' + (x - 44); char ret = c_mz; ret = is_dec_19.select(c_19, ret); ret = is_alpha_AH.select(c_AH, ret); ret = is_alpha_JN.select(c_JN, ret); ret = is_alpha_PZ.select(c_PZ, ret); ret = is_alpha_ak.select(c_ak, ret); return ret; } std::string base58_encode(BigInt v, size_t leading_zeros) { const uint8_t radix = 58; std::string result; BigInt q; while(v.is_nonzero()) { uint8_t r; ct_divide_u8(v, radix, q, r); result.push_back(lookup_base58_char(r)); v.swap(q); } for(size_t i = 0; i != leading_zeros; ++i) result.push_back('1'); // 'zero' byte return std::string(result.rbegin(), result.rend()); } template size_t count_leading_zeros(const T input[], size_t input_length, Z zero) { size_t leading_zeros = 0; while(leading_zeros < input_length && input[leading_zeros] == zero) leading_zeros += 1; return leading_zeros; } uint8_t base58_value_of(char input) { // "123456789 ABCDEFGH JKLMN PQRSTUVWXYZ abcdefghijk mnopqrstuvwxyz" const uint8_t c = static_cast(input); const auto is_dec_19 = CT::Mask::is_within_range(c, uint8_t('1'), uint8_t('9')); const auto is_alpha_AH = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('H')); const auto is_alpha_JN = CT::Mask::is_within_range(c, uint8_t('J'), uint8_t('N')); const auto is_alpha_PZ = CT::Mask::is_within_range(c, uint8_t('P'), uint8_t('Z')); const auto is_alpha_ak = CT::Mask::is_within_range(c, uint8_t('a'), uint8_t('k')); const auto is_alpha_mz = CT::Mask::is_within_range(c, uint8_t('m'), uint8_t('z')); const uint8_t c_dec_19 = c - uint8_t('1'); const uint8_t c_AH = c - uint8_t('A') + 9; const uint8_t c_JN = c - uint8_t('J') + 17; const uint8_t c_PZ = c - uint8_t('P') + 22; const uint8_t c_ak = c - uint8_t('a') + 33; const uint8_t c_mz = c - uint8_t('m') + 44; uint8_t ret = 0xFF; // default value ret = is_dec_19.select(c_dec_19, ret); ret = is_alpha_AH.select(c_AH, ret); ret = is_alpha_JN.select(c_JN, ret); ret = is_alpha_PZ.select(c_PZ, ret); ret = is_alpha_ak.select(c_ak, ret); ret = is_alpha_mz.select(c_mz, ret); return ret; } } std::string base58_encode(const uint8_t input[], size_t input_length) { BigInt v(input, input_length); return base58_encode(v, count_leading_zeros(input, input_length, 0)); } std::string base58_check_encode(const uint8_t input[], size_t input_length) { BigInt v(input, input_length); v <<= 32; v += sha256_d_checksum(input, input_length); return base58_encode(v, count_leading_zeros(input, input_length, 0)); } std::vector base58_decode(const char input[], size_t input_length) { const size_t leading_zeros = count_leading_zeros(input, input_length, '1'); BigInt v; for(size_t i = leading_zeros; i != input_length; ++i) { const char c = input[i]; if(c == ' ' || c == '\n') continue; const uint8_t idx = base58_value_of(c); if(idx == 0xFF) throw Decoding_Error("Invalid base58"); v *= 58; v += idx; } std::vector output(v.bytes() + leading_zeros); v.binary_encode(output.data() + leading_zeros); return output; } std::vector base58_check_decode(const char input[], size_t input_length) { std::vector dec = base58_decode(input, input_length); if(dec.size() < 4) throw Decoding_Error("Invalid base58 too short for checksum"); const uint32_t computed_checksum = sha256_d_checksum(dec.data(), dec.size() - 4); const uint32_t checksum = load_be(&dec[dec.size()-4], 0); if(checksum != computed_checksum) throw Decoding_Error("Invalid base58 checksum"); dec.resize(dec.size() - 4); return dec; } } /* * Base64 Encoding and Decoding * (C) 2010,2015,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { class Base64 final { public: static inline std::string name() noexcept { return "base64"; } static inline size_t encoding_bytes_in() noexcept { return m_encoding_bytes_in; } static inline size_t encoding_bytes_out() noexcept { return m_encoding_bytes_out; } static inline size_t decoding_bytes_in() noexcept { return m_encoding_bytes_out; } static inline size_t decoding_bytes_out() noexcept { return m_encoding_bytes_in; } static inline size_t bits_consumed() noexcept { return m_encoding_bits; } static inline size_t remaining_bits_before_padding() noexcept { return m_remaining_bits_before_padding; } static inline size_t encode_max_output(size_t input_length) { return (round_up(input_length, m_encoding_bytes_in) / m_encoding_bytes_in) * m_encoding_bytes_out; } static inline size_t decode_max_output(size_t input_length) { return (round_up(input_length, m_encoding_bytes_out) * m_encoding_bytes_in) / m_encoding_bytes_out; } static void encode(char out[8], const uint8_t in[5]) noexcept; static uint8_t lookup_binary_value(char input) noexcept; static bool check_bad_char(uint8_t bin, char input, bool ignore_ws); static void decode(uint8_t* out_ptr, const uint8_t decode_buf[4]) { out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; } static inline size_t bytes_to_remove(size_t final_truncate) { return final_truncate; } private: static const size_t m_encoding_bits = 6; static const size_t m_remaining_bits_before_padding = 8; static const size_t m_encoding_bytes_in = 3; static const size_t m_encoding_bytes_out = 4; }; char lookup_base64_char(uint8_t x) { BOTAN_DEBUG_ASSERT(x < 64); const auto in_az = CT::Mask::is_within_range(x, 26, 51); const auto in_09 = CT::Mask::is_within_range(x, 52, 61); const auto eq_plus = CT::Mask::is_equal(x, 62); const auto eq_slash = CT::Mask::is_equal(x, 63); const char c_AZ = 'A' + x; const char c_az = 'a' + (x - 26); const char c_09 = '0' + (x - 2*26); const char c_plus = '+'; const char c_slash = '/'; char ret = c_AZ; ret = in_az.select(c_az, ret); ret = in_09.select(c_09, ret); ret = eq_plus.select(c_plus, ret); ret = eq_slash.select(c_slash, ret); return ret; } //static void Base64::encode(char out[8], const uint8_t in[5]) noexcept { const uint8_t b0 = (in[0] & 0xFC) >> 2; const uint8_t b1 = ((in[0] & 0x03) << 4) | (in[1] >> 4); const uint8_t b2 = ((in[1] & 0x0F) << 2) | (in[2] >> 6); const uint8_t b3 = in[2] & 0x3F; out[0] = lookup_base64_char(b0); out[1] = lookup_base64_char(b1); out[2] = lookup_base64_char(b2); out[3] = lookup_base64_char(b3); } //static uint8_t Base64::lookup_binary_value(char input) noexcept { const uint8_t c = static_cast(input); const auto is_alpha_upper = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('Z')); const auto is_alpha_lower = CT::Mask::is_within_range(c, uint8_t('a'), uint8_t('z')); const auto is_decimal = CT::Mask::is_within_range(c, uint8_t('0'), uint8_t('9')); const auto is_plus = CT::Mask::is_equal(c, uint8_t('+')); const auto is_slash = CT::Mask::is_equal(c, uint8_t('/')); const auto is_equal = CT::Mask::is_equal(c, uint8_t('=')); const auto is_whitespace = CT::Mask::is_any_of(c, { uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') }); const uint8_t c_upper = c - uint8_t('A'); const uint8_t c_lower = c - uint8_t('a') + 26; const uint8_t c_decim = c - uint8_t('0') + 2*26; uint8_t ret = 0xFF; // default value ret = is_alpha_upper.select(c_upper, ret); ret = is_alpha_lower.select(c_lower, ret); ret = is_decimal.select(c_decim, ret); ret = is_plus.select(62, ret); ret = is_slash.select(63, ret); ret = is_equal.select(0x81, ret); ret = is_whitespace.select(0x80, ret); return ret; } //static bool Base64::check_bad_char(uint8_t bin, char input, bool ignore_ws) { if(bin <= 0x3F) { return true; } else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) { std::string bad_char(1, input); if(bad_char == "\t") { bad_char = "\\t"; } else if(bad_char == "\n") { bad_char = "\\n"; } else if(bad_char == "\r") { bad_char = "\\r"; } throw Invalid_Argument( std::string("base64_decode: invalid base64 character '") + bad_char + "'"); } return false; } } size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t& input_consumed, bool final_inputs) { return base_encode(Base64(), out, in, input_length, input_consumed, final_inputs); } std::string base64_encode(const uint8_t input[], size_t input_length) { return base_encode_to_string(Base64(), input, input_length); } size_t base64_decode(uint8_t out[], const char in[], size_t input_length, size_t& input_consumed, bool final_inputs, bool ignore_ws) { return base_decode(Base64(), out, in, input_length, input_consumed, final_inputs, ignore_ws); } size_t base64_decode(uint8_t output[], const char input[], size_t input_length, bool ignore_ws) { return base_decode_full(Base64(), output, input, input_length, ignore_ws); } size_t base64_decode(uint8_t output[], const std::string& input, bool ignore_ws) { return base64_decode(output, input.data(), input.length(), ignore_ws); } secure_vector base64_decode(const char input[], size_t input_length, bool ignore_ws) { return base_decode_to_vec>(Base64(), input, input_length, ignore_ws); } secure_vector base64_decode(const std::string& input, bool ignore_ws) { return base64_decode(input.data(), input.size(), ignore_ws); } size_t base64_encode_max_output(size_t input_length) { return Base64::encode_max_output(input_length); } size_t base64_decode_max_output(size_t input_length) { return Base64::decode_max_output(input_length); } } /* * Bcrypt Password Hashing * (C) 2010,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { std::string bcrypt_base64_encode(const uint8_t input[], size_t length) { // Bcrypt uses a non-standard base64 alphabet const uint8_t OPENBSD_BASE64_SUB[256] = { 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; std::string b64 = base64_encode(input, length); while(b64.size() && b64[b64.size()-1] == '=') b64 = b64.substr(0, b64.size() - 1); for(size_t i = 0; i != b64.size(); ++i) b64[i] = OPENBSD_BASE64_SUB[static_cast(b64[i])]; return b64; } std::vector bcrypt_base64_decode(std::string input) { const uint8_t OPENBSD_BASE64_SUB[256] = { 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; for(size_t i = 0; i != input.size(); ++i) input[i] = OPENBSD_BASE64_SUB[static_cast(input[i])]; return unlock(base64_decode(input)); } std::string make_bcrypt(const std::string& pass, const std::vector& salt, uint16_t work_factor, char version) { /* * On a 4 GHz Skylake, workfactor == 18 takes about 15 seconds to * hash a password. This seems like a reasonable upper bound for the * time being. * Bcrypt allows up to work factor 31 (2^31 iterations) */ BOTAN_ARG_CHECK(work_factor >= 4 && work_factor <= 18, "Invalid bcrypt work factor"); static const uint8_t BCRYPT_MAGIC[8*3] = { 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74 }; Blowfish blowfish; // Include the trailing NULL byte, so we need c_str() not data() blowfish.salted_set_key(cast_char_ptr_to_uint8(pass.c_str()), pass.length() + 1, salt.data(), salt.size(), work_factor); std::vector ctext(BCRYPT_MAGIC, BCRYPT_MAGIC + 8*3); for(size_t i = 0; i != 64; ++i) blowfish.encrypt_n(ctext.data(), ctext.data(), 3); std::string salt_b64 = bcrypt_base64_encode(salt.data(), salt.size()); std::string work_factor_str = std::to_string(work_factor); if(work_factor_str.length() == 1) work_factor_str = "0" + work_factor_str; return "$2" + std::string(1, version) + "$" + work_factor_str + "$" + salt_b64.substr(0, 22) + bcrypt_base64_encode(ctext.data(), ctext.size() - 1); } } std::string generate_bcrypt(const std::string& pass, RandomNumberGenerator& rng, uint16_t work_factor, char version) { /* 2a, 2b and 2y are identical for our purposes because our implementation of 2a never had the truncation or signed char bugs in the first place. */ if(version != 'a' && version != 'b' && version != 'y') throw Invalid_Argument("Unknown bcrypt version '" + std::string(1, version) + "'"); std::vector salt; rng.random_vec(salt, 16); return make_bcrypt(pass, salt, work_factor, version); } bool check_bcrypt(const std::string& pass, const std::string& hash) { if(hash.size() != 60 || hash[0] != '$' || hash[1] != '2' || hash[3] != '$' || hash[6] != '$') { return false; } const char bcrypt_version = hash[2]; if(bcrypt_version != 'a' && bcrypt_version != 'b' && bcrypt_version != 'y') { return false; } const uint16_t workfactor = to_uint16(hash.substr(4, 2)); const std::vector salt = bcrypt_base64_decode(hash.substr(7, 22)); if(salt.size() != 16) return false; const std::string compare = make_bcrypt(pass, salt, workfactor, bcrypt_version); return same_mem(hash.data(), compare.data(), compare.size()); } } /* * (C) 2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Bcrypt_PBKDF::derive_key(uint8_t output[], size_t output_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) const { bcrypt_pbkdf(output, output_len, password, password_len, salt, salt_len, m_iterations); } std::string Bcrypt_PBKDF::to_string() const { return "Bcrypt-PBKDF(" + std::to_string(m_iterations) + ")"; } std::string Bcrypt_PBKDF_Family::name() const { return "Bcrypt-PBKDF"; } std::unique_ptr Bcrypt_PBKDF_Family::tune(size_t output_length, std::chrono::milliseconds msec, size_t /*max_memory*/) const { Timer timer("Bcrypt_PBKDF"); const auto tune_time = BOTAN_PBKDF_TUNING_TIME; const size_t blocks = (output_length + 32 - 1) / 32; if(blocks == 0) return default_params(); const size_t starting_iter = 2; timer.run_until_elapsed(tune_time, [&]() { uint8_t output[32] = { 0 }; bcrypt_pbkdf(output, sizeof(output), "test", 4, nullptr, 0, starting_iter); }); if(timer.events() < blocks || timer.value() == 0) return default_params(); const uint64_t measured_time = timer.value() / (timer.events() / blocks); const uint64_t target_nsec = msec.count() * static_cast(1000000); const uint64_t desired_increase = target_nsec / measured_time; if(desired_increase == 0) return this->from_iterations(starting_iter); return this->from_iterations(static_cast(desired_increase * starting_iter)); } std::unique_ptr Bcrypt_PBKDF_Family::default_params() const { return this->from_iterations(32); // About 100 ms on fast machine } std::unique_ptr Bcrypt_PBKDF_Family::from_iterations(size_t iter) const { return std::unique_ptr(new Bcrypt_PBKDF(iter)); } std::unique_ptr Bcrypt_PBKDF_Family::from_params(size_t iter, size_t /*t*/, size_t /*p*/) const { return this->from_iterations(iter); } namespace { void bcrypt_round(Blowfish& blowfish, const secure_vector& pass_hash, const secure_vector& salt_hash, secure_vector& out, secure_vector& tmp) { const size_t BCRYPT_PBKDF_OUTPUT = 32; // "OxychromaticBlowfishSwatDynamite" static const uint8_t BCRYPT_PBKDF_MAGIC[BCRYPT_PBKDF_OUTPUT] = { 0x4F, 0x78, 0x79, 0x63, 0x68, 0x72, 0x6F, 0x6D, 0x61, 0x74, 0x69, 0x63, 0x42, 0x6C, 0x6F, 0x77, 0x66, 0x69, 0x73, 0x68, 0x53, 0x77, 0x61, 0x74, 0x44, 0x79, 0x6E, 0x61, 0x6D, 0x69, 0x74, 0x65 }; const size_t BCRYPT_PBKDF_WORKFACTOR = 6; const size_t BCRYPT_PBKDF_ROUNDS = 64; blowfish.salted_set_key(pass_hash.data(), pass_hash.size(), salt_hash.data(), salt_hash.size(), BCRYPT_PBKDF_WORKFACTOR, true); copy_mem(tmp.data(), BCRYPT_PBKDF_MAGIC, BCRYPT_PBKDF_OUTPUT); for(size_t i = 0; i != BCRYPT_PBKDF_ROUNDS; ++i) blowfish.encrypt(tmp); /* Bcrypt PBKDF loads the Blowfish output as big endian for no reason in particular. We can't just swap everything once at the end because the (big-endian) values are fed into SHA-512 to generate the salt for the next round */ for(size_t i = 0; i != 32/4; ++i) { const uint32_t w = load_le(tmp.data(), i); store_be(w, &tmp[sizeof(uint32_t)*i]); } xor_buf(out.data(), tmp.data(), BCRYPT_PBKDF_OUTPUT); } } void bcrypt_pbkdf(uint8_t output[], size_t output_len, const char* pass, size_t pass_len, const uint8_t salt[], size_t salt_len, size_t rounds) { BOTAN_ARG_CHECK(rounds >= 1, "Invalid rounds for Bcrypt PBKDF"); // No output desired, so we are all done already... if(output_len == 0) return; BOTAN_ARG_CHECK(output_len <= 10*1024*1024, "Too much output for Bcrypt PBKDF"); const size_t BCRYPT_BLOCK_SIZE = 32; const size_t blocks = (output_len + BCRYPT_BLOCK_SIZE - 1) / BCRYPT_BLOCK_SIZE; std::unique_ptr sha512 = HashFunction::create_or_throw("SHA-512"); const secure_vector pass_hash = sha512->process(reinterpret_cast(pass), pass_len); secure_vector salt_hash(sha512->output_length()); Blowfish blowfish; secure_vector out(BCRYPT_BLOCK_SIZE); secure_vector tmp(BCRYPT_BLOCK_SIZE); for(size_t block = 0; block != blocks; ++block) { clear_mem(out.data(), out.size()); sha512->update(salt, salt_len); sha512->update_be(static_cast(block + 1)); sha512->final(salt_hash.data()); bcrypt_round(blowfish, pass_hash, salt_hash, out, tmp); for(size_t r = 1; r != rounds; ++r) { // Next salt is H(prev_output) sha512->update(tmp); sha512->final(salt_hash.data()); bcrypt_round(blowfish, pass_hash, salt_hash, out, tmp); } for(size_t i = 0; i != BCRYPT_BLOCK_SIZE; ++i) { const size_t dest = i * blocks + block; if(dest < output_len) output[dest] = out[i]; } } } } /* * BigInt Encoding/Decoding * (C) 1999-2010,2012,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string BigInt::to_dec_string() const { BigInt copy = *this; copy.set_sign(Positive); uint8_t remainder; std::vector digits; while(copy > 0) { ct_divide_u8(copy, 10, copy, remainder); digits.push_back(remainder); } std::string s; for(auto i = digits.rbegin(); i != digits.rend(); ++i) { s.push_back(Charset::digit2char(*i)); } if(s.empty()) s += "0"; return s; } std::string BigInt::to_hex_string() const { const std::vector bits = BigInt::encode(*this); if(bits.empty()) return "00"; else return hex_encode(bits); } /* * Encode a BigInt */ void BigInt::encode(uint8_t output[], const BigInt& n, Base base) { secure_vector enc = n.encode_locked(base); copy_mem(output, enc.data(), enc.size()); } namespace { std::vector str_to_vector(const std::string& s) { std::vector v(s.size()); std::memcpy(v.data(), s.data(), s.size()); return v; } secure_vector str_to_lvector(const std::string& s) { secure_vector v(s.size()); std::memcpy(v.data(), s.data(), s.size()); return v; } } /* * Encode a BigInt */ std::vector BigInt::encode(const BigInt& n, Base base) { if(base == Binary) return BigInt::encode(n); else if(base == Hexadecimal) return str_to_vector(n.to_hex_string()); else if(base == Decimal) return str_to_vector(n.to_dec_string()); else throw Invalid_Argument("Unknown BigInt encoding base"); } /* * Encode a BigInt */ secure_vector BigInt::encode_locked(const BigInt& n, Base base) { if(base == Binary) return BigInt::encode_locked(n); else if(base == Hexadecimal) return str_to_lvector(n.to_hex_string()); else if(base == Decimal) return str_to_lvector(n.to_dec_string()); else throw Invalid_Argument("Unknown BigInt encoding base"); } /* * Encode a BigInt, with leading 0s if needed */ secure_vector BigInt::encode_1363(const BigInt& n, size_t bytes) { if(n.bytes() > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); secure_vector output(bytes); n.binary_encode(output.data(), output.size()); return output; } //static void BigInt::encode_1363(uint8_t output[], size_t bytes, const BigInt& n) { if(n.bytes() > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); n.binary_encode(output, bytes); } /* * Encode two BigInt, with leading 0s if needed, and concatenate */ secure_vector BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) { if(n1.bytes() > bytes || n2.bytes() > bytes) throw Encoding_Error("encode_fixed_length_int_pair: values too large to encode properly"); secure_vector output(2 * bytes); n1.binary_encode(output.data() , bytes); n2.binary_encode(output.data() + bytes, bytes); return output; } /* * Decode a BigInt */ BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) { BigInt r; if(base == Binary) { r.binary_decode(buf, length); } else if(base == Hexadecimal) { secure_vector binary; if(length % 2) { // Handle lack of leading 0 const char buf0_with_leading_0[2] = { '0', static_cast(buf[0]) }; binary = hex_decode_locked(buf0_with_leading_0, 2); binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), length - 1, false); } else binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), length, false); r.binary_decode(binary.data(), binary.size()); } else if(base == Decimal) { for(size_t i = 0; i != length; ++i) { if(Charset::is_space(buf[i])) continue; if(!Charset::is_digit(buf[i])) throw Invalid_Argument("BigInt::decode: " "Invalid character in decimal input"); const uint8_t x = Charset::char2digit(buf[i]); if(x >= 10) throw Invalid_Argument("BigInt: Invalid decimal string"); r *= 10; r += x; } } else throw Invalid_Argument("Unknown BigInt decoding method"); return r; } } /* * BigInt Input/Output * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include namespace Botan { /* * Write the BigInt into a stream */ std::ostream& operator<<(std::ostream& stream, const BigInt& n) { size_t base = 10; if(stream.flags() & std::ios::hex) base = 16; if(stream.flags() & std::ios::oct) throw Invalid_Argument("Octal output of BigInt not supported"); if(n == 0) stream.write("0", 1); else { if(n < 0) stream.write("-", 1); std::string enc; if(base == 10) enc = n.to_dec_string(); else enc = n.to_hex_string(); size_t skip = 0; while(skip < enc.size() && enc[skip] == '0') ++skip; stream.write(&enc[skip], enc.size() - skip); } if(!stream.good()) throw Stream_IO_Error("BigInt output operator has failed"); return stream; } /* * Read the BigInt from a stream */ std::istream& operator>>(std::istream& stream, BigInt& n) { std::string str; std::getline(stream, str); if(stream.bad() || (stream.fail() && !stream.eof())) throw Stream_IO_Error("BigInt input operator has failed"); n = BigInt(str); return stream; } } /* * (C) 1999-2007,2018 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { BigInt& BigInt::add(const word y[], size_t y_words, Sign y_sign) { const size_t x_sw = sig_words(); grow_to(std::max(x_sw, y_words) + 1); if(sign() == y_sign) { bigint_add2(mutable_data(), size() - 1, y, y_words); } else { const int32_t relative_size = bigint_cmp(data(), x_sw, y, y_words); if(relative_size >= 0) { // *this >= y bigint_sub2(mutable_data(), x_sw, y, y_words); } else { // *this < y bigint_sub2_rev(mutable_data(), y, y_words); } //this->sign_fixup(relative_size, y_sign); if(relative_size < 0) set_sign(y_sign); else if(relative_size == 0) set_sign(Positive); } return (*this); } BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector& ws) { if(this->is_negative() || s.is_negative() || mod.is_negative()) throw Invalid_Argument("BigInt::mod_add expects all arguments are positive"); BOTAN_DEBUG_ASSERT(*this < mod); BOTAN_DEBUG_ASSERT(s < mod); /* t + s or t + s - p == t - (p - s) So first compute ws = p - s Then compute t + s and t - ws If t - ws does not borrow, then that is the correct valued */ const size_t mod_sw = mod.sig_words(); BOTAN_ARG_CHECK(mod_sw > 0, "BigInt::mod_add modulus must be positive"); this->grow_to(mod_sw); s.grow_to(mod_sw); // First mod_sw for p - s, 2*mod_sw for bigint_addsub workspace if(ws.size() < 3*mod_sw) ws.resize(3*mod_sw); word borrow = bigint_sub3(&ws[0], mod.data(), mod_sw, s.data(), mod_sw); BOTAN_DEBUG_ASSERT(borrow == 0); // Compute t - ws borrow = bigint_sub3(&ws[mod_sw], this->data(), mod_sw, &ws[0], mod_sw); // Compute t + s bigint_add3_nc(&ws[mod_sw*2], this->data(), mod_sw, s.data(), mod_sw); CT::conditional_copy_mem(borrow, &ws[0], &ws[mod_sw*2], &ws[mod_sw], mod_sw); set_words(&ws[0], mod_sw); return (*this); } BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector& ws) { if(this->is_negative() || s.is_negative() || mod.is_negative()) throw Invalid_Argument("BigInt::mod_sub expects all arguments are positive"); // We are assuming in this function that *this and s are no more than mod_sw words long BOTAN_DEBUG_ASSERT(*this < mod); BOTAN_DEBUG_ASSERT(s < mod); const size_t mod_sw = mod.sig_words(); this->grow_to(mod_sw); s.grow_to(mod_sw); if(ws.size() < mod_sw) ws.resize(mod_sw); if(mod_sw == 4) bigint_mod_sub_n<4>(mutable_data(), s.data(), mod.data(), ws.data()); else if(mod_sw == 6) bigint_mod_sub_n<6>(mutable_data(), s.data(), mod.data(), ws.data()); else bigint_mod_sub(mutable_data(), s.data(), mod.data(), mod_sw, ws.data()); return (*this); } BigInt& BigInt::mod_mul(uint8_t y, const BigInt& mod, secure_vector& ws) { BOTAN_ARG_CHECK(this->is_negative() == false, "*this must be positive"); BOTAN_ARG_CHECK(y < 16, "y too large"); BOTAN_DEBUG_ASSERT(*this < mod); *this *= static_cast(y); this->reduce_below(mod, ws); return (*this); } BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector& ws) { if(this->sign() != BigInt::Positive) throw Invalid_State("BigInt::sub_rev requires this is positive"); const size_t x_sw = this->sig_words(); ws.resize(std::max(x_sw, y_sw)); clear_mem(ws.data(), ws.size()); const int32_t relative_size = bigint_sub_abs(ws.data(), data(), x_sw, y, y_sw); this->cond_flip_sign(relative_size > 0); this->swap_reg(ws); return (*this); } /* * Multiplication Operator */ BigInt& BigInt::operator*=(const BigInt& y) { secure_vector ws; return this->mul(y, ws); } BigInt& BigInt::mul(const BigInt& y, secure_vector& ws) { const size_t x_sw = sig_words(); const size_t y_sw = y.sig_words(); set_sign((sign() == y.sign()) ? Positive : Negative); if(x_sw == 0 || y_sw == 0) { clear(); set_sign(Positive); } else if(x_sw == 1 && y_sw) { grow_to(y_sw + 1); bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0)); } else if(y_sw == 1 && x_sw) { word carry = bigint_linmul2(mutable_data(), x_sw, y.word_at(0)); set_word_at(x_sw, carry); } else { const size_t new_size = x_sw + y_sw + 1; ws.resize(new_size); secure_vector z_reg(new_size); bigint_mul(z_reg.data(), z_reg.size(), data(), size(), x_sw, y.data(), y.size(), y_sw, ws.data(), ws.size()); this->swap_reg(z_reg); } return (*this); } BigInt& BigInt::square(secure_vector& ws) { const size_t sw = sig_words(); secure_vector z(2*sw); ws.resize(z.size()); bigint_sqr(z.data(), z.size(), data(), size(), sw, ws.data(), ws.size()); swap_reg(z); set_sign(BigInt::Positive); return (*this); } BigInt& BigInt::operator*=(word y) { if(y == 0) { clear(); set_sign(Positive); } const word carry = bigint_linmul2(mutable_data(), size(), y); set_word_at(size(), carry); return (*this); } /* * Division Operator */ BigInt& BigInt::operator/=(const BigInt& y) { if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) (*this) >>= (y.bits() - 1); else (*this) = (*this) / y; return (*this); } /* * Modulo Operator */ BigInt& BigInt::operator%=(const BigInt& mod) { return (*this = (*this) % mod); } /* * Modulo Operator */ word BigInt::operator%=(word mod) { if(mod == 0) throw BigInt::DivideByZero(); word remainder = 0; if(is_power_of_2(mod)) { remainder = (word_at(0) & (mod - 1)); } else { const size_t sw = sig_words(); for(size_t i = sw; i > 0; --i) remainder = bigint_modop(remainder, word_at(i-1), mod); } if(remainder && sign() == BigInt::Negative) remainder = mod - remainder; m_data.set_to_zero(); m_data.set_word_at(0, remainder); set_sign(BigInt::Positive); return remainder; } /* * Left Shift Operator */ BigInt& BigInt::operator<<=(size_t shift) { const size_t shift_words = shift / BOTAN_MP_WORD_BITS; const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; const size_t size = sig_words(); const size_t bits_free = top_bits_free(); const size_t new_size = size + shift_words + (bits_free < shift_bits); m_data.grow_to(new_size); bigint_shl1(m_data.mutable_data(), new_size, size, shift_words, shift_bits); return (*this); } /* * Right Shift Operator */ BigInt& BigInt::operator>>=(size_t shift) { const size_t shift_words = shift / BOTAN_MP_WORD_BITS; const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; bigint_shr1(m_data.mutable_data(), m_data.size(), shift_words, shift_bits); if(is_negative() && is_zero()) set_sign(Positive); return (*this); } } /* * BigInt Binary Operators * (C) 1999-2007,2018 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { //static BigInt BigInt::add2(const BigInt& x, const word y[], size_t y_words, BigInt::Sign y_sign) { const size_t x_sw = x.sig_words(); BigInt z(x.sign(), std::max(x_sw, y_words) + 1); if(x.sign() == y_sign) { bigint_add3(z.mutable_data(), x.data(), x_sw, y, y_words); } else { const int32_t relative_size = bigint_sub_abs(z.mutable_data(), x.data(), x_sw, y, y_words); //z.sign_fixup(relative_size, y_sign); if(relative_size < 0) z.set_sign(y_sign); else if(relative_size == 0) z.set_sign(BigInt::Positive); } return z; } /* * Multiplication Operator */ BigInt operator*(const BigInt& x, const BigInt& y) { const size_t x_sw = x.sig_words(); const size_t y_sw = y.sig_words(); BigInt z(BigInt::Positive, x.size() + y.size()); if(x_sw == 1 && y_sw) bigint_linmul3(z.mutable_data(), y.data(), y_sw, x.word_at(0)); else if(y_sw == 1 && x_sw) bigint_linmul3(z.mutable_data(), x.data(), x_sw, y.word_at(0)); else if(x_sw && y_sw) { secure_vector workspace(z.size()); bigint_mul(z.mutable_data(), z.size(), x.data(), x.size(), x_sw, y.data(), y.size(), y_sw, workspace.data(), workspace.size()); } z.cond_flip_sign(x_sw > 0 && y_sw > 0 && x.sign() != y.sign()); return z; } /* * Multiplication Operator */ BigInt operator*(const BigInt& x, word y) { const size_t x_sw = x.sig_words(); BigInt z(BigInt::Positive, x_sw + 1); if(x_sw && y) { bigint_linmul3(z.mutable_data(), x.data(), x_sw, y); z.set_sign(x.sign()); } return z; } /* * Division Operator */ BigInt operator/(const BigInt& x, const BigInt& y) { if(y.sig_words() == 1) { return x / y.word_at(0); } BigInt q, r; vartime_divide(x, y, q, r); return q; } /* * Division Operator */ BigInt operator/(const BigInt& x, word y) { if(y == 0) throw BigInt::DivideByZero(); else if(y == 1) return x; else if(y == 2) return (x >> 1); else if(y <= 255) { BigInt q; uint8_t r; ct_divide_u8(x, static_cast(y), q, r); return q; } BigInt q, r; vartime_divide(x, y, q, r); return q; } /* * Modulo Operator */ BigInt operator%(const BigInt& n, const BigInt& mod) { if(mod.is_zero()) throw BigInt::DivideByZero(); if(mod.is_negative()) throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); if(n.is_positive() && mod.is_positive() && n < mod) return n; if(mod.sig_words() == 1) { return n % mod.word_at(0); } BigInt q, r; vartime_divide(n, mod, q, r); return r; } /* * Modulo Operator */ word operator%(const BigInt& n, word mod) { if(mod == 0) throw BigInt::DivideByZero(); if(mod == 1) return 0; word remainder = 0; if(is_power_of_2(mod)) { remainder = (n.word_at(0) & (mod - 1)); } else { const size_t sw = n.sig_words(); for(size_t i = sw; i > 0; --i) { remainder = bigint_modop(remainder, n.word_at(i-1), mod); } } if(remainder && n.sign() == BigInt::Negative) return mod - remainder; return remainder; } /* * Left Shift Operator */ BigInt operator<<(const BigInt& x, size_t shift) { const size_t shift_words = shift / BOTAN_MP_WORD_BITS, shift_bits = shift % BOTAN_MP_WORD_BITS; const size_t x_sw = x.sig_words(); BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); bigint_shl2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); return y; } /* * Right Shift Operator */ BigInt operator>>(const BigInt& x, size_t shift) { const size_t shift_words = shift / BOTAN_MP_WORD_BITS; const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; const size_t x_sw = x.sig_words(); BigInt y(x.sign(), x_sw - shift_words); bigint_shr2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); if(x.is_negative() && y.is_zero()) y.set_sign(BigInt::Positive); return y; } } /* * BigInt Random Generation * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Randomize this number */ void BigInt::randomize(RandomNumberGenerator& rng, size_t bitsize, bool set_high_bit) { set_sign(Positive); if(bitsize == 0) { clear(); } else { secure_vector array = rng.random_vec(round_up(bitsize, 8) / 8); // Always cut unwanted bits if(bitsize % 8) array[0] &= 0xFF >> (8 - (bitsize % 8)); // Set the highest bit if wanted if (set_high_bit) array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0); binary_decode(array); } } /* * Generate a random integer within given range */ BigInt BigInt::random_integer(RandomNumberGenerator& rng, const BigInt& min, const BigInt& max) { if(min.is_negative() || max.is_negative() || max <= min) throw Invalid_Argument("BigInt::random_integer invalid range"); BigInt r; const size_t bits = max.bits(); do { r.randomize(rng, bits, false); } while(r < min || r >= max); return r; } } /* * BigInt Base * (C) 1999-2011,2012,2014,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { BigInt::BigInt(const word words[], size_t length) { m_data.set_words(words, length); } /* * Construct a BigInt from a regular number */ BigInt::BigInt(uint64_t n) { if(n > 0) { #if BOTAN_MP_WORD_BITS == 32 m_data.set_word_at(0, static_cast(n)); m_data.set_word_at(1, static_cast(n >> 32)); #else m_data.set_word_at(0, n); #endif } } /* * Construct a BigInt of the specified size */ BigInt::BigInt(Sign s, size_t size) { m_data.set_size(size); m_signedness = s; } /* * Construct a BigInt from a string */ BigInt::BigInt(const std::string& str) { Base base = Decimal; size_t markers = 0; bool negative = false; if(str.length() > 0 && str[0] == '-') { markers += 1; negative = true; } if(str.length() > markers + 2 && str[markers ] == '0' && str[markers + 1] == 'x') { markers += 2; base = Hexadecimal; } *this = decode(cast_char_ptr_to_uint8(str.data()) + markers, str.length() - markers, base); if(negative) set_sign(Negative); else set_sign(Positive); } BigInt::BigInt(const uint8_t input[], size_t length) { binary_decode(input, length); } /* * Construct a BigInt from an encoded BigInt */ BigInt::BigInt(const uint8_t input[], size_t length, Base base) { *this = decode(input, length, base); } BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits) { if(8 * length > max_bits) length = (max_bits + 7) / 8; binary_decode(buf, length); if(8 * length > max_bits) *this >>= (8 - (max_bits % 8)); } /* * Construct a BigInt from an encoded BigInt */ BigInt::BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit) { randomize(rng, bits, set_high_bit); } uint8_t BigInt::byte_at(size_t n) const { return get_byte(sizeof(word) - (n % sizeof(word)) - 1, word_at(n / sizeof(word))); } int32_t BigInt::cmp_word(word other) const { if(is_negative()) return -1; // other is positive ... const size_t sw = this->sig_words(); if(sw > 1) return 1; // must be larger since other is just one word ... return bigint_cmp(this->data(), sw, &other, 1); } /* * Comparison Function */ int32_t BigInt::cmp(const BigInt& other, bool check_signs) const { if(check_signs) { if(other.is_positive() && this->is_negative()) return -1; if(other.is_negative() && this->is_positive()) return 1; if(other.is_negative() && this->is_negative()) return (-bigint_cmp(this->data(), this->size(), other.data(), other.size())); } return bigint_cmp(this->data(), this->size(), other.data(), other.size()); } bool BigInt::is_equal(const BigInt& other) const { if(this->sign() != other.sign()) return false; return bigint_ct_is_eq(this->data(), this->sig_words(), other.data(), other.sig_words()).is_set(); } bool BigInt::is_less_than(const BigInt& other) const { if(this->is_negative() && other.is_positive()) return true; if(this->is_positive() && other.is_negative()) return false; if(other.is_negative() && this->is_negative()) { return bigint_ct_is_lt(other.data(), other.sig_words(), this->data(), this->sig_words()).is_set(); } return bigint_ct_is_lt(this->data(), this->sig_words(), other.data(), other.sig_words()).is_set(); } void BigInt::encode_words(word out[], size_t size) const { const size_t words = sig_words(); if(words > size) throw Encoding_Error("BigInt::encode_words value too large to encode"); clear_mem(out, size); copy_mem(out, data(), words); } size_t BigInt::Data::calc_sig_words() const { const size_t sz = m_reg.size(); size_t sig = sz; word sub = 1; for(size_t i = 0; i != sz; ++i) { const word w = m_reg[sz - i - 1]; sub &= ct_is_zero(w); sig -= sub; } /* * This depends on the data so is poisoned, but unpoison it here as * later conditionals are made on the size. */ CT::unpoison(sig); return sig; } /* * Return bits {offset...offset+length} */ uint32_t BigInt::get_substring(size_t offset, size_t length) const { if(length == 0 || length > 32) throw Invalid_Argument("BigInt::get_substring invalid substring length"); const uint32_t mask = 0xFFFFFFFF >> (32 - length); const size_t word_offset = offset / BOTAN_MP_WORD_BITS; const size_t wshift = (offset % BOTAN_MP_WORD_BITS); /* * The substring is contained within one or at most two words. The * offset and length are not secret, so we can perform conditional * operations on those values. */ const word w0 = word_at(word_offset); if(wshift == 0 || (offset + length) / BOTAN_MP_WORD_BITS == word_offset) { return static_cast(w0 >> wshift) & mask; } else { const word w1 = word_at(word_offset + 1); return static_cast((w0 >> wshift) | (w1 << (BOTAN_MP_WORD_BITS - wshift))) & mask; } } /* * Convert this number to a uint32_t, if possible */ uint32_t BigInt::to_u32bit() const { if(is_negative()) throw Encoding_Error("BigInt::to_u32bit: Number is negative"); if(bits() > 32) throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); uint32_t out = 0; for(size_t i = 0; i != 4; ++i) out = (out << 8) | byte_at(3-i); return out; } /* * Set bit number n */ void BigInt::conditionally_set_bit(size_t n, bool set_it) { const size_t which = n / BOTAN_MP_WORD_BITS; const word mask = static_cast(set_it) << (n % BOTAN_MP_WORD_BITS); m_data.set_word_at(which, word_at(which) | mask); } /* * Clear bit number n */ void BigInt::clear_bit(size_t n) { const size_t which = n / BOTAN_MP_WORD_BITS; if(which < size()) { const word mask = ~(static_cast(1) << (n % BOTAN_MP_WORD_BITS)); m_data.set_word_at(which, word_at(which) & mask); } } size_t BigInt::bytes() const { return round_up(bits(), 8) / 8; } size_t BigInt::top_bits_free() const { const size_t words = sig_words(); const word top_word = word_at(words - 1); const size_t bits_used = high_bit(top_word); CT::unpoison(bits_used); return BOTAN_MP_WORD_BITS - bits_used; } size_t BigInt::bits() const { const size_t words = sig_words(); if(words == 0) return 0; const size_t full_words = (words - 1) * BOTAN_MP_WORD_BITS; const size_t top_bits = BOTAN_MP_WORD_BITS - top_bits_free(); return full_words + top_bits; } /* * Calcluate the size in a certain base */ size_t BigInt::encoded_size(Base base) const { static const double LOG_2_BASE_10 = 0.30102999566; if(base == Binary) return bytes(); else if(base == Hexadecimal) return 2*bytes(); else if(base == Decimal) return static_cast((bits() * LOG_2_BASE_10) + 1); else throw Invalid_Argument("Unknown base for BigInt encoding"); } /* * Return the negation of this number */ BigInt BigInt::operator-() const { BigInt x = (*this); x.flip_sign(); return x; } size_t BigInt::reduce_below(const BigInt& p, secure_vector& ws) { if(p.is_negative() || this->is_negative()) throw Invalid_Argument("BigInt::reduce_below both values must be positive"); const size_t p_words = p.sig_words(); if(size() < p_words + 1) grow_to(p_words + 1); if(ws.size() < p_words + 1) ws.resize(p_words + 1); clear_mem(ws.data(), ws.size()); size_t reductions = 0; for(;;) { word borrow = bigint_sub3(ws.data(), data(), p_words + 1, p.data(), p_words); if(borrow) break; ++reductions; swap_reg(ws); } return reductions; } void BigInt::ct_reduce_below(const BigInt& mod, secure_vector& ws, size_t bound) { if(mod.is_negative() || this->is_negative()) throw Invalid_Argument("BigInt::ct_reduce_below both values must be positive"); const size_t mod_words = mod.sig_words(); grow_to(mod_words); const size_t sz = size(); ws.resize(sz); clear_mem(ws.data(), sz); for(size_t i = 0; i != bound; ++i) { word borrow = bigint_sub3(ws.data(), data(), sz, mod.data(), mod_words); CT::Mask::is_zero(borrow).select_n(mutable_data(), ws.data(), data(), sz); } } /* * Return the absolute value of this number */ BigInt BigInt::abs() const { BigInt x = (*this); x.set_sign(Positive); return x; } void BigInt::binary_encode(uint8_t buf[]) const { this->binary_encode(buf, bytes()); } /* * Encode this number into bytes */ void BigInt::binary_encode(uint8_t output[], size_t len) const { const size_t full_words = len / sizeof(word); const size_t extra_bytes = len % sizeof(word); for(size_t i = 0; i != full_words; ++i) { const word w = word_at(i); store_be(w, output + (len - (i+1)*sizeof(word))); } if(extra_bytes > 0) { const word w = word_at(full_words); for(size_t i = 0; i != extra_bytes; ++i) { output[extra_bytes - i - 1] = get_byte(sizeof(word) - i - 1, w); } } } /* * Set this number to the value in buf */ void BigInt::binary_decode(const uint8_t buf[], size_t length) { clear(); const size_t full_words = length / sizeof(word); const size_t extra_bytes = length % sizeof(word); secure_vector reg((round_up(full_words + (extra_bytes > 0 ? 1 : 0), 8))); for(size_t i = 0; i != full_words; ++i) { reg[i] = load_be(buf + length - sizeof(word)*(i+1), 0); } if(extra_bytes > 0) { for(size_t i = 0; i != extra_bytes; ++i) reg[full_words] = (reg[full_words] << 8) | buf[i]; } m_data.swap(reg); } void BigInt::ct_cond_add(bool predicate, const BigInt& value) { if(this->is_negative() || value.is_negative()) throw Invalid_Argument("BigInt::ct_cond_add requires both values to be positive"); this->grow_to(1 + value.sig_words()); bigint_cnd_add(static_cast(predicate), this->mutable_data(), this->size(), value.data(), value.sig_words()); } void BigInt::ct_cond_swap(bool predicate, BigInt& other) { const size_t max_words = std::max(size(), other.size()); grow_to(max_words); other.grow_to(max_words); bigint_cnd_swap(predicate, this->mutable_data(), other.mutable_data(), max_words); } void BigInt::cond_flip_sign(bool predicate) { // This code is assuming Negative == 0, Positive == 1 const auto mask = CT::Mask::expand(predicate); const uint8_t current_sign = static_cast(sign()); const uint8_t new_sign = mask.select(current_sign ^ 1, current_sign); set_sign(static_cast(new_sign)); } void BigInt::ct_cond_assign(bool predicate, const BigInt& other) { const size_t t_words = size(); const size_t o_words = other.size(); if(o_words < t_words) grow_to(o_words); const size_t r_words = std::max(t_words, o_words); const auto mask = CT::Mask::expand(predicate); for(size_t i = 0; i != r_words; ++i) { const word o_word = other.word_at(i); const word t_word = this->word_at(i); this->set_word_at(i, mask.select(o_word, t_word)); } const bool different_sign = sign() != other.sign(); cond_flip_sign(predicate && different_sign); } #if defined(BOTAN_HAS_VALGRIND) void BigInt::const_time_poison() const { CT::poison(m_data.const_data(), m_data.size()); } void BigInt::const_time_unpoison() const { CT::unpoison(m_data.const_data(), m_data.size()); } #endif void BigInt::const_time_lookup(secure_vector& output, const std::vector& vec, size_t idx) { const size_t words = output.size(); clear_mem(output.data(), output.size()); CT::poison(&idx, sizeof(idx)); for(size_t i = 0; i != vec.size(); ++i) { BOTAN_ASSERT(vec[i].size() >= words, "Word size as expected in const_time_lookup"); const auto mask = CT::Mask::is_equal(i, idx); for(size_t w = 0; w != words; ++w) { const word viw = vec[i].word_at(w); output[w] = mask.if_set_return(viw); } } CT::unpoison(idx); CT::unpoison(output.data(), output.size()); } } /* * Division Algorithm * (C) 1999-2007,2012,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Handle signed operands, if necessary */ void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) { q.cond_flip_sign(x.sign() != y.sign()); if(x.is_negative() && r.is_nonzero()) { q -= 1; r = y.abs() - r; } } inline bool division_check(word q, word y2, word y1, word x3, word x2, word x1) { /* Compute (y3,y2,y1) = (y2,y1) * q and return true if (y3,y2,y1) > (x3,x2,x1) */ word y3 = 0; y1 = word_madd2(q, y1, &y3); y2 = word_madd2(q, y2, &y3); const word x[3] = { x1, x2, x3 }; const word y[3] = { y1, y2, y3 }; return bigint_ct_is_lt(x, 3, y, 3).is_set(); } } void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out) { const size_t x_words = x.sig_words(); const size_t y_words = y.sig_words(); const size_t x_bits = x.bits(); BigInt q(BigInt::Positive, x_words); BigInt r(BigInt::Positive, y_words); BigInt t(BigInt::Positive, y_words); // a temporary for(size_t i = 0; i != x_bits; ++i) { const size_t b = x_bits - 1 - i; const bool x_b = x.get_bit(b); r *= 2; r.conditionally_set_bit(0, x_b); const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0; q.conditionally_set_bit(b, r_gte_y); r.ct_cond_swap(r_gte_y, t); } sign_fixup(x, y, q, r); r_out = r; q_out = q; } void ct_divide_u8(const BigInt& x, uint8_t y, BigInt& q_out, uint8_t& r_out) { const size_t x_words = x.sig_words(); const size_t x_bits = x.bits(); BigInt q(BigInt::Positive, x_words); uint32_t r = 0; for(size_t i = 0; i != x_bits; ++i) { const size_t b = x_bits - 1 - i; const bool x_b = x.get_bit(b); r *= 2; r += x_b; const auto r_gte_y = CT::Mask::is_gte(r, y); q.conditionally_set_bit(b, r_gte_y.is_set()); r = r_gte_y.select(r - y, r); } if(x.is_negative()) { q.flip_sign(); if(r != 0) { --q; r = y - r; } } r_out = static_cast(r); q_out = q; } BigInt ct_modulo(const BigInt& x, const BigInt& y) { if(y.is_negative() || y.is_zero()) throw Invalid_Argument("ct_modulo requires y > 0"); const size_t y_words = y.sig_words(); const size_t x_bits = x.bits(); BigInt r(BigInt::Positive, y_words); BigInt t(BigInt::Positive, y_words); for(size_t i = 0; i != x_bits; ++i) { const size_t b = x_bits - 1 - i; const bool x_b = x.get_bit(b); r *= 2; r.conditionally_set_bit(0, x_b); const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0; r.ct_cond_swap(r_gte_y, t); } if(x.is_negative()) { if(r.is_nonzero()) { r = y - r; } } return r; } /* * Solve x = q * y + r * * See Handbook of Applied Cryptography section 14.2.5 */ void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out) { if(y_arg.is_zero()) throw BigInt::DivideByZero(); const size_t y_words = y_arg.sig_words(); BOTAN_ASSERT_NOMSG(y_words > 0); BigInt y = y_arg; BigInt r = x; BigInt q = 0; secure_vector ws; r.set_sign(BigInt::Positive); y.set_sign(BigInt::Positive); // Calculate shifts needed to normalize y with high bit set const size_t shifts = y.top_bits_free(); y <<= shifts; r <<= shifts; // we know y has not changed size, since we only shifted up to set high bit const size_t t = y_words - 1; const size_t n = std::max(y_words, r.sig_words()) - 1; // r may have changed size however BOTAN_ASSERT_NOMSG(n >= t); q.grow_to(n - t + 1); word* q_words = q.mutable_data(); BigInt shifted_y = y << (BOTAN_MP_WORD_BITS * (n-t)); // Set q_{n-t} to number of times r > shifted_y q_words[n-t] = r.reduce_below(shifted_y, ws); const word y_t0 = y.word_at(t); const word y_t1 = y.word_at(t-1); BOTAN_DEBUG_ASSERT((y_t0 >> (BOTAN_MP_WORD_BITS-1)) == 1); for(size_t j = n; j != t; --j) { const word x_j0 = r.word_at(j); const word x_j1 = r.word_at(j-1); const word x_j2 = r.word_at(j-2); word qjt = bigint_divop(x_j0, x_j1, y_t0); qjt = CT::Mask::is_equal(x_j0, y_t0).select(MP_WORD_MAX, qjt); // Per HAC 14.23, this operation is required at most twice qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2); qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2); BOTAN_DEBUG_ASSERT(division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2) == false); shifted_y >>= BOTAN_MP_WORD_BITS; // Now shifted_y == y << (BOTAN_MP_WORD_BITS * (j-t-1)) // TODO this sequence could be better r -= qjt * shifted_y; qjt -= r.is_negative(); r += static_cast(r.is_negative()) * shifted_y; q_words[j-t-1] = qjt; } r >>= shifts; sign_fixup(x, y_arg, q, r); r_out = r; q_out = q; } } /* * BLAKE2b * (C) 2016 cynecx * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { enum blake2b_constant { BLAKE2B_BLOCKBYTES = 128, BLAKE2B_IVU64COUNT = 8 }; const uint64_t blake2b_IV[BLAKE2B_IVU64COUNT] = { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 }; } BLAKE2b::BLAKE2b(size_t output_bits) : m_output_bits(output_bits), m_buffer(BLAKE2B_BLOCKBYTES), m_bufpos(0), m_H(BLAKE2B_IVU64COUNT) { if(output_bits == 0 || output_bits > 512 || output_bits % 8 != 0) { throw Invalid_Argument("Bad output bits size for BLAKE2b"); } state_init(); } void BLAKE2b::state_init() { copy_mem(m_H.data(), blake2b_IV, BLAKE2B_IVU64COUNT); m_H[0] ^= 0x01010000 ^ static_cast(output_length()); m_T[0] = m_T[1] = 0; m_F[0] = m_F[1] = 0; m_bufpos = 0; } namespace { BOTAN_FORCE_INLINE void G(uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d, uint64_t M0, uint64_t M1) { a = a + b + M0; d = rotr<32>(d ^ a); c = c + d; b = rotr<24>(b ^ c); a = a + b + M1; d = rotr<16>(d ^ a); c = c + d; b = rotr<63>(b ^ c); } template BOTAN_FORCE_INLINE void ROUND(uint64_t* v, const uint64_t* M) { G(v[ 0], v[ 4], v[ 8], v[12], M[i0], M[i1]); G(v[ 1], v[ 5], v[ 9], v[13], M[i2], M[i3]); G(v[ 2], v[ 6], v[10], v[14], M[i4], M[i5]); G(v[ 3], v[ 7], v[11], v[15], M[i6], M[i7]); G(v[ 0], v[ 5], v[10], v[15], M[i8], M[i9]); G(v[ 1], v[ 6], v[11], v[12], M[iA], M[iB]); G(v[ 2], v[ 7], v[ 8], v[13], M[iC], M[iD]); G(v[ 3], v[ 4], v[ 9], v[14], M[iE], M[iF]); } } void BLAKE2b::compress(const uint8_t* input, size_t blocks, uint64_t increment) { for(size_t b = 0; b != blocks; ++b) { m_T[0] += increment; if(m_T[0] < increment) { m_T[1]++; } uint64_t M[16]; uint64_t v[16]; load_le(M, input, 16); input += BLAKE2B_BLOCKBYTES; for(size_t i = 0; i < 8; i++) v[i] = m_H[i]; for(size_t i = 0; i != 8; ++i) v[i + 8] = blake2b_IV[i]; v[12] ^= m_T[0]; v[13] ^= m_T[1]; v[14] ^= m_F[0]; v[15] ^= m_F[1]; ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M); ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M); ROUND<11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4>(v, M); ROUND< 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8>(v, M); ROUND< 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13>(v, M); ROUND< 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9>(v, M); ROUND<12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11>(v, M); ROUND<13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10>(v, M); ROUND< 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5>(v, M); ROUND<10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0>(v, M); ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M); ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M); for(size_t i = 0; i < 8; i++) { m_H[i] ^= v[i] ^ v[i + 8]; } } } void BLAKE2b::add_data(const uint8_t input[], size_t length) { if(length == 0) return; if(m_bufpos > 0) { if(m_bufpos < BLAKE2B_BLOCKBYTES) { const size_t take = std::min(BLAKE2B_BLOCKBYTES - m_bufpos, length); copy_mem(&m_buffer[m_bufpos], input, take); m_bufpos += take; length -= take; input += take; } if(m_bufpos == m_buffer.size() && length > 0) { compress(m_buffer.data(), 1, BLAKE2B_BLOCKBYTES); m_bufpos = 0; } } if(length > BLAKE2B_BLOCKBYTES) { const size_t full_blocks = ((length-1) / BLAKE2B_BLOCKBYTES); compress(input, full_blocks, BLAKE2B_BLOCKBYTES); input += full_blocks * BLAKE2B_BLOCKBYTES; length -= full_blocks * BLAKE2B_BLOCKBYTES; } if(length > 0) { copy_mem(&m_buffer[m_bufpos], input, length); m_bufpos += length; } } void BLAKE2b::final_result(uint8_t output[]) { if(m_bufpos != BLAKE2B_BLOCKBYTES) clear_mem(&m_buffer[m_bufpos], BLAKE2B_BLOCKBYTES - m_bufpos); m_F[0] = 0xFFFFFFFFFFFFFFFF; compress(m_buffer.data(), 1, m_bufpos); copy_out_vec_le(output, output_length(), m_H); state_init(); } std::string BLAKE2b::name() const { return "BLAKE2b(" + std::to_string(m_output_bits) + ")"; } HashFunction* BLAKE2b::clone() const { return new BLAKE2b(m_output_bits); } std::unique_ptr BLAKE2b::copy_state() const { return std::unique_ptr(new BLAKE2b(*this)); } void BLAKE2b::clear() { zeroise(m_H); zeroise(m_buffer); m_bufpos = 0; state_init(); } } /* * Block Ciphers * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_AES) #endif #if defined(BOTAN_HAS_ARIA) #endif #if defined(BOTAN_HAS_BLOWFISH) #endif #if defined(BOTAN_HAS_CAMELLIA) #endif #if defined(BOTAN_HAS_CAST_128) #endif #if defined(BOTAN_HAS_CAST_256) #endif #if defined(BOTAN_HAS_CASCADE) #endif #if defined(BOTAN_HAS_DES) #endif #if defined(BOTAN_HAS_GOST_28147_89) #endif #if defined(BOTAN_HAS_IDEA) #endif #if defined(BOTAN_HAS_KASUMI) #endif #if defined(BOTAN_HAS_LION) #endif #if defined(BOTAN_HAS_MISTY1) #endif #if defined(BOTAN_HAS_NOEKEON) #endif #if defined(BOTAN_HAS_SEED) #endif #if defined(BOTAN_HAS_SERPENT) #endif #if defined(BOTAN_HAS_SHACAL2) #endif #if defined(BOTAN_HAS_SM4) #endif #if defined(BOTAN_HAS_TWOFISH) #endif #if defined(BOTAN_HAS_THREEFISH_512) #endif #if defined(BOTAN_HAS_XTEA) #endif #if defined(BOTAN_HAS_OPENSSL) #endif #if defined(BOTAN_HAS_COMMONCRYPTO) #endif namespace Botan { std::unique_ptr BlockCipher::create(const std::string& algo, const std::string& provider) { #if defined(BOTAN_HAS_COMMONCRYPTO) if(provider.empty() || provider == "commoncrypto") { if(auto bc = make_commoncrypto_block_cipher(algo)) return bc; if(!provider.empty()) return nullptr; } #endif #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { if(auto bc = make_openssl_block_cipher(algo)) return bc; if(!provider.empty()) return nullptr; } #endif // TODO: CryptoAPI // TODO: /dev/crypto // Only base providers from here on out if(provider.empty() == false && provider != "base") return nullptr; #if defined(BOTAN_HAS_AES) if(algo == "AES-128") { return std::unique_ptr(new AES_128); } if(algo == "AES-192") { return std::unique_ptr(new AES_192); } if(algo == "AES-256") { return std::unique_ptr(new AES_256); } #endif #if defined(BOTAN_HAS_ARIA) if(algo == "ARIA-128") { return std::unique_ptr(new ARIA_128); } if(algo == "ARIA-192") { return std::unique_ptr(new ARIA_192); } if(algo == "ARIA-256") { return std::unique_ptr(new ARIA_256); } #endif #if defined(BOTAN_HAS_SERPENT) if(algo == "Serpent") { return std::unique_ptr(new Serpent); } #endif #if defined(BOTAN_HAS_SHACAL2) if(algo == "SHACAL2") { return std::unique_ptr(new SHACAL2); } #endif #if defined(BOTAN_HAS_TWOFISH) if(algo == "Twofish") { return std::unique_ptr(new Twofish); } #endif #if defined(BOTAN_HAS_THREEFISH_512) if(algo == "Threefish-512") { return std::unique_ptr(new Threefish_512); } #endif #if defined(BOTAN_HAS_BLOWFISH) if(algo == "Blowfish") { return std::unique_ptr(new Blowfish); } #endif #if defined(BOTAN_HAS_CAMELLIA) if(algo == "Camellia-128") { return std::unique_ptr(new Camellia_128); } if(algo == "Camellia-192") { return std::unique_ptr(new Camellia_192); } if(algo == "Camellia-256") { return std::unique_ptr(new Camellia_256); } #endif #if defined(BOTAN_HAS_DES) if(algo == "DES") { return std::unique_ptr(new DES); } if(algo == "DESX") { return std::unique_ptr(new DESX); } if(algo == "TripleDES" || algo == "3DES" || algo == "DES-EDE") { return std::unique_ptr(new TripleDES); } #endif #if defined(BOTAN_HAS_NOEKEON) if(algo == "Noekeon") { return std::unique_ptr(new Noekeon); } #endif #if defined(BOTAN_HAS_CAST_128) if(algo == "CAST-128" || algo == "CAST5") { return std::unique_ptr(new CAST_128); } #endif #if defined(BOTAN_HAS_CAST_256) if(algo == "CAST-256") { return std::unique_ptr(new CAST_256); } #endif #if defined(BOTAN_HAS_IDEA) if(algo == "IDEA") { return std::unique_ptr(new IDEA); } #endif #if defined(BOTAN_HAS_KASUMI) if(algo == "KASUMI") { return std::unique_ptr(new KASUMI); } #endif #if defined(BOTAN_HAS_MISTY1) if(algo == "MISTY1") { return std::unique_ptr(new MISTY1); } #endif #if defined(BOTAN_HAS_SEED) if(algo == "SEED") { return std::unique_ptr(new SEED); } #endif #if defined(BOTAN_HAS_SM4) if(algo == "SM4") { return std::unique_ptr(new SM4); } #endif #if defined(BOTAN_HAS_XTEA) if(algo == "XTEA") { return std::unique_ptr(new XTEA); } #endif const SCAN_Name req(algo); #if defined(BOTAN_HAS_GOST_28147_89) if(req.algo_name() == "GOST-28147-89") { return std::unique_ptr(new GOST_28147_89(req.arg(0, "R3411_94_TestParam"))); } #endif #if defined(BOTAN_HAS_CASCADE) if(req.algo_name() == "Cascade" && req.arg_count() == 2) { std::unique_ptr c1(BlockCipher::create(req.arg(0))); std::unique_ptr c2(BlockCipher::create(req.arg(1))); if(c1 && c2) return std::unique_ptr(new Cascade_Cipher(c1.release(), c2.release())); } #endif #if defined(BOTAN_HAS_LION) if(req.algo_name() == "Lion" && req.arg_count_between(2, 3)) { std::unique_ptr hash(HashFunction::create(req.arg(0))); std::unique_ptr stream(StreamCipher::create(req.arg(1))); if(hash && stream) { const size_t block_size = req.arg_as_integer(2, 1024); return std::unique_ptr(new Lion(hash.release(), stream.release(), block_size)); } } #endif BOTAN_UNUSED(req); BOTAN_UNUSED(provider); return nullptr; } //static std::unique_ptr BlockCipher::create_or_throw(const std::string& algo, const std::string& provider) { if(auto bc = BlockCipher::create(algo, provider)) { return bc; } throw Lookup_Error("Block cipher", algo, provider); } std::vector BlockCipher::providers(const std::string& algo) { return probe_providers_of(algo, { "base", "openssl", "commoncrypto" }); } } /* * Blowfish * (C) 1999-2011,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { const uint32_t P_INIT[18] = { 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B }; const uint32_t S_INIT[1024] = { 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7, 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 }; inline uint32_t BFF(uint32_t X, const secure_vector& S) { return ((S[ get_byte(0, X)] + S[256+get_byte(1, X)]) ^ S[512+get_byte(2, X)]) + S[768+get_byte(3, X)]; } } /* * Blowfish Encryption */ void Blowfish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_S.empty() == false); while(blocks >= 4) { uint32_t L0, R0, L1, R1, L2, R2, L3, R3; load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); for(size_t r = 0; r != 16; r += 2) { L0 ^= m_P[r]; L1 ^= m_P[r]; L2 ^= m_P[r]; L3 ^= m_P[r]; R0 ^= BFF(L0, m_S); R1 ^= BFF(L1, m_S); R2 ^= BFF(L2, m_S); R3 ^= BFF(L3, m_S); R0 ^= m_P[r+1]; R1 ^= m_P[r+1]; R2 ^= m_P[r+1]; R3 ^= m_P[r+1]; L0 ^= BFF(R0, m_S); L1 ^= BFF(R1, m_S); L2 ^= BFF(R2, m_S); L3 ^= BFF(R3, m_S); } L0 ^= m_P[16]; R0 ^= m_P[17]; L1 ^= m_P[16]; R1 ^= m_P[17]; L2 ^= m_P[16]; R2 ^= m_P[17]; L3 ^= m_P[16]; R3 ^= m_P[17]; store_be(out, R0, L0, R1, L1, R2, L2, R3, L3); in += 4*BLOCK_SIZE; out += 4*BLOCK_SIZE; blocks -= 4; } while(blocks) { uint32_t L, R; load_be(in, L, R); for(size_t r = 0; r != 16; r += 2) { L ^= m_P[r]; R ^= BFF(L, m_S); R ^= m_P[r+1]; L ^= BFF(R, m_S); } L ^= m_P[16]; R ^= m_P[17]; store_be(out, R, L); in += BLOCK_SIZE; out += BLOCK_SIZE; blocks--; } } /* * Blowfish Decryption */ void Blowfish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_S.empty() == false); while(blocks >= 4) { uint32_t L0, R0, L1, R1, L2, R2, L3, R3; load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); for(size_t r = 17; r != 1; r -= 2) { L0 ^= m_P[r]; L1 ^= m_P[r]; L2 ^= m_P[r]; L3 ^= m_P[r]; R0 ^= BFF(L0, m_S); R1 ^= BFF(L1, m_S); R2 ^= BFF(L2, m_S); R3 ^= BFF(L3, m_S); R0 ^= m_P[r-1]; R1 ^= m_P[r-1]; R2 ^= m_P[r-1]; R3 ^= m_P[r-1]; L0 ^= BFF(R0, m_S); L1 ^= BFF(R1, m_S); L2 ^= BFF(R2, m_S); L3 ^= BFF(R3, m_S); } L0 ^= m_P[1]; R0 ^= m_P[0]; L1 ^= m_P[1]; R1 ^= m_P[0]; L2 ^= m_P[1]; R2 ^= m_P[0]; L3 ^= m_P[1]; R3 ^= m_P[0]; store_be(out, R0, L0, R1, L1, R2, L2, R3, L3); in += 4*BLOCK_SIZE; out += 4*BLOCK_SIZE; blocks -= 4; } while(blocks) { uint32_t L, R; load_be(in, L, R); for(size_t r = 17; r != 1; r -= 2) { L ^= m_P[r]; R ^= BFF(L, m_S); R ^= m_P[r-1]; L ^= BFF(R, m_S); } L ^= m_P[1]; R ^= m_P[0]; store_be(out, R, L); in += BLOCK_SIZE; out += BLOCK_SIZE; blocks--; } } /* * Blowfish Key Schedule */ void Blowfish::key_schedule(const uint8_t key[], size_t length) { m_P.resize(18); copy_mem(m_P.data(), P_INIT, 18); m_S.resize(1024); copy_mem(m_S.data(), S_INIT, 1024); key_expansion(key, length, nullptr, 0); } void Blowfish::key_expansion(const uint8_t key[], size_t length, const uint8_t salt[], size_t salt_length) { BOTAN_ASSERT_NOMSG(salt_length % 4 == 0); for(size_t i = 0, j = 0; i != 18; ++i, j += 4) m_P[i] ^= make_uint32(key[(j ) % length], key[(j+1) % length], key[(j+2) % length], key[(j+3) % length]); const size_t P_salt_offset = (salt_length > 0) ? 18 % (salt_length / 4) : 0; uint32_t L = 0, R = 0; generate_sbox(m_P, L, R, salt, salt_length, 0); generate_sbox(m_S, L, R, salt, salt_length, P_salt_offset); } /* * Modified key schedule used for bcrypt password hashing */ void Blowfish::salted_set_key(const uint8_t key[], size_t length, const uint8_t salt[], size_t salt_length, size_t workfactor, bool salt_first) { BOTAN_ARG_CHECK(salt_length > 0 && salt_length % 4 == 0, "Invalid salt length for Blowfish salted key schedule"); if(length > 72) { // Truncate longer passwords to the 72 char bcrypt limit length = 72; } m_P.resize(18); copy_mem(m_P.data(), P_INIT, 18); m_S.resize(1024); copy_mem(m_S.data(), S_INIT, 1024); key_expansion(key, length, salt, salt_length); if(workfactor > 0) { const size_t rounds = static_cast(1) << workfactor; for(size_t r = 0; r != rounds; ++r) { if(salt_first) { key_expansion(salt, salt_length, nullptr, 0); key_expansion(key, length, nullptr, 0); } else { key_expansion(key, length, nullptr, 0); key_expansion(salt, salt_length, nullptr, 0); } } } } /* * Generate one of the Sboxes */ void Blowfish::generate_sbox(secure_vector& box, uint32_t& L, uint32_t& R, const uint8_t salt[], size_t salt_length, size_t salt_off) const { for(size_t i = 0; i != box.size(); i += 2) { if(salt_length > 0) { L ^= load_be(salt, (i + salt_off) % (salt_length / 4)); R ^= load_be(salt, (i + salt_off + 1) % (salt_length / 4)); } for(size_t r = 0; r != 16; r += 2) { L ^= m_P[r]; R ^= BFF(L, m_S); R ^= m_P[r+1]; L ^= BFF(R, m_S); } uint32_t T = R; R = L ^ m_P[16]; L = T ^ m_P[17]; box[i] = L; box[i+1] = R; } } /* * Clear memory of sensitive data */ void Blowfish::clear() { zap(m_P); zap(m_S); } } /* * Camellia * (C) 2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { alignas(64) const uint64_t Camellia_SBOX1[256] = { 0x7070700070000070, 0x8282820082000082, 0x2C2C2C002C00002C, 0xECECEC00EC0000EC, 0xB3B3B300B30000B3, 0x2727270027000027, 0xC0C0C000C00000C0, 0xE5E5E500E50000E5, 0xE4E4E400E40000E4, 0x8585850085000085, 0x5757570057000057, 0x3535350035000035, 0xEAEAEA00EA0000EA, 0x0C0C0C000C00000C, 0xAEAEAE00AE0000AE, 0x4141410041000041, 0x2323230023000023, 0xEFEFEF00EF0000EF, 0x6B6B6B006B00006B, 0x9393930093000093, 0x4545450045000045, 0x1919190019000019, 0xA5A5A500A50000A5, 0x2121210021000021, 0xEDEDED00ED0000ED, 0x0E0E0E000E00000E, 0x4F4F4F004F00004F, 0x4E4E4E004E00004E, 0x1D1D1D001D00001D, 0x6565650065000065, 0x9292920092000092, 0xBDBDBD00BD0000BD, 0x8686860086000086, 0xB8B8B800B80000B8, 0xAFAFAF00AF0000AF, 0x8F8F8F008F00008F, 0x7C7C7C007C00007C, 0xEBEBEB00EB0000EB, 0x1F1F1F001F00001F, 0xCECECE00CE0000CE, 0x3E3E3E003E00003E, 0x3030300030000030, 0xDCDCDC00DC0000DC, 0x5F5F5F005F00005F, 0x5E5E5E005E00005E, 0xC5C5C500C50000C5, 0x0B0B0B000B00000B, 0x1A1A1A001A00001A, 0xA6A6A600A60000A6, 0xE1E1E100E10000E1, 0x3939390039000039, 0xCACACA00CA0000CA, 0xD5D5D500D50000D5, 0x4747470047000047, 0x5D5D5D005D00005D, 0x3D3D3D003D00003D, 0xD9D9D900D90000D9, 0x0101010001000001, 0x5A5A5A005A00005A, 0xD6D6D600D60000D6, 0x5151510051000051, 0x5656560056000056, 0x6C6C6C006C00006C, 0x4D4D4D004D00004D, 0x8B8B8B008B00008B, 0x0D0D0D000D00000D, 0x9A9A9A009A00009A, 0x6666660066000066, 0xFBFBFB00FB0000FB, 0xCCCCCC00CC0000CC, 0xB0B0B000B00000B0, 0x2D2D2D002D00002D, 0x7474740074000074, 0x1212120012000012, 0x2B2B2B002B00002B, 0x2020200020000020, 0xF0F0F000F00000F0, 0xB1B1B100B10000B1, 0x8484840084000084, 0x9999990099000099, 0xDFDFDF00DF0000DF, 0x4C4C4C004C00004C, 0xCBCBCB00CB0000CB, 0xC2C2C200C20000C2, 0x3434340034000034, 0x7E7E7E007E00007E, 0x7676760076000076, 0x0505050005000005, 0x6D6D6D006D00006D, 0xB7B7B700B70000B7, 0xA9A9A900A90000A9, 0x3131310031000031, 0xD1D1D100D10000D1, 0x1717170017000017, 0x0404040004000004, 0xD7D7D700D70000D7, 0x1414140014000014, 0x5858580058000058, 0x3A3A3A003A00003A, 0x6161610061000061, 0xDEDEDE00DE0000DE, 0x1B1B1B001B00001B, 0x1111110011000011, 0x1C1C1C001C00001C, 0x3232320032000032, 0x0F0F0F000F00000F, 0x9C9C9C009C00009C, 0x1616160016000016, 0x5353530053000053, 0x1818180018000018, 0xF2F2F200F20000F2, 0x2222220022000022, 0xFEFEFE00FE0000FE, 0x4444440044000044, 0xCFCFCF00CF0000CF, 0xB2B2B200B20000B2, 0xC3C3C300C30000C3, 0xB5B5B500B50000B5, 0x7A7A7A007A00007A, 0x9191910091000091, 0x2424240024000024, 0x0808080008000008, 0xE8E8E800E80000E8, 0xA8A8A800A80000A8, 0x6060600060000060, 0xFCFCFC00FC0000FC, 0x6969690069000069, 0x5050500050000050, 0xAAAAAA00AA0000AA, 0xD0D0D000D00000D0, 0xA0A0A000A00000A0, 0x7D7D7D007D00007D, 0xA1A1A100A10000A1, 0x8989890089000089, 0x6262620062000062, 0x9797970097000097, 0x5454540054000054, 0x5B5B5B005B00005B, 0x1E1E1E001E00001E, 0x9595950095000095, 0xE0E0E000E00000E0, 0xFFFFFF00FF0000FF, 0x6464640064000064, 0xD2D2D200D20000D2, 0x1010100010000010, 0xC4C4C400C40000C4, 0x0000000000000000, 0x4848480048000048, 0xA3A3A300A30000A3, 0xF7F7F700F70000F7, 0x7575750075000075, 0xDBDBDB00DB0000DB, 0x8A8A8A008A00008A, 0x0303030003000003, 0xE6E6E600E60000E6, 0xDADADA00DA0000DA, 0x0909090009000009, 0x3F3F3F003F00003F, 0xDDDDDD00DD0000DD, 0x9494940094000094, 0x8787870087000087, 0x5C5C5C005C00005C, 0x8383830083000083, 0x0202020002000002, 0xCDCDCD00CD0000CD, 0x4A4A4A004A00004A, 0x9090900090000090, 0x3333330033000033, 0x7373730073000073, 0x6767670067000067, 0xF6F6F600F60000F6, 0xF3F3F300F30000F3, 0x9D9D9D009D00009D, 0x7F7F7F007F00007F, 0xBFBFBF00BF0000BF, 0xE2E2E200E20000E2, 0x5252520052000052, 0x9B9B9B009B00009B, 0xD8D8D800D80000D8, 0x2626260026000026, 0xC8C8C800C80000C8, 0x3737370037000037, 0xC6C6C600C60000C6, 0x3B3B3B003B00003B, 0x8181810081000081, 0x9696960096000096, 0x6F6F6F006F00006F, 0x4B4B4B004B00004B, 0x1313130013000013, 0xBEBEBE00BE0000BE, 0x6363630063000063, 0x2E2E2E002E00002E, 0xE9E9E900E90000E9, 0x7979790079000079, 0xA7A7A700A70000A7, 0x8C8C8C008C00008C, 0x9F9F9F009F00009F, 0x6E6E6E006E00006E, 0xBCBCBC00BC0000BC, 0x8E8E8E008E00008E, 0x2929290029000029, 0xF5F5F500F50000F5, 0xF9F9F900F90000F9, 0xB6B6B600B60000B6, 0x2F2F2F002F00002F, 0xFDFDFD00FD0000FD, 0xB4B4B400B40000B4, 0x5959590059000059, 0x7878780078000078, 0x9898980098000098, 0x0606060006000006, 0x6A6A6A006A00006A, 0xE7E7E700E70000E7, 0x4646460046000046, 0x7171710071000071, 0xBABABA00BA0000BA, 0xD4D4D400D40000D4, 0x2525250025000025, 0xABABAB00AB0000AB, 0x4242420042000042, 0x8888880088000088, 0xA2A2A200A20000A2, 0x8D8D8D008D00008D, 0xFAFAFA00FA0000FA, 0x7272720072000072, 0x0707070007000007, 0xB9B9B900B90000B9, 0x5555550055000055, 0xF8F8F800F80000F8, 0xEEEEEE00EE0000EE, 0xACACAC00AC0000AC, 0x0A0A0A000A00000A, 0x3636360036000036, 0x4949490049000049, 0x2A2A2A002A00002A, 0x6868680068000068, 0x3C3C3C003C00003C, 0x3838380038000038, 0xF1F1F100F10000F1, 0xA4A4A400A40000A4, 0x4040400040000040, 0x2828280028000028, 0xD3D3D300D30000D3, 0x7B7B7B007B00007B, 0xBBBBBB00BB0000BB, 0xC9C9C900C90000C9, 0x4343430043000043, 0xC1C1C100C10000C1, 0x1515150015000015, 0xE3E3E300E30000E3, 0xADADAD00AD0000AD, 0xF4F4F400F40000F4, 0x7777770077000077, 0xC7C7C700C70000C7, 0x8080800080000080, 0x9E9E9E009E00009E }; alignas(64) const uint64_t Camellia_SBOX2[256] = { 0x00E0E0E0E0E00000, 0x0005050505050000, 0x0058585858580000, 0x00D9D9D9D9D90000, 0x0067676767670000, 0x004E4E4E4E4E0000, 0x0081818181810000, 0x00CBCBCBCBCB0000, 0x00C9C9C9C9C90000, 0x000B0B0B0B0B0000, 0x00AEAEAEAEAE0000, 0x006A6A6A6A6A0000, 0x00D5D5D5D5D50000, 0x0018181818180000, 0x005D5D5D5D5D0000, 0x0082828282820000, 0x0046464646460000, 0x00DFDFDFDFDF0000, 0x00D6D6D6D6D60000, 0x0027272727270000, 0x008A8A8A8A8A0000, 0x0032323232320000, 0x004B4B4B4B4B0000, 0x0042424242420000, 0x00DBDBDBDBDB0000, 0x001C1C1C1C1C0000, 0x009E9E9E9E9E0000, 0x009C9C9C9C9C0000, 0x003A3A3A3A3A0000, 0x00CACACACACA0000, 0x0025252525250000, 0x007B7B7B7B7B0000, 0x000D0D0D0D0D0000, 0x0071717171710000, 0x005F5F5F5F5F0000, 0x001F1F1F1F1F0000, 0x00F8F8F8F8F80000, 0x00D7D7D7D7D70000, 0x003E3E3E3E3E0000, 0x009D9D9D9D9D0000, 0x007C7C7C7C7C0000, 0x0060606060600000, 0x00B9B9B9B9B90000, 0x00BEBEBEBEBE0000, 0x00BCBCBCBCBC0000, 0x008B8B8B8B8B0000, 0x0016161616160000, 0x0034343434340000, 0x004D4D4D4D4D0000, 0x00C3C3C3C3C30000, 0x0072727272720000, 0x0095959595950000, 0x00ABABABABAB0000, 0x008E8E8E8E8E0000, 0x00BABABABABA0000, 0x007A7A7A7A7A0000, 0x00B3B3B3B3B30000, 0x0002020202020000, 0x00B4B4B4B4B40000, 0x00ADADADADAD0000, 0x00A2A2A2A2A20000, 0x00ACACACACAC0000, 0x00D8D8D8D8D80000, 0x009A9A9A9A9A0000, 0x0017171717170000, 0x001A1A1A1A1A0000, 0x0035353535350000, 0x00CCCCCCCCCC0000, 0x00F7F7F7F7F70000, 0x0099999999990000, 0x0061616161610000, 0x005A5A5A5A5A0000, 0x00E8E8E8E8E80000, 0x0024242424240000, 0x0056565656560000, 0x0040404040400000, 0x00E1E1E1E1E10000, 0x0063636363630000, 0x0009090909090000, 0x0033333333330000, 0x00BFBFBFBFBF0000, 0x0098989898980000, 0x0097979797970000, 0x0085858585850000, 0x0068686868680000, 0x00FCFCFCFCFC0000, 0x00ECECECECEC0000, 0x000A0A0A0A0A0000, 0x00DADADADADA0000, 0x006F6F6F6F6F0000, 0x0053535353530000, 0x0062626262620000, 0x00A3A3A3A3A30000, 0x002E2E2E2E2E0000, 0x0008080808080000, 0x00AFAFAFAFAF0000, 0x0028282828280000, 0x00B0B0B0B0B00000, 0x0074747474740000, 0x00C2C2C2C2C20000, 0x00BDBDBDBDBD0000, 0x0036363636360000, 0x0022222222220000, 0x0038383838380000, 0x0064646464640000, 0x001E1E1E1E1E0000, 0x0039393939390000, 0x002C2C2C2C2C0000, 0x00A6A6A6A6A60000, 0x0030303030300000, 0x00E5E5E5E5E50000, 0x0044444444440000, 0x00FDFDFDFDFD0000, 0x0088888888880000, 0x009F9F9F9F9F0000, 0x0065656565650000, 0x0087878787870000, 0x006B6B6B6B6B0000, 0x00F4F4F4F4F40000, 0x0023232323230000, 0x0048484848480000, 0x0010101010100000, 0x00D1D1D1D1D10000, 0x0051515151510000, 0x00C0C0C0C0C00000, 0x00F9F9F9F9F90000, 0x00D2D2D2D2D20000, 0x00A0A0A0A0A00000, 0x0055555555550000, 0x00A1A1A1A1A10000, 0x0041414141410000, 0x00FAFAFAFAFA0000, 0x0043434343430000, 0x0013131313130000, 0x00C4C4C4C4C40000, 0x002F2F2F2F2F0000, 0x00A8A8A8A8A80000, 0x00B6B6B6B6B60000, 0x003C3C3C3C3C0000, 0x002B2B2B2B2B0000, 0x00C1C1C1C1C10000, 0x00FFFFFFFFFF0000, 0x00C8C8C8C8C80000, 0x00A5A5A5A5A50000, 0x0020202020200000, 0x0089898989890000, 0x0000000000000000, 0x0090909090900000, 0x0047474747470000, 0x00EFEFEFEFEF0000, 0x00EAEAEAEAEA0000, 0x00B7B7B7B7B70000, 0x0015151515150000, 0x0006060606060000, 0x00CDCDCDCDCD0000, 0x00B5B5B5B5B50000, 0x0012121212120000, 0x007E7E7E7E7E0000, 0x00BBBBBBBBBB0000, 0x0029292929290000, 0x000F0F0F0F0F0000, 0x00B8B8B8B8B80000, 0x0007070707070000, 0x0004040404040000, 0x009B9B9B9B9B0000, 0x0094949494940000, 0x0021212121210000, 0x0066666666660000, 0x00E6E6E6E6E60000, 0x00CECECECECE0000, 0x00EDEDEDEDED0000, 0x00E7E7E7E7E70000, 0x003B3B3B3B3B0000, 0x00FEFEFEFEFE0000, 0x007F7F7F7F7F0000, 0x00C5C5C5C5C50000, 0x00A4A4A4A4A40000, 0x0037373737370000, 0x00B1B1B1B1B10000, 0x004C4C4C4C4C0000, 0x0091919191910000, 0x006E6E6E6E6E0000, 0x008D8D8D8D8D0000, 0x0076767676760000, 0x0003030303030000, 0x002D2D2D2D2D0000, 0x00DEDEDEDEDE0000, 0x0096969696960000, 0x0026262626260000, 0x007D7D7D7D7D0000, 0x00C6C6C6C6C60000, 0x005C5C5C5C5C0000, 0x00D3D3D3D3D30000, 0x00F2F2F2F2F20000, 0x004F4F4F4F4F0000, 0x0019191919190000, 0x003F3F3F3F3F0000, 0x00DCDCDCDCDC0000, 0x0079797979790000, 0x001D1D1D1D1D0000, 0x0052525252520000, 0x00EBEBEBEBEB0000, 0x00F3F3F3F3F30000, 0x006D6D6D6D6D0000, 0x005E5E5E5E5E0000, 0x00FBFBFBFBFB0000, 0x0069696969690000, 0x00B2B2B2B2B20000, 0x00F0F0F0F0F00000, 0x0031313131310000, 0x000C0C0C0C0C0000, 0x00D4D4D4D4D40000, 0x00CFCFCFCFCF0000, 0x008C8C8C8C8C0000, 0x00E2E2E2E2E20000, 0x0075757575750000, 0x00A9A9A9A9A90000, 0x004A4A4A4A4A0000, 0x0057575757570000, 0x0084848484840000, 0x0011111111110000, 0x0045454545450000, 0x001B1B1B1B1B0000, 0x00F5F5F5F5F50000, 0x00E4E4E4E4E40000, 0x000E0E0E0E0E0000, 0x0073737373730000, 0x00AAAAAAAAAA0000, 0x00F1F1F1F1F10000, 0x00DDDDDDDDDD0000, 0x0059595959590000, 0x0014141414140000, 0x006C6C6C6C6C0000, 0x0092929292920000, 0x0054545454540000, 0x00D0D0D0D0D00000, 0x0078787878780000, 0x0070707070700000, 0x00E3E3E3E3E30000, 0x0049494949490000, 0x0080808080800000, 0x0050505050500000, 0x00A7A7A7A7A70000, 0x00F6F6F6F6F60000, 0x0077777777770000, 0x0093939393930000, 0x0086868686860000, 0x0083838383830000, 0x002A2A2A2A2A0000, 0x00C7C7C7C7C70000, 0x005B5B5B5B5B0000, 0x00E9E9E9E9E90000, 0x00EEEEEEEEEE0000, 0x008F8F8F8F8F0000, 0x0001010101010000, 0x003D3D3D3D3D0000 }; alignas(64) const uint64_t Camellia_SBOX3[256] = { 0x3800383800383800, 0x4100414100414100, 0x1600161600161600, 0x7600767600767600, 0xD900D9D900D9D900, 0x9300939300939300, 0x6000606000606000, 0xF200F2F200F2F200, 0x7200727200727200, 0xC200C2C200C2C200, 0xAB00ABAB00ABAB00, 0x9A009A9A009A9A00, 0x7500757500757500, 0x0600060600060600, 0x5700575700575700, 0xA000A0A000A0A000, 0x9100919100919100, 0xF700F7F700F7F700, 0xB500B5B500B5B500, 0xC900C9C900C9C900, 0xA200A2A200A2A200, 0x8C008C8C008C8C00, 0xD200D2D200D2D200, 0x9000909000909000, 0xF600F6F600F6F600, 0x0700070700070700, 0xA700A7A700A7A700, 0x2700272700272700, 0x8E008E8E008E8E00, 0xB200B2B200B2B200, 0x4900494900494900, 0xDE00DEDE00DEDE00, 0x4300434300434300, 0x5C005C5C005C5C00, 0xD700D7D700D7D700, 0xC700C7C700C7C700, 0x3E003E3E003E3E00, 0xF500F5F500F5F500, 0x8F008F8F008F8F00, 0x6700676700676700, 0x1F001F1F001F1F00, 0x1800181800181800, 0x6E006E6E006E6E00, 0xAF00AFAF00AFAF00, 0x2F002F2F002F2F00, 0xE200E2E200E2E200, 0x8500858500858500, 0x0D000D0D000D0D00, 0x5300535300535300, 0xF000F0F000F0F000, 0x9C009C9C009C9C00, 0x6500656500656500, 0xEA00EAEA00EAEA00, 0xA300A3A300A3A300, 0xAE00AEAE00AEAE00, 0x9E009E9E009E9E00, 0xEC00ECEC00ECEC00, 0x8000808000808000, 0x2D002D2D002D2D00, 0x6B006B6B006B6B00, 0xA800A8A800A8A800, 0x2B002B2B002B2B00, 0x3600363600363600, 0xA600A6A600A6A600, 0xC500C5C500C5C500, 0x8600868600868600, 0x4D004D4D004D4D00, 0x3300333300333300, 0xFD00FDFD00FDFD00, 0x6600666600666600, 0x5800585800585800, 0x9600969600969600, 0x3A003A3A003A3A00, 0x0900090900090900, 0x9500959500959500, 0x1000101000101000, 0x7800787800787800, 0xD800D8D800D8D800, 0x4200424200424200, 0xCC00CCCC00CCCC00, 0xEF00EFEF00EFEF00, 0x2600262600262600, 0xE500E5E500E5E500, 0x6100616100616100, 0x1A001A1A001A1A00, 0x3F003F3F003F3F00, 0x3B003B3B003B3B00, 0x8200828200828200, 0xB600B6B600B6B600, 0xDB00DBDB00DBDB00, 0xD400D4D400D4D400, 0x9800989800989800, 0xE800E8E800E8E800, 0x8B008B8B008B8B00, 0x0200020200020200, 0xEB00EBEB00EBEB00, 0x0A000A0A000A0A00, 0x2C002C2C002C2C00, 0x1D001D1D001D1D00, 0xB000B0B000B0B000, 0x6F006F6F006F6F00, 0x8D008D8D008D8D00, 0x8800888800888800, 0x0E000E0E000E0E00, 0x1900191900191900, 0x8700878700878700, 0x4E004E4E004E4E00, 0x0B000B0B000B0B00, 0xA900A9A900A9A900, 0x0C000C0C000C0C00, 0x7900797900797900, 0x1100111100111100, 0x7F007F7F007F7F00, 0x2200222200222200, 0xE700E7E700E7E700, 0x5900595900595900, 0xE100E1E100E1E100, 0xDA00DADA00DADA00, 0x3D003D3D003D3D00, 0xC800C8C800C8C800, 0x1200121200121200, 0x0400040400040400, 0x7400747400747400, 0x5400545400545400, 0x3000303000303000, 0x7E007E7E007E7E00, 0xB400B4B400B4B400, 0x2800282800282800, 0x5500555500555500, 0x6800686800686800, 0x5000505000505000, 0xBE00BEBE00BEBE00, 0xD000D0D000D0D000, 0xC400C4C400C4C400, 0x3100313100313100, 0xCB00CBCB00CBCB00, 0x2A002A2A002A2A00, 0xAD00ADAD00ADAD00, 0x0F000F0F000F0F00, 0xCA00CACA00CACA00, 0x7000707000707000, 0xFF00FFFF00FFFF00, 0x3200323200323200, 0x6900696900696900, 0x0800080800080800, 0x6200626200626200, 0x0000000000000000, 0x2400242400242400, 0xD100D1D100D1D100, 0xFB00FBFB00FBFB00, 0xBA00BABA00BABA00, 0xED00EDED00EDED00, 0x4500454500454500, 0x8100818100818100, 0x7300737300737300, 0x6D006D6D006D6D00, 0x8400848400848400, 0x9F009F9F009F9F00, 0xEE00EEEE00EEEE00, 0x4A004A4A004A4A00, 0xC300C3C300C3C300, 0x2E002E2E002E2E00, 0xC100C1C100C1C100, 0x0100010100010100, 0xE600E6E600E6E600, 0x2500252500252500, 0x4800484800484800, 0x9900999900999900, 0xB900B9B900B9B900, 0xB300B3B300B3B300, 0x7B007B7B007B7B00, 0xF900F9F900F9F900, 0xCE00CECE00CECE00, 0xBF00BFBF00BFBF00, 0xDF00DFDF00DFDF00, 0x7100717100717100, 0x2900292900292900, 0xCD00CDCD00CDCD00, 0x6C006C6C006C6C00, 0x1300131300131300, 0x6400646400646400, 0x9B009B9B009B9B00, 0x6300636300636300, 0x9D009D9D009D9D00, 0xC000C0C000C0C000, 0x4B004B4B004B4B00, 0xB700B7B700B7B700, 0xA500A5A500A5A500, 0x8900898900898900, 0x5F005F5F005F5F00, 0xB100B1B100B1B100, 0x1700171700171700, 0xF400F4F400F4F400, 0xBC00BCBC00BCBC00, 0xD300D3D300D3D300, 0x4600464600464600, 0xCF00CFCF00CFCF00, 0x3700373700373700, 0x5E005E5E005E5E00, 0x4700474700474700, 0x9400949400949400, 0xFA00FAFA00FAFA00, 0xFC00FCFC00FCFC00, 0x5B005B5B005B5B00, 0x9700979700979700, 0xFE00FEFE00FEFE00, 0x5A005A5A005A5A00, 0xAC00ACAC00ACAC00, 0x3C003C3C003C3C00, 0x4C004C4C004C4C00, 0x0300030300030300, 0x3500353500353500, 0xF300F3F300F3F300, 0x2300232300232300, 0xB800B8B800B8B800, 0x5D005D5D005D5D00, 0x6A006A6A006A6A00, 0x9200929200929200, 0xD500D5D500D5D500, 0x2100212100212100, 0x4400444400444400, 0x5100515100515100, 0xC600C6C600C6C600, 0x7D007D7D007D7D00, 0x3900393900393900, 0x8300838300838300, 0xDC00DCDC00DCDC00, 0xAA00AAAA00AAAA00, 0x7C007C7C007C7C00, 0x7700777700777700, 0x5600565600565600, 0x0500050500050500, 0x1B001B1B001B1B00, 0xA400A4A400A4A400, 0x1500151500151500, 0x3400343400343400, 0x1E001E1E001E1E00, 0x1C001C1C001C1C00, 0xF800F8F800F8F800, 0x5200525200525200, 0x2000202000202000, 0x1400141400141400, 0xE900E9E900E9E900, 0xBD00BDBD00BDBD00, 0xDD00DDDD00DDDD00, 0xE400E4E400E4E400, 0xA100A1A100A1A100, 0xE000E0E000E0E000, 0x8A008A8A008A8A00, 0xF100F1F100F1F100, 0xD600D6D600D6D600, 0x7A007A7A007A7A00, 0xBB00BBBB00BBBB00, 0xE300E3E300E3E300, 0x4000404000404000, 0x4F004F4F004F4F00 }; alignas(64) const uint64_t Camellia_SBOX4[256] = { 0x7070007000007070, 0x2C2C002C00002C2C, 0xB3B300B30000B3B3, 0xC0C000C00000C0C0, 0xE4E400E40000E4E4, 0x5757005700005757, 0xEAEA00EA0000EAEA, 0xAEAE00AE0000AEAE, 0x2323002300002323, 0x6B6B006B00006B6B, 0x4545004500004545, 0xA5A500A50000A5A5, 0xEDED00ED0000EDED, 0x4F4F004F00004F4F, 0x1D1D001D00001D1D, 0x9292009200009292, 0x8686008600008686, 0xAFAF00AF0000AFAF, 0x7C7C007C00007C7C, 0x1F1F001F00001F1F, 0x3E3E003E00003E3E, 0xDCDC00DC0000DCDC, 0x5E5E005E00005E5E, 0x0B0B000B00000B0B, 0xA6A600A60000A6A6, 0x3939003900003939, 0xD5D500D50000D5D5, 0x5D5D005D00005D5D, 0xD9D900D90000D9D9, 0x5A5A005A00005A5A, 0x5151005100005151, 0x6C6C006C00006C6C, 0x8B8B008B00008B8B, 0x9A9A009A00009A9A, 0xFBFB00FB0000FBFB, 0xB0B000B00000B0B0, 0x7474007400007474, 0x2B2B002B00002B2B, 0xF0F000F00000F0F0, 0x8484008400008484, 0xDFDF00DF0000DFDF, 0xCBCB00CB0000CBCB, 0x3434003400003434, 0x7676007600007676, 0x6D6D006D00006D6D, 0xA9A900A90000A9A9, 0xD1D100D10000D1D1, 0x0404000400000404, 0x1414001400001414, 0x3A3A003A00003A3A, 0xDEDE00DE0000DEDE, 0x1111001100001111, 0x3232003200003232, 0x9C9C009C00009C9C, 0x5353005300005353, 0xF2F200F20000F2F2, 0xFEFE00FE0000FEFE, 0xCFCF00CF0000CFCF, 0xC3C300C30000C3C3, 0x7A7A007A00007A7A, 0x2424002400002424, 0xE8E800E80000E8E8, 0x6060006000006060, 0x6969006900006969, 0xAAAA00AA0000AAAA, 0xA0A000A00000A0A0, 0xA1A100A10000A1A1, 0x6262006200006262, 0x5454005400005454, 0x1E1E001E00001E1E, 0xE0E000E00000E0E0, 0x6464006400006464, 0x1010001000001010, 0x0000000000000000, 0xA3A300A30000A3A3, 0x7575007500007575, 0x8A8A008A00008A8A, 0xE6E600E60000E6E6, 0x0909000900000909, 0xDDDD00DD0000DDDD, 0x8787008700008787, 0x8383008300008383, 0xCDCD00CD0000CDCD, 0x9090009000009090, 0x7373007300007373, 0xF6F600F60000F6F6, 0x9D9D009D00009D9D, 0xBFBF00BF0000BFBF, 0x5252005200005252, 0xD8D800D80000D8D8, 0xC8C800C80000C8C8, 0xC6C600C60000C6C6, 0x8181008100008181, 0x6F6F006F00006F6F, 0x1313001300001313, 0x6363006300006363, 0xE9E900E90000E9E9, 0xA7A700A70000A7A7, 0x9F9F009F00009F9F, 0xBCBC00BC0000BCBC, 0x2929002900002929, 0xF9F900F90000F9F9, 0x2F2F002F00002F2F, 0xB4B400B40000B4B4, 0x7878007800007878, 0x0606000600000606, 0xE7E700E70000E7E7, 0x7171007100007171, 0xD4D400D40000D4D4, 0xABAB00AB0000ABAB, 0x8888008800008888, 0x8D8D008D00008D8D, 0x7272007200007272, 0xB9B900B90000B9B9, 0xF8F800F80000F8F8, 0xACAC00AC0000ACAC, 0x3636003600003636, 0x2A2A002A00002A2A, 0x3C3C003C00003C3C, 0xF1F100F10000F1F1, 0x4040004000004040, 0xD3D300D30000D3D3, 0xBBBB00BB0000BBBB, 0x4343004300004343, 0x1515001500001515, 0xADAD00AD0000ADAD, 0x7777007700007777, 0x8080008000008080, 0x8282008200008282, 0xECEC00EC0000ECEC, 0x2727002700002727, 0xE5E500E50000E5E5, 0x8585008500008585, 0x3535003500003535, 0x0C0C000C00000C0C, 0x4141004100004141, 0xEFEF00EF0000EFEF, 0x9393009300009393, 0x1919001900001919, 0x2121002100002121, 0x0E0E000E00000E0E, 0x4E4E004E00004E4E, 0x6565006500006565, 0xBDBD00BD0000BDBD, 0xB8B800B80000B8B8, 0x8F8F008F00008F8F, 0xEBEB00EB0000EBEB, 0xCECE00CE0000CECE, 0x3030003000003030, 0x5F5F005F00005F5F, 0xC5C500C50000C5C5, 0x1A1A001A00001A1A, 0xE1E100E10000E1E1, 0xCACA00CA0000CACA, 0x4747004700004747, 0x3D3D003D00003D3D, 0x0101000100000101, 0xD6D600D60000D6D6, 0x5656005600005656, 0x4D4D004D00004D4D, 0x0D0D000D00000D0D, 0x6666006600006666, 0xCCCC00CC0000CCCC, 0x2D2D002D00002D2D, 0x1212001200001212, 0x2020002000002020, 0xB1B100B10000B1B1, 0x9999009900009999, 0x4C4C004C00004C4C, 0xC2C200C20000C2C2, 0x7E7E007E00007E7E, 0x0505000500000505, 0xB7B700B70000B7B7, 0x3131003100003131, 0x1717001700001717, 0xD7D700D70000D7D7, 0x5858005800005858, 0x6161006100006161, 0x1B1B001B00001B1B, 0x1C1C001C00001C1C, 0x0F0F000F00000F0F, 0x1616001600001616, 0x1818001800001818, 0x2222002200002222, 0x4444004400004444, 0xB2B200B20000B2B2, 0xB5B500B50000B5B5, 0x9191009100009191, 0x0808000800000808, 0xA8A800A80000A8A8, 0xFCFC00FC0000FCFC, 0x5050005000005050, 0xD0D000D00000D0D0, 0x7D7D007D00007D7D, 0x8989008900008989, 0x9797009700009797, 0x5B5B005B00005B5B, 0x9595009500009595, 0xFFFF00FF0000FFFF, 0xD2D200D20000D2D2, 0xC4C400C40000C4C4, 0x4848004800004848, 0xF7F700F70000F7F7, 0xDBDB00DB0000DBDB, 0x0303000300000303, 0xDADA00DA0000DADA, 0x3F3F003F00003F3F, 0x9494009400009494, 0x5C5C005C00005C5C, 0x0202000200000202, 0x4A4A004A00004A4A, 0x3333003300003333, 0x6767006700006767, 0xF3F300F30000F3F3, 0x7F7F007F00007F7F, 0xE2E200E20000E2E2, 0x9B9B009B00009B9B, 0x2626002600002626, 0x3737003700003737, 0x3B3B003B00003B3B, 0x9696009600009696, 0x4B4B004B00004B4B, 0xBEBE00BE0000BEBE, 0x2E2E002E00002E2E, 0x7979007900007979, 0x8C8C008C00008C8C, 0x6E6E006E00006E6E, 0x8E8E008E00008E8E, 0xF5F500F50000F5F5, 0xB6B600B60000B6B6, 0xFDFD00FD0000FDFD, 0x5959005900005959, 0x9898009800009898, 0x6A6A006A00006A6A, 0x4646004600004646, 0xBABA00BA0000BABA, 0x2525002500002525, 0x4242004200004242, 0xA2A200A20000A2A2, 0xFAFA00FA0000FAFA, 0x0707000700000707, 0x5555005500005555, 0xEEEE00EE0000EEEE, 0x0A0A000A00000A0A, 0x4949004900004949, 0x6868006800006868, 0x3838003800003838, 0xA4A400A40000A4A4, 0x2828002800002828, 0x7B7B007B00007B7B, 0xC9C900C90000C9C9, 0xC1C100C10000C1C1, 0xE3E300E30000E3E3, 0xF4F400F40000F4F4, 0xC7C700C70000C7C7, 0x9E9E009E00009E9E }; alignas(64) const uint64_t Camellia_SBOX5[256] = { 0x00E0E0E000E0E0E0, 0x0005050500050505, 0x0058585800585858, 0x00D9D9D900D9D9D9, 0x0067676700676767, 0x004E4E4E004E4E4E, 0x0081818100818181, 0x00CBCBCB00CBCBCB, 0x00C9C9C900C9C9C9, 0x000B0B0B000B0B0B, 0x00AEAEAE00AEAEAE, 0x006A6A6A006A6A6A, 0x00D5D5D500D5D5D5, 0x0018181800181818, 0x005D5D5D005D5D5D, 0x0082828200828282, 0x0046464600464646, 0x00DFDFDF00DFDFDF, 0x00D6D6D600D6D6D6, 0x0027272700272727, 0x008A8A8A008A8A8A, 0x0032323200323232, 0x004B4B4B004B4B4B, 0x0042424200424242, 0x00DBDBDB00DBDBDB, 0x001C1C1C001C1C1C, 0x009E9E9E009E9E9E, 0x009C9C9C009C9C9C, 0x003A3A3A003A3A3A, 0x00CACACA00CACACA, 0x0025252500252525, 0x007B7B7B007B7B7B, 0x000D0D0D000D0D0D, 0x0071717100717171, 0x005F5F5F005F5F5F, 0x001F1F1F001F1F1F, 0x00F8F8F800F8F8F8, 0x00D7D7D700D7D7D7, 0x003E3E3E003E3E3E, 0x009D9D9D009D9D9D, 0x007C7C7C007C7C7C, 0x0060606000606060, 0x00B9B9B900B9B9B9, 0x00BEBEBE00BEBEBE, 0x00BCBCBC00BCBCBC, 0x008B8B8B008B8B8B, 0x0016161600161616, 0x0034343400343434, 0x004D4D4D004D4D4D, 0x00C3C3C300C3C3C3, 0x0072727200727272, 0x0095959500959595, 0x00ABABAB00ABABAB, 0x008E8E8E008E8E8E, 0x00BABABA00BABABA, 0x007A7A7A007A7A7A, 0x00B3B3B300B3B3B3, 0x0002020200020202, 0x00B4B4B400B4B4B4, 0x00ADADAD00ADADAD, 0x00A2A2A200A2A2A2, 0x00ACACAC00ACACAC, 0x00D8D8D800D8D8D8, 0x009A9A9A009A9A9A, 0x0017171700171717, 0x001A1A1A001A1A1A, 0x0035353500353535, 0x00CCCCCC00CCCCCC, 0x00F7F7F700F7F7F7, 0x0099999900999999, 0x0061616100616161, 0x005A5A5A005A5A5A, 0x00E8E8E800E8E8E8, 0x0024242400242424, 0x0056565600565656, 0x0040404000404040, 0x00E1E1E100E1E1E1, 0x0063636300636363, 0x0009090900090909, 0x0033333300333333, 0x00BFBFBF00BFBFBF, 0x0098989800989898, 0x0097979700979797, 0x0085858500858585, 0x0068686800686868, 0x00FCFCFC00FCFCFC, 0x00ECECEC00ECECEC, 0x000A0A0A000A0A0A, 0x00DADADA00DADADA, 0x006F6F6F006F6F6F, 0x0053535300535353, 0x0062626200626262, 0x00A3A3A300A3A3A3, 0x002E2E2E002E2E2E, 0x0008080800080808, 0x00AFAFAF00AFAFAF, 0x0028282800282828, 0x00B0B0B000B0B0B0, 0x0074747400747474, 0x00C2C2C200C2C2C2, 0x00BDBDBD00BDBDBD, 0x0036363600363636, 0x0022222200222222, 0x0038383800383838, 0x0064646400646464, 0x001E1E1E001E1E1E, 0x0039393900393939, 0x002C2C2C002C2C2C, 0x00A6A6A600A6A6A6, 0x0030303000303030, 0x00E5E5E500E5E5E5, 0x0044444400444444, 0x00FDFDFD00FDFDFD, 0x0088888800888888, 0x009F9F9F009F9F9F, 0x0065656500656565, 0x0087878700878787, 0x006B6B6B006B6B6B, 0x00F4F4F400F4F4F4, 0x0023232300232323, 0x0048484800484848, 0x0010101000101010, 0x00D1D1D100D1D1D1, 0x0051515100515151, 0x00C0C0C000C0C0C0, 0x00F9F9F900F9F9F9, 0x00D2D2D200D2D2D2, 0x00A0A0A000A0A0A0, 0x0055555500555555, 0x00A1A1A100A1A1A1, 0x0041414100414141, 0x00FAFAFA00FAFAFA, 0x0043434300434343, 0x0013131300131313, 0x00C4C4C400C4C4C4, 0x002F2F2F002F2F2F, 0x00A8A8A800A8A8A8, 0x00B6B6B600B6B6B6, 0x003C3C3C003C3C3C, 0x002B2B2B002B2B2B, 0x00C1C1C100C1C1C1, 0x00FFFFFF00FFFFFF, 0x00C8C8C800C8C8C8, 0x00A5A5A500A5A5A5, 0x0020202000202020, 0x0089898900898989, 0x0000000000000000, 0x0090909000909090, 0x0047474700474747, 0x00EFEFEF00EFEFEF, 0x00EAEAEA00EAEAEA, 0x00B7B7B700B7B7B7, 0x0015151500151515, 0x0006060600060606, 0x00CDCDCD00CDCDCD, 0x00B5B5B500B5B5B5, 0x0012121200121212, 0x007E7E7E007E7E7E, 0x00BBBBBB00BBBBBB, 0x0029292900292929, 0x000F0F0F000F0F0F, 0x00B8B8B800B8B8B8, 0x0007070700070707, 0x0004040400040404, 0x009B9B9B009B9B9B, 0x0094949400949494, 0x0021212100212121, 0x0066666600666666, 0x00E6E6E600E6E6E6, 0x00CECECE00CECECE, 0x00EDEDED00EDEDED, 0x00E7E7E700E7E7E7, 0x003B3B3B003B3B3B, 0x00FEFEFE00FEFEFE, 0x007F7F7F007F7F7F, 0x00C5C5C500C5C5C5, 0x00A4A4A400A4A4A4, 0x0037373700373737, 0x00B1B1B100B1B1B1, 0x004C4C4C004C4C4C, 0x0091919100919191, 0x006E6E6E006E6E6E, 0x008D8D8D008D8D8D, 0x0076767600767676, 0x0003030300030303, 0x002D2D2D002D2D2D, 0x00DEDEDE00DEDEDE, 0x0096969600969696, 0x0026262600262626, 0x007D7D7D007D7D7D, 0x00C6C6C600C6C6C6, 0x005C5C5C005C5C5C, 0x00D3D3D300D3D3D3, 0x00F2F2F200F2F2F2, 0x004F4F4F004F4F4F, 0x0019191900191919, 0x003F3F3F003F3F3F, 0x00DCDCDC00DCDCDC, 0x0079797900797979, 0x001D1D1D001D1D1D, 0x0052525200525252, 0x00EBEBEB00EBEBEB, 0x00F3F3F300F3F3F3, 0x006D6D6D006D6D6D, 0x005E5E5E005E5E5E, 0x00FBFBFB00FBFBFB, 0x0069696900696969, 0x00B2B2B200B2B2B2, 0x00F0F0F000F0F0F0, 0x0031313100313131, 0x000C0C0C000C0C0C, 0x00D4D4D400D4D4D4, 0x00CFCFCF00CFCFCF, 0x008C8C8C008C8C8C, 0x00E2E2E200E2E2E2, 0x0075757500757575, 0x00A9A9A900A9A9A9, 0x004A4A4A004A4A4A, 0x0057575700575757, 0x0084848400848484, 0x0011111100111111, 0x0045454500454545, 0x001B1B1B001B1B1B, 0x00F5F5F500F5F5F5, 0x00E4E4E400E4E4E4, 0x000E0E0E000E0E0E, 0x0073737300737373, 0x00AAAAAA00AAAAAA, 0x00F1F1F100F1F1F1, 0x00DDDDDD00DDDDDD, 0x0059595900595959, 0x0014141400141414, 0x006C6C6C006C6C6C, 0x0092929200929292, 0x0054545400545454, 0x00D0D0D000D0D0D0, 0x0078787800787878, 0x0070707000707070, 0x00E3E3E300E3E3E3, 0x0049494900494949, 0x0080808000808080, 0x0050505000505050, 0x00A7A7A700A7A7A7, 0x00F6F6F600F6F6F6, 0x0077777700777777, 0x0093939300939393, 0x0086868600868686, 0x0083838300838383, 0x002A2A2A002A2A2A, 0x00C7C7C700C7C7C7, 0x005B5B5B005B5B5B, 0x00E9E9E900E9E9E9, 0x00EEEEEE00EEEEEE, 0x008F8F8F008F8F8F, 0x0001010100010101, 0x003D3D3D003D3D3D }; alignas(64) const uint64_t Camellia_SBOX6[256] = { 0x3800383838003838, 0x4100414141004141, 0x1600161616001616, 0x7600767676007676, 0xD900D9D9D900D9D9, 0x9300939393009393, 0x6000606060006060, 0xF200F2F2F200F2F2, 0x7200727272007272, 0xC200C2C2C200C2C2, 0xAB00ABABAB00ABAB, 0x9A009A9A9A009A9A, 0x7500757575007575, 0x0600060606000606, 0x5700575757005757, 0xA000A0A0A000A0A0, 0x9100919191009191, 0xF700F7F7F700F7F7, 0xB500B5B5B500B5B5, 0xC900C9C9C900C9C9, 0xA200A2A2A200A2A2, 0x8C008C8C8C008C8C, 0xD200D2D2D200D2D2, 0x9000909090009090, 0xF600F6F6F600F6F6, 0x0700070707000707, 0xA700A7A7A700A7A7, 0x2700272727002727, 0x8E008E8E8E008E8E, 0xB200B2B2B200B2B2, 0x4900494949004949, 0xDE00DEDEDE00DEDE, 0x4300434343004343, 0x5C005C5C5C005C5C, 0xD700D7D7D700D7D7, 0xC700C7C7C700C7C7, 0x3E003E3E3E003E3E, 0xF500F5F5F500F5F5, 0x8F008F8F8F008F8F, 0x6700676767006767, 0x1F001F1F1F001F1F, 0x1800181818001818, 0x6E006E6E6E006E6E, 0xAF00AFAFAF00AFAF, 0x2F002F2F2F002F2F, 0xE200E2E2E200E2E2, 0x8500858585008585, 0x0D000D0D0D000D0D, 0x5300535353005353, 0xF000F0F0F000F0F0, 0x9C009C9C9C009C9C, 0x6500656565006565, 0xEA00EAEAEA00EAEA, 0xA300A3A3A300A3A3, 0xAE00AEAEAE00AEAE, 0x9E009E9E9E009E9E, 0xEC00ECECEC00ECEC, 0x8000808080008080, 0x2D002D2D2D002D2D, 0x6B006B6B6B006B6B, 0xA800A8A8A800A8A8, 0x2B002B2B2B002B2B, 0x3600363636003636, 0xA600A6A6A600A6A6, 0xC500C5C5C500C5C5, 0x8600868686008686, 0x4D004D4D4D004D4D, 0x3300333333003333, 0xFD00FDFDFD00FDFD, 0x6600666666006666, 0x5800585858005858, 0x9600969696009696, 0x3A003A3A3A003A3A, 0x0900090909000909, 0x9500959595009595, 0x1000101010001010, 0x7800787878007878, 0xD800D8D8D800D8D8, 0x4200424242004242, 0xCC00CCCCCC00CCCC, 0xEF00EFEFEF00EFEF, 0x2600262626002626, 0xE500E5E5E500E5E5, 0x6100616161006161, 0x1A001A1A1A001A1A, 0x3F003F3F3F003F3F, 0x3B003B3B3B003B3B, 0x8200828282008282, 0xB600B6B6B600B6B6, 0xDB00DBDBDB00DBDB, 0xD400D4D4D400D4D4, 0x9800989898009898, 0xE800E8E8E800E8E8, 0x8B008B8B8B008B8B, 0x0200020202000202, 0xEB00EBEBEB00EBEB, 0x0A000A0A0A000A0A, 0x2C002C2C2C002C2C, 0x1D001D1D1D001D1D, 0xB000B0B0B000B0B0, 0x6F006F6F6F006F6F, 0x8D008D8D8D008D8D, 0x8800888888008888, 0x0E000E0E0E000E0E, 0x1900191919001919, 0x8700878787008787, 0x4E004E4E4E004E4E, 0x0B000B0B0B000B0B, 0xA900A9A9A900A9A9, 0x0C000C0C0C000C0C, 0x7900797979007979, 0x1100111111001111, 0x7F007F7F7F007F7F, 0x2200222222002222, 0xE700E7E7E700E7E7, 0x5900595959005959, 0xE100E1E1E100E1E1, 0xDA00DADADA00DADA, 0x3D003D3D3D003D3D, 0xC800C8C8C800C8C8, 0x1200121212001212, 0x0400040404000404, 0x7400747474007474, 0x5400545454005454, 0x3000303030003030, 0x7E007E7E7E007E7E, 0xB400B4B4B400B4B4, 0x2800282828002828, 0x5500555555005555, 0x6800686868006868, 0x5000505050005050, 0xBE00BEBEBE00BEBE, 0xD000D0D0D000D0D0, 0xC400C4C4C400C4C4, 0x3100313131003131, 0xCB00CBCBCB00CBCB, 0x2A002A2A2A002A2A, 0xAD00ADADAD00ADAD, 0x0F000F0F0F000F0F, 0xCA00CACACA00CACA, 0x7000707070007070, 0xFF00FFFFFF00FFFF, 0x3200323232003232, 0x6900696969006969, 0x0800080808000808, 0x6200626262006262, 0x0000000000000000, 0x2400242424002424, 0xD100D1D1D100D1D1, 0xFB00FBFBFB00FBFB, 0xBA00BABABA00BABA, 0xED00EDEDED00EDED, 0x4500454545004545, 0x8100818181008181, 0x7300737373007373, 0x6D006D6D6D006D6D, 0x8400848484008484, 0x9F009F9F9F009F9F, 0xEE00EEEEEE00EEEE, 0x4A004A4A4A004A4A, 0xC300C3C3C300C3C3, 0x2E002E2E2E002E2E, 0xC100C1C1C100C1C1, 0x0100010101000101, 0xE600E6E6E600E6E6, 0x2500252525002525, 0x4800484848004848, 0x9900999999009999, 0xB900B9B9B900B9B9, 0xB300B3B3B300B3B3, 0x7B007B7B7B007B7B, 0xF900F9F9F900F9F9, 0xCE00CECECE00CECE, 0xBF00BFBFBF00BFBF, 0xDF00DFDFDF00DFDF, 0x7100717171007171, 0x2900292929002929, 0xCD00CDCDCD00CDCD, 0x6C006C6C6C006C6C, 0x1300131313001313, 0x6400646464006464, 0x9B009B9B9B009B9B, 0x6300636363006363, 0x9D009D9D9D009D9D, 0xC000C0C0C000C0C0, 0x4B004B4B4B004B4B, 0xB700B7B7B700B7B7, 0xA500A5A5A500A5A5, 0x8900898989008989, 0x5F005F5F5F005F5F, 0xB100B1B1B100B1B1, 0x1700171717001717, 0xF400F4F4F400F4F4, 0xBC00BCBCBC00BCBC, 0xD300D3D3D300D3D3, 0x4600464646004646, 0xCF00CFCFCF00CFCF, 0x3700373737003737, 0x5E005E5E5E005E5E, 0x4700474747004747, 0x9400949494009494, 0xFA00FAFAFA00FAFA, 0xFC00FCFCFC00FCFC, 0x5B005B5B5B005B5B, 0x9700979797009797, 0xFE00FEFEFE00FEFE, 0x5A005A5A5A005A5A, 0xAC00ACACAC00ACAC, 0x3C003C3C3C003C3C, 0x4C004C4C4C004C4C, 0x0300030303000303, 0x3500353535003535, 0xF300F3F3F300F3F3, 0x2300232323002323, 0xB800B8B8B800B8B8, 0x5D005D5D5D005D5D, 0x6A006A6A6A006A6A, 0x9200929292009292, 0xD500D5D5D500D5D5, 0x2100212121002121, 0x4400444444004444, 0x5100515151005151, 0xC600C6C6C600C6C6, 0x7D007D7D7D007D7D, 0x3900393939003939, 0x8300838383008383, 0xDC00DCDCDC00DCDC, 0xAA00AAAAAA00AAAA, 0x7C007C7C7C007C7C, 0x7700777777007777, 0x5600565656005656, 0x0500050505000505, 0x1B001B1B1B001B1B, 0xA400A4A4A400A4A4, 0x1500151515001515, 0x3400343434003434, 0x1E001E1E1E001E1E, 0x1C001C1C1C001C1C, 0xF800F8F8F800F8F8, 0x5200525252005252, 0x2000202020002020, 0x1400141414001414, 0xE900E9E9E900E9E9, 0xBD00BDBDBD00BDBD, 0xDD00DDDDDD00DDDD, 0xE400E4E4E400E4E4, 0xA100A1A1A100A1A1, 0xE000E0E0E000E0E0, 0x8A008A8A8A008A8A, 0xF100F1F1F100F1F1, 0xD600D6D6D600D6D6, 0x7A007A7A7A007A7A, 0xBB00BBBBBB00BBBB, 0xE300E3E3E300E3E3, 0x4000404040004040, 0x4F004F4F4F004F4F }; alignas(64) const uint64_t Camellia_SBOX7[256] = { 0x7070007070700070, 0x2C2C002C2C2C002C, 0xB3B300B3B3B300B3, 0xC0C000C0C0C000C0, 0xE4E400E4E4E400E4, 0x5757005757570057, 0xEAEA00EAEAEA00EA, 0xAEAE00AEAEAE00AE, 0x2323002323230023, 0x6B6B006B6B6B006B, 0x4545004545450045, 0xA5A500A5A5A500A5, 0xEDED00EDEDED00ED, 0x4F4F004F4F4F004F, 0x1D1D001D1D1D001D, 0x9292009292920092, 0x8686008686860086, 0xAFAF00AFAFAF00AF, 0x7C7C007C7C7C007C, 0x1F1F001F1F1F001F, 0x3E3E003E3E3E003E, 0xDCDC00DCDCDC00DC, 0x5E5E005E5E5E005E, 0x0B0B000B0B0B000B, 0xA6A600A6A6A600A6, 0x3939003939390039, 0xD5D500D5D5D500D5, 0x5D5D005D5D5D005D, 0xD9D900D9D9D900D9, 0x5A5A005A5A5A005A, 0x5151005151510051, 0x6C6C006C6C6C006C, 0x8B8B008B8B8B008B, 0x9A9A009A9A9A009A, 0xFBFB00FBFBFB00FB, 0xB0B000B0B0B000B0, 0x7474007474740074, 0x2B2B002B2B2B002B, 0xF0F000F0F0F000F0, 0x8484008484840084, 0xDFDF00DFDFDF00DF, 0xCBCB00CBCBCB00CB, 0x3434003434340034, 0x7676007676760076, 0x6D6D006D6D6D006D, 0xA9A900A9A9A900A9, 0xD1D100D1D1D100D1, 0x0404000404040004, 0x1414001414140014, 0x3A3A003A3A3A003A, 0xDEDE00DEDEDE00DE, 0x1111001111110011, 0x3232003232320032, 0x9C9C009C9C9C009C, 0x5353005353530053, 0xF2F200F2F2F200F2, 0xFEFE00FEFEFE00FE, 0xCFCF00CFCFCF00CF, 0xC3C300C3C3C300C3, 0x7A7A007A7A7A007A, 0x2424002424240024, 0xE8E800E8E8E800E8, 0x6060006060600060, 0x6969006969690069, 0xAAAA00AAAAAA00AA, 0xA0A000A0A0A000A0, 0xA1A100A1A1A100A1, 0x6262006262620062, 0x5454005454540054, 0x1E1E001E1E1E001E, 0xE0E000E0E0E000E0, 0x6464006464640064, 0x1010001010100010, 0x0000000000000000, 0xA3A300A3A3A300A3, 0x7575007575750075, 0x8A8A008A8A8A008A, 0xE6E600E6E6E600E6, 0x0909000909090009, 0xDDDD00DDDDDD00DD, 0x8787008787870087, 0x8383008383830083, 0xCDCD00CDCDCD00CD, 0x9090009090900090, 0x7373007373730073, 0xF6F600F6F6F600F6, 0x9D9D009D9D9D009D, 0xBFBF00BFBFBF00BF, 0x5252005252520052, 0xD8D800D8D8D800D8, 0xC8C800C8C8C800C8, 0xC6C600C6C6C600C6, 0x8181008181810081, 0x6F6F006F6F6F006F, 0x1313001313130013, 0x6363006363630063, 0xE9E900E9E9E900E9, 0xA7A700A7A7A700A7, 0x9F9F009F9F9F009F, 0xBCBC00BCBCBC00BC, 0x2929002929290029, 0xF9F900F9F9F900F9, 0x2F2F002F2F2F002F, 0xB4B400B4B4B400B4, 0x7878007878780078, 0x0606000606060006, 0xE7E700E7E7E700E7, 0x7171007171710071, 0xD4D400D4D4D400D4, 0xABAB00ABABAB00AB, 0x8888008888880088, 0x8D8D008D8D8D008D, 0x7272007272720072, 0xB9B900B9B9B900B9, 0xF8F800F8F8F800F8, 0xACAC00ACACAC00AC, 0x3636003636360036, 0x2A2A002A2A2A002A, 0x3C3C003C3C3C003C, 0xF1F100F1F1F100F1, 0x4040004040400040, 0xD3D300D3D3D300D3, 0xBBBB00BBBBBB00BB, 0x4343004343430043, 0x1515001515150015, 0xADAD00ADADAD00AD, 0x7777007777770077, 0x8080008080800080, 0x8282008282820082, 0xECEC00ECECEC00EC, 0x2727002727270027, 0xE5E500E5E5E500E5, 0x8585008585850085, 0x3535003535350035, 0x0C0C000C0C0C000C, 0x4141004141410041, 0xEFEF00EFEFEF00EF, 0x9393009393930093, 0x1919001919190019, 0x2121002121210021, 0x0E0E000E0E0E000E, 0x4E4E004E4E4E004E, 0x6565006565650065, 0xBDBD00BDBDBD00BD, 0xB8B800B8B8B800B8, 0x8F8F008F8F8F008F, 0xEBEB00EBEBEB00EB, 0xCECE00CECECE00CE, 0x3030003030300030, 0x5F5F005F5F5F005F, 0xC5C500C5C5C500C5, 0x1A1A001A1A1A001A, 0xE1E100E1E1E100E1, 0xCACA00CACACA00CA, 0x4747004747470047, 0x3D3D003D3D3D003D, 0x0101000101010001, 0xD6D600D6D6D600D6, 0x5656005656560056, 0x4D4D004D4D4D004D, 0x0D0D000D0D0D000D, 0x6666006666660066, 0xCCCC00CCCCCC00CC, 0x2D2D002D2D2D002D, 0x1212001212120012, 0x2020002020200020, 0xB1B100B1B1B100B1, 0x9999009999990099, 0x4C4C004C4C4C004C, 0xC2C200C2C2C200C2, 0x7E7E007E7E7E007E, 0x0505000505050005, 0xB7B700B7B7B700B7, 0x3131003131310031, 0x1717001717170017, 0xD7D700D7D7D700D7, 0x5858005858580058, 0x6161006161610061, 0x1B1B001B1B1B001B, 0x1C1C001C1C1C001C, 0x0F0F000F0F0F000F, 0x1616001616160016, 0x1818001818180018, 0x2222002222220022, 0x4444004444440044, 0xB2B200B2B2B200B2, 0xB5B500B5B5B500B5, 0x9191009191910091, 0x0808000808080008, 0xA8A800A8A8A800A8, 0xFCFC00FCFCFC00FC, 0x5050005050500050, 0xD0D000D0D0D000D0, 0x7D7D007D7D7D007D, 0x8989008989890089, 0x9797009797970097, 0x5B5B005B5B5B005B, 0x9595009595950095, 0xFFFF00FFFFFF00FF, 0xD2D200D2D2D200D2, 0xC4C400C4C4C400C4, 0x4848004848480048, 0xF7F700F7F7F700F7, 0xDBDB00DBDBDB00DB, 0x0303000303030003, 0xDADA00DADADA00DA, 0x3F3F003F3F3F003F, 0x9494009494940094, 0x5C5C005C5C5C005C, 0x0202000202020002, 0x4A4A004A4A4A004A, 0x3333003333330033, 0x6767006767670067, 0xF3F300F3F3F300F3, 0x7F7F007F7F7F007F, 0xE2E200E2E2E200E2, 0x9B9B009B9B9B009B, 0x2626002626260026, 0x3737003737370037, 0x3B3B003B3B3B003B, 0x9696009696960096, 0x4B4B004B4B4B004B, 0xBEBE00BEBEBE00BE, 0x2E2E002E2E2E002E, 0x7979007979790079, 0x8C8C008C8C8C008C, 0x6E6E006E6E6E006E, 0x8E8E008E8E8E008E, 0xF5F500F5F5F500F5, 0xB6B600B6B6B600B6, 0xFDFD00FDFDFD00FD, 0x5959005959590059, 0x9898009898980098, 0x6A6A006A6A6A006A, 0x4646004646460046, 0xBABA00BABABA00BA, 0x2525002525250025, 0x4242004242420042, 0xA2A200A2A2A200A2, 0xFAFA00FAFAFA00FA, 0x0707000707070007, 0x5555005555550055, 0xEEEE00EEEEEE00EE, 0x0A0A000A0A0A000A, 0x4949004949490049, 0x6868006868680068, 0x3838003838380038, 0xA4A400A4A4A400A4, 0x2828002828280028, 0x7B7B007B7B7B007B, 0xC9C900C9C9C900C9, 0xC1C100C1C1C100C1, 0xE3E300E3E3E300E3, 0xF4F400F4F4F400F4, 0xC7C700C7C7C700C7, 0x9E9E009E9E9E009E }; alignas(64) const uint64_t Camellia_SBOX8[256] = { 0x7070700070707000, 0x8282820082828200, 0x2C2C2C002C2C2C00, 0xECECEC00ECECEC00, 0xB3B3B300B3B3B300, 0x2727270027272700, 0xC0C0C000C0C0C000, 0xE5E5E500E5E5E500, 0xE4E4E400E4E4E400, 0x8585850085858500, 0x5757570057575700, 0x3535350035353500, 0xEAEAEA00EAEAEA00, 0x0C0C0C000C0C0C00, 0xAEAEAE00AEAEAE00, 0x4141410041414100, 0x2323230023232300, 0xEFEFEF00EFEFEF00, 0x6B6B6B006B6B6B00, 0x9393930093939300, 0x4545450045454500, 0x1919190019191900, 0xA5A5A500A5A5A500, 0x2121210021212100, 0xEDEDED00EDEDED00, 0x0E0E0E000E0E0E00, 0x4F4F4F004F4F4F00, 0x4E4E4E004E4E4E00, 0x1D1D1D001D1D1D00, 0x6565650065656500, 0x9292920092929200, 0xBDBDBD00BDBDBD00, 0x8686860086868600, 0xB8B8B800B8B8B800, 0xAFAFAF00AFAFAF00, 0x8F8F8F008F8F8F00, 0x7C7C7C007C7C7C00, 0xEBEBEB00EBEBEB00, 0x1F1F1F001F1F1F00, 0xCECECE00CECECE00, 0x3E3E3E003E3E3E00, 0x3030300030303000, 0xDCDCDC00DCDCDC00, 0x5F5F5F005F5F5F00, 0x5E5E5E005E5E5E00, 0xC5C5C500C5C5C500, 0x0B0B0B000B0B0B00, 0x1A1A1A001A1A1A00, 0xA6A6A600A6A6A600, 0xE1E1E100E1E1E100, 0x3939390039393900, 0xCACACA00CACACA00, 0xD5D5D500D5D5D500, 0x4747470047474700, 0x5D5D5D005D5D5D00, 0x3D3D3D003D3D3D00, 0xD9D9D900D9D9D900, 0x0101010001010100, 0x5A5A5A005A5A5A00, 0xD6D6D600D6D6D600, 0x5151510051515100, 0x5656560056565600, 0x6C6C6C006C6C6C00, 0x4D4D4D004D4D4D00, 0x8B8B8B008B8B8B00, 0x0D0D0D000D0D0D00, 0x9A9A9A009A9A9A00, 0x6666660066666600, 0xFBFBFB00FBFBFB00, 0xCCCCCC00CCCCCC00, 0xB0B0B000B0B0B000, 0x2D2D2D002D2D2D00, 0x7474740074747400, 0x1212120012121200, 0x2B2B2B002B2B2B00, 0x2020200020202000, 0xF0F0F000F0F0F000, 0xB1B1B100B1B1B100, 0x8484840084848400, 0x9999990099999900, 0xDFDFDF00DFDFDF00, 0x4C4C4C004C4C4C00, 0xCBCBCB00CBCBCB00, 0xC2C2C200C2C2C200, 0x3434340034343400, 0x7E7E7E007E7E7E00, 0x7676760076767600, 0x0505050005050500, 0x6D6D6D006D6D6D00, 0xB7B7B700B7B7B700, 0xA9A9A900A9A9A900, 0x3131310031313100, 0xD1D1D100D1D1D100, 0x1717170017171700, 0x0404040004040400, 0xD7D7D700D7D7D700, 0x1414140014141400, 0x5858580058585800, 0x3A3A3A003A3A3A00, 0x6161610061616100, 0xDEDEDE00DEDEDE00, 0x1B1B1B001B1B1B00, 0x1111110011111100, 0x1C1C1C001C1C1C00, 0x3232320032323200, 0x0F0F0F000F0F0F00, 0x9C9C9C009C9C9C00, 0x1616160016161600, 0x5353530053535300, 0x1818180018181800, 0xF2F2F200F2F2F200, 0x2222220022222200, 0xFEFEFE00FEFEFE00, 0x4444440044444400, 0xCFCFCF00CFCFCF00, 0xB2B2B200B2B2B200, 0xC3C3C300C3C3C300, 0xB5B5B500B5B5B500, 0x7A7A7A007A7A7A00, 0x9191910091919100, 0x2424240024242400, 0x0808080008080800, 0xE8E8E800E8E8E800, 0xA8A8A800A8A8A800, 0x6060600060606000, 0xFCFCFC00FCFCFC00, 0x6969690069696900, 0x5050500050505000, 0xAAAAAA00AAAAAA00, 0xD0D0D000D0D0D000, 0xA0A0A000A0A0A000, 0x7D7D7D007D7D7D00, 0xA1A1A100A1A1A100, 0x8989890089898900, 0x6262620062626200, 0x9797970097979700, 0x5454540054545400, 0x5B5B5B005B5B5B00, 0x1E1E1E001E1E1E00, 0x9595950095959500, 0xE0E0E000E0E0E000, 0xFFFFFF00FFFFFF00, 0x6464640064646400, 0xD2D2D200D2D2D200, 0x1010100010101000, 0xC4C4C400C4C4C400, 0x0000000000000000, 0x4848480048484800, 0xA3A3A300A3A3A300, 0xF7F7F700F7F7F700, 0x7575750075757500, 0xDBDBDB00DBDBDB00, 0x8A8A8A008A8A8A00, 0x0303030003030300, 0xE6E6E600E6E6E600, 0xDADADA00DADADA00, 0x0909090009090900, 0x3F3F3F003F3F3F00, 0xDDDDDD00DDDDDD00, 0x9494940094949400, 0x8787870087878700, 0x5C5C5C005C5C5C00, 0x8383830083838300, 0x0202020002020200, 0xCDCDCD00CDCDCD00, 0x4A4A4A004A4A4A00, 0x9090900090909000, 0x3333330033333300, 0x7373730073737300, 0x6767670067676700, 0xF6F6F600F6F6F600, 0xF3F3F300F3F3F300, 0x9D9D9D009D9D9D00, 0x7F7F7F007F7F7F00, 0xBFBFBF00BFBFBF00, 0xE2E2E200E2E2E200, 0x5252520052525200, 0x9B9B9B009B9B9B00, 0xD8D8D800D8D8D800, 0x2626260026262600, 0xC8C8C800C8C8C800, 0x3737370037373700, 0xC6C6C600C6C6C600, 0x3B3B3B003B3B3B00, 0x8181810081818100, 0x9696960096969600, 0x6F6F6F006F6F6F00, 0x4B4B4B004B4B4B00, 0x1313130013131300, 0xBEBEBE00BEBEBE00, 0x6363630063636300, 0x2E2E2E002E2E2E00, 0xE9E9E900E9E9E900, 0x7979790079797900, 0xA7A7A700A7A7A700, 0x8C8C8C008C8C8C00, 0x9F9F9F009F9F9F00, 0x6E6E6E006E6E6E00, 0xBCBCBC00BCBCBC00, 0x8E8E8E008E8E8E00, 0x2929290029292900, 0xF5F5F500F5F5F500, 0xF9F9F900F9F9F900, 0xB6B6B600B6B6B600, 0x2F2F2F002F2F2F00, 0xFDFDFD00FDFDFD00, 0xB4B4B400B4B4B400, 0x5959590059595900, 0x7878780078787800, 0x9898980098989800, 0x0606060006060600, 0x6A6A6A006A6A6A00, 0xE7E7E700E7E7E700, 0x4646460046464600, 0x7171710071717100, 0xBABABA00BABABA00, 0xD4D4D400D4D4D400, 0x2525250025252500, 0xABABAB00ABABAB00, 0x4242420042424200, 0x8888880088888800, 0xA2A2A200A2A2A200, 0x8D8D8D008D8D8D00, 0xFAFAFA00FAFAFA00, 0x7272720072727200, 0x0707070007070700, 0xB9B9B900B9B9B900, 0x5555550055555500, 0xF8F8F800F8F8F800, 0xEEEEEE00EEEEEE00, 0xACACAC00ACACAC00, 0x0A0A0A000A0A0A00, 0x3636360036363600, 0x4949490049494900, 0x2A2A2A002A2A2A00, 0x6868680068686800, 0x3C3C3C003C3C3C00, 0x3838380038383800, 0xF1F1F100F1F1F100, 0xA4A4A400A4A4A400, 0x4040400040404000, 0x2828280028282800, 0xD3D3D300D3D3D300, 0x7B7B7B007B7B7B00, 0xBBBBBB00BBBBBB00, 0xC9C9C900C9C9C900, 0x4343430043434300, 0xC1C1C100C1C1C100, 0x1515150015151500, 0xE3E3E300E3E3E300, 0xADADAD00ADADAD00, 0xF4F4F400F4F4F400, 0x7777770077777700, 0xC7C7C700C7C7C700, 0x8080800080808000, 0x9E9E9E009E9E9E00 }; namespace Camellia_F { /* * We use the slow byte-wise version of F in the first and last rounds * to help protect against side channels analyzing cache hits on the * larger sbox tables. */ uint64_t F_SLOW(uint64_t v, uint64_t K) { alignas(64) static const uint8_t SBOX[256] = { 0x70, 0x82, 0x2C, 0xEC, 0xB3, 0x27, 0xC0, 0xE5, 0xE4, 0x85, 0x57, 0x35, 0xEA, 0x0C, 0xAE, 0x41, 0x23, 0xEF, 0x6B, 0x93, 0x45, 0x19, 0xA5, 0x21, 0xED, 0x0E, 0x4F, 0x4E, 0x1D, 0x65, 0x92, 0xBD, 0x86, 0xB8, 0xAF, 0x8F, 0x7C, 0xEB, 0x1F, 0xCE, 0x3E, 0x30, 0xDC, 0x5F, 0x5E, 0xC5, 0x0B, 0x1A, 0xA6, 0xE1, 0x39, 0xCA, 0xD5, 0x47, 0x5D, 0x3D, 0xD9, 0x01, 0x5A, 0xD6, 0x51, 0x56, 0x6C, 0x4D, 0x8B, 0x0D, 0x9A, 0x66, 0xFB, 0xCC, 0xB0, 0x2D, 0x74, 0x12, 0x2B, 0x20, 0xF0, 0xB1, 0x84, 0x99, 0xDF, 0x4C, 0xCB, 0xC2, 0x34, 0x7E, 0x76, 0x05, 0x6D, 0xB7, 0xA9, 0x31, 0xD1, 0x17, 0x04, 0xD7, 0x14, 0x58, 0x3A, 0x61, 0xDE, 0x1B, 0x11, 0x1C, 0x32, 0x0F, 0x9C, 0x16, 0x53, 0x18, 0xF2, 0x22, 0xFE, 0x44, 0xCF, 0xB2, 0xC3, 0xB5, 0x7A, 0x91, 0x24, 0x08, 0xE8, 0xA8, 0x60, 0xFC, 0x69, 0x50, 0xAA, 0xD0, 0xA0, 0x7D, 0xA1, 0x89, 0x62, 0x97, 0x54, 0x5B, 0x1E, 0x95, 0xE0, 0xFF, 0x64, 0xD2, 0x10, 0xC4, 0x00, 0x48, 0xA3, 0xF7, 0x75, 0xDB, 0x8A, 0x03, 0xE6, 0xDA, 0x09, 0x3F, 0xDD, 0x94, 0x87, 0x5C, 0x83, 0x02, 0xCD, 0x4A, 0x90, 0x33, 0x73, 0x67, 0xF6, 0xF3, 0x9D, 0x7F, 0xBF, 0xE2, 0x52, 0x9B, 0xD8, 0x26, 0xC8, 0x37, 0xC6, 0x3B, 0x81, 0x96, 0x6F, 0x4B, 0x13, 0xBE, 0x63, 0x2E, 0xE9, 0x79, 0xA7, 0x8C, 0x9F, 0x6E, 0xBC, 0x8E, 0x29, 0xF5, 0xF9, 0xB6, 0x2F, 0xFD, 0xB4, 0x59, 0x78, 0x98, 0x06, 0x6A, 0xE7, 0x46, 0x71, 0xBA, 0xD4, 0x25, 0xAB, 0x42, 0x88, 0xA2, 0x8D, 0xFA, 0x72, 0x07, 0xB9, 0x55, 0xF8, 0xEE, 0xAC, 0x0A, 0x36, 0x49, 0x2A, 0x68, 0x3C, 0x38, 0xF1, 0xA4, 0x40, 0x28, 0xD3, 0x7B, 0xBB, 0xC9, 0x43, 0xC1, 0x15, 0xE3, 0xAD, 0xF4, 0x77, 0xC7, 0x80, 0x9E }; const uint64_t x = v ^ K; const uint8_t t1 = SBOX[get_byte(0, x)]; const uint8_t t2 = rotl<1>(SBOX[get_byte(1, x)]); const uint8_t t3 = rotl<7>(SBOX[get_byte(2, x)]); const uint8_t t4 = SBOX[rotl<1>(get_byte(3, x))]; const uint8_t t5 = rotl<1>(SBOX[get_byte(4, x)]); const uint8_t t6 = rotl<7>(SBOX[get_byte(5, x)]); const uint8_t t7 = SBOX[rotl<1>(get_byte(6, x))]; const uint8_t t8 = SBOX[get_byte(7, x)]; const uint8_t y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; const uint8_t y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; const uint8_t y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; const uint8_t y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; const uint8_t y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; const uint8_t y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; const uint8_t y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; const uint8_t y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; return make_uint64(y1, y2, y3, y4, y5, y6, y7, y8); } inline uint64_t F(uint64_t v, uint64_t K) { const uint64_t x = v ^ K; return Camellia_SBOX1[get_byte(0, x)] ^ Camellia_SBOX2[get_byte(1, x)] ^ Camellia_SBOX3[get_byte(2, x)] ^ Camellia_SBOX4[get_byte(3, x)] ^ Camellia_SBOX5[get_byte(4, x)] ^ Camellia_SBOX6[get_byte(5, x)] ^ Camellia_SBOX7[get_byte(6, x)] ^ Camellia_SBOX8[get_byte(7, x)]; } inline uint64_t FL(uint64_t v, uint64_t K) { uint32_t x1 = static_cast(v >> 32); uint32_t x2 = static_cast(v & 0xFFFFFFFF); const uint32_t k1 = static_cast(K >> 32); const uint32_t k2 = static_cast(K & 0xFFFFFFFF); x2 ^= rotl<1>(x1 & k1); x1 ^= (x2 | k2); return ((static_cast(x1) << 32) | x2); } inline uint64_t FLINV(uint64_t v, uint64_t K) { uint32_t x1 = static_cast(v >> 32); uint32_t x2 = static_cast(v & 0xFFFFFFFF); const uint32_t k1 = static_cast(K >> 32); const uint32_t k2 = static_cast(K & 0xFFFFFFFF); x1 ^= (x2 | k2); x2 ^= rotl<1>(x1 & k1); return ((static_cast(x1) << 32) | x2); } /* * Camellia Encryption */ void encrypt(const uint8_t in[], uint8_t out[], size_t blocks, const secure_vector& SK, const size_t rounds) { BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint64_t D1, D2; load_be(in + 16*i, D1, D2); const uint64_t* K = SK.data(); D1 ^= *K++; D2 ^= *K++; D2 ^= F_SLOW(D1, *K++); D1 ^= F_SLOW(D2, *K++); for(size_t r = 1; r != rounds - 1; ++r) { if(r % 3 == 0) { D1 = FL (D1, *K++); D2 = FLINV(D2, *K++); } D2 ^= F(D1, *K++); D1 ^= F(D2, *K++); } D2 ^= F_SLOW(D1, *K++); D1 ^= F_SLOW(D2, *K++); D2 ^= *K++; D1 ^= *K++; store_be(out + 16*i, D2, D1); } } /* * Camellia Decryption */ void decrypt(const uint8_t in[], uint8_t out[], size_t blocks, const secure_vector& SK, const size_t rounds) { BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint64_t D1, D2; load_be(in + 16*i, D1, D2); const uint64_t* K = &SK[SK.size()-1]; D2 ^= *K--; D1 ^= *K--; D2 ^= F_SLOW(D1, *K--); D1 ^= F_SLOW(D2, *K--); for(size_t r = 1; r != rounds - 1; ++r) { if(r % 3 == 0) { D1 = FL (D1, *K--); D2 = FLINV(D2, *K--); } D2 ^= F(D1, *K--); D1 ^= F(D2, *K--); } D2 ^= F_SLOW(D1, *K--); D1 ^= F_SLOW(D2, *K--); D1 ^= *K--; D2 ^= *K; store_be(out + 16*i, D2, D1); } } uint64_t left_rot_hi(uint64_t h, uint64_t l, size_t shift) { return (h << shift) | (l >> (64-shift)); } uint64_t left_rot_lo(uint64_t h, uint64_t l, size_t shift) { return (h >> (64-shift)) | (l << shift); } /* * Camellia Key Schedule */ void key_schedule(secure_vector& SK, const uint8_t key[], size_t length) { const uint64_t Sigma1 = 0xA09E667F3BCC908B; const uint64_t Sigma2 = 0xB67AE8584CAA73B2; const uint64_t Sigma3 = 0xC6EF372FE94F82BE; const uint64_t Sigma4 = 0x54FF53A5F1D36F1C; const uint64_t Sigma5 = 0x10E527FADE682D1D; const uint64_t Sigma6 = 0xB05688C2B3E6C1FD; const uint64_t KL_H = load_be(key, 0); const uint64_t KL_L = load_be(key, 1); const uint64_t KR_H = (length >= 24) ? load_be(key, 2) : 0; const uint64_t KR_L = (length == 32) ? load_be(key, 3) : ((length == 24) ? ~KR_H : 0); uint64_t D1 = KL_H ^ KR_H; uint64_t D2 = KL_L ^ KR_L; D2 ^= F(D1, Sigma1); D1 ^= F(D2, Sigma2); D1 ^= KL_H; D2 ^= KL_L; D2 ^= F(D1, Sigma3); D1 ^= F(D2, Sigma4); const uint64_t KA_H = D1; const uint64_t KA_L = D2; D1 = KA_H ^ KR_H; D2 = KA_L ^ KR_L; D2 ^= F(D1, Sigma5); D1 ^= F(D2, Sigma6); const uint64_t KB_H = D1; const uint64_t KB_L = D2; if(length == 16) { SK.resize(26); SK[ 0] = KL_H; SK[ 1] = KL_L; SK[ 2] = KA_H; SK[ 3] = KA_L; SK[ 4] = left_rot_hi(KL_H, KL_L, 15); SK[ 5] = left_rot_lo(KL_H, KL_L, 15); SK[ 6] = left_rot_hi(KA_H, KA_L, 15); SK[ 7] = left_rot_lo(KA_H, KA_L, 15); SK[ 8] = left_rot_hi(KA_H, KA_L, 30); SK[ 9] = left_rot_lo(KA_H, KA_L, 30); SK[10] = left_rot_hi(KL_H, KL_L, 45); SK[11] = left_rot_lo(KL_H, KL_L, 45); SK[12] = left_rot_hi(KA_H, KA_L, 45); SK[13] = left_rot_lo(KL_H, KL_L, 60); SK[14] = left_rot_hi(KA_H, KA_L, 60); SK[15] = left_rot_lo(KA_H, KA_L, 60); SK[16] = left_rot_lo(KL_H, KL_L, 77-64); SK[17] = left_rot_hi(KL_H, KL_L, 77-64); SK[18] = left_rot_lo(KL_H, KL_L, 94-64); SK[19] = left_rot_hi(KL_H, KL_L, 94-64); SK[20] = left_rot_lo(KA_H, KA_L, 94-64); SK[21] = left_rot_hi(KA_H, KA_L, 94-64); SK[22] = left_rot_lo(KL_H, KL_L, 111-64); SK[23] = left_rot_hi(KL_H, KL_L, 111-64); SK[24] = left_rot_lo(KA_H, KA_L, 111-64); SK[25] = left_rot_hi(KA_H, KA_L, 111-64); } else { SK.resize(34); SK[ 0] = KL_H; SK[ 1] = KL_L; SK[ 2] = KB_H; SK[ 3] = KB_L; SK[ 4] = left_rot_hi(KR_H, KR_L, 15); SK[ 5] = left_rot_lo(KR_H, KR_L, 15); SK[ 6] = left_rot_hi(KA_H, KA_L, 15); SK[ 7] = left_rot_lo(KA_H, KA_L, 15); SK[ 8] = left_rot_hi(KR_H, KR_L, 30); SK[ 9] = left_rot_lo(KR_H, KR_L, 30); SK[10] = left_rot_hi(KB_H, KB_L, 30); SK[11] = left_rot_lo(KB_H, KB_L, 30); SK[12] = left_rot_hi(KL_H, KL_L, 45); SK[13] = left_rot_lo(KL_H, KL_L, 45); SK[14] = left_rot_hi(KA_H, KA_L, 45); SK[15] = left_rot_lo(KA_H, KA_L, 45); SK[16] = left_rot_hi(KL_H, KL_L, 60); SK[17] = left_rot_lo(KL_H, KL_L, 60); SK[18] = left_rot_hi(KR_H, KR_L, 60); SK[19] = left_rot_lo(KR_H, KR_L, 60); SK[20] = left_rot_hi(KB_H, KB_L, 60); SK[21] = left_rot_lo(KB_H, KB_L, 60); SK[22] = left_rot_lo(KL_H, KL_L, 77-64); SK[23] = left_rot_hi(KL_H, KL_L, 77-64); SK[24] = left_rot_lo(KA_H, KA_L, 77-64); SK[25] = left_rot_hi(KA_H, KA_L, 77-64); SK[26] = left_rot_lo(KR_H, KR_L, 94-64); SK[27] = left_rot_hi(KR_H, KR_L, 94-64); SK[28] = left_rot_lo(KA_H, KA_L, 94-64); SK[29] = left_rot_hi(KA_H, KA_L, 94-64); SK[30] = left_rot_lo(KL_H, KL_L, 111-64); SK[31] = left_rot_hi(KL_H, KL_L, 111-64); SK[32] = left_rot_lo(KB_H, KB_L, 111-64); SK[33] = left_rot_hi(KB_H, KB_L, 111-64); } } } } void Camellia_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SK.empty() == false); Camellia_F::encrypt(in, out, blocks, m_SK, 9); } void Camellia_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SK.empty() == false); Camellia_F::encrypt(in, out, blocks, m_SK, 12); } void Camellia_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SK.empty() == false); Camellia_F::encrypt(in, out, blocks, m_SK, 12); } void Camellia_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SK.empty() == false); Camellia_F::decrypt(in, out, blocks, m_SK, 9); } void Camellia_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SK.empty() == false); Camellia_F::decrypt(in, out, blocks, m_SK, 12); } void Camellia_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SK.empty() == false); Camellia_F::decrypt(in, out, blocks, m_SK, 12); } void Camellia_128::key_schedule(const uint8_t key[], size_t length) { Camellia_F::key_schedule(m_SK, key, length); } void Camellia_192::key_schedule(const uint8_t key[], size_t length) { Camellia_F::key_schedule(m_SK, key, length); } void Camellia_256::key_schedule(const uint8_t key[], size_t length) { Camellia_F::key_schedule(m_SK, key, length); } void Camellia_128::clear() { zap(m_SK); } void Camellia_192::clear() { zap(m_SK); } void Camellia_256::clear() { zap(m_SK); } } /* * Block Cipher Cascade * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Cascade_Cipher::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size()); size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size()); m_cipher1->encrypt_n(in, out, c1_blocks); m_cipher2->encrypt_n(out, out, c2_blocks); } void Cascade_Cipher::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size()); size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size()); m_cipher2->decrypt_n(in, out, c2_blocks); m_cipher1->decrypt_n(out, out, c1_blocks); } void Cascade_Cipher::key_schedule(const uint8_t key[], size_t) { const uint8_t* key2 = key + m_cipher1->maximum_keylength(); m_cipher1->set_key(key , m_cipher1->maximum_keylength()); m_cipher2->set_key(key2, m_cipher2->maximum_keylength()); } void Cascade_Cipher::clear() { m_cipher1->clear(); m_cipher2->clear(); } std::string Cascade_Cipher::name() const { return "Cascade(" + m_cipher1->name() + "," + m_cipher2->name() + ")"; } BlockCipher* Cascade_Cipher::clone() const { return new Cascade_Cipher(m_cipher1->clone(), m_cipher2->clone()); } namespace { size_t euclids_algorithm(size_t a, size_t b) { while(b != 0) { size_t t = b; b = a % b; a = t; } return a; } size_t block_size_for_cascade(size_t bs, size_t bs2) { if(bs == bs2) return bs; const size_t gcd = euclids_algorithm(bs, bs2); return (bs * bs2) / gcd; } } Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) : m_cipher1(c1), m_cipher2(c2) { m_block = block_size_for_cascade(c1->block_size(), c2->block_size()); BOTAN_ASSERT(m_block % c1->block_size() == 0 && m_block % c2->block_size() == 0, "Combined block size is a multiple of each ciphers block"); } } /* * CAST-128 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * CAST-128 Round Type 1 */ inline uint32_t F1(uint32_t R, uint32_t MK, uint8_t RK) { const uint32_t T = rotl_var(MK + R, RK); return (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) - CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)]; } /* * CAST-128 Round Type 2 */ inline uint32_t F2(uint32_t R, uint32_t MK, uint8_t RK) { const uint32_t T = rotl_var(MK ^ R, RK); return (CAST_SBOX1[get_byte(0, T)] - CAST_SBOX2[get_byte(1, T)] + CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)]; } /* * CAST-128 Round Type 3 */ inline uint32_t F3(uint32_t R, uint32_t MK, uint8_t RK) { const uint32_t T = rotl_var(MK - R, RK); return ((CAST_SBOX1[get_byte(0, T)] + CAST_SBOX2[get_byte(1, T)]) ^ CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)]; } } /* * CAST-128 Encryption */ void CAST_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); while(blocks >= 2) { uint32_t L0, R0, L1, R1; load_be(in, L0, R0, L1, R1); L0 ^= F1(R0, m_MK[ 0], m_RK[ 0]); L1 ^= F1(R1, m_MK[ 0], m_RK[ 0]); R0 ^= F2(L0, m_MK[ 1], m_RK[ 1]); R1 ^= F2(L1, m_MK[ 1], m_RK[ 1]); L0 ^= F3(R0, m_MK[ 2], m_RK[ 2]); L1 ^= F3(R1, m_MK[ 2], m_RK[ 2]); R0 ^= F1(L0, m_MK[ 3], m_RK[ 3]); R1 ^= F1(L1, m_MK[ 3], m_RK[ 3]); L0 ^= F2(R0, m_MK[ 4], m_RK[ 4]); L1 ^= F2(R1, m_MK[ 4], m_RK[ 4]); R0 ^= F3(L0, m_MK[ 5], m_RK[ 5]); R1 ^= F3(L1, m_MK[ 5], m_RK[ 5]); L0 ^= F1(R0, m_MK[ 6], m_RK[ 6]); L1 ^= F1(R1, m_MK[ 6], m_RK[ 6]); R0 ^= F2(L0, m_MK[ 7], m_RK[ 7]); R1 ^= F2(L1, m_MK[ 7], m_RK[ 7]); L0 ^= F3(R0, m_MK[ 8], m_RK[ 8]); L1 ^= F3(R1, m_MK[ 8], m_RK[ 8]); R0 ^= F1(L0, m_MK[ 9], m_RK[ 9]); R1 ^= F1(L1, m_MK[ 9], m_RK[ 9]); L0 ^= F2(R0, m_MK[10], m_RK[10]); L1 ^= F2(R1, m_MK[10], m_RK[10]); R0 ^= F3(L0, m_MK[11], m_RK[11]); R1 ^= F3(L1, m_MK[11], m_RK[11]); L0 ^= F1(R0, m_MK[12], m_RK[12]); L1 ^= F1(R1, m_MK[12], m_RK[12]); R0 ^= F2(L0, m_MK[13], m_RK[13]); R1 ^= F2(L1, m_MK[13], m_RK[13]); L0 ^= F3(R0, m_MK[14], m_RK[14]); L1 ^= F3(R1, m_MK[14], m_RK[14]); R0 ^= F1(L0, m_MK[15], m_RK[15]); R1 ^= F1(L1, m_MK[15], m_RK[15]); store_be(out, R0, L0, R1, L1); blocks -= 2; out += 2 * BLOCK_SIZE; in += 2 * BLOCK_SIZE; } if(blocks) { uint32_t L, R; load_be(in, L, R); L ^= F1(R, m_MK[ 0], m_RK[ 0]); R ^= F2(L, m_MK[ 1], m_RK[ 1]); L ^= F3(R, m_MK[ 2], m_RK[ 2]); R ^= F1(L, m_MK[ 3], m_RK[ 3]); L ^= F2(R, m_MK[ 4], m_RK[ 4]); R ^= F3(L, m_MK[ 5], m_RK[ 5]); L ^= F1(R, m_MK[ 6], m_RK[ 6]); R ^= F2(L, m_MK[ 7], m_RK[ 7]); L ^= F3(R, m_MK[ 8], m_RK[ 8]); R ^= F1(L, m_MK[ 9], m_RK[ 9]); L ^= F2(R, m_MK[10], m_RK[10]); R ^= F3(L, m_MK[11], m_RK[11]); L ^= F1(R, m_MK[12], m_RK[12]); R ^= F2(L, m_MK[13], m_RK[13]); L ^= F3(R, m_MK[14], m_RK[14]); R ^= F1(L, m_MK[15], m_RK[15]); store_be(out, R, L); } } /* * CAST-128 Decryption */ void CAST_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); while(blocks >= 2) { uint32_t L0, R0, L1, R1; load_be(in, L0, R0, L1, R1); L0 ^= F1(R0, m_MK[15], m_RK[15]); L1 ^= F1(R1, m_MK[15], m_RK[15]); R0 ^= F3(L0, m_MK[14], m_RK[14]); R1 ^= F3(L1, m_MK[14], m_RK[14]); L0 ^= F2(R0, m_MK[13], m_RK[13]); L1 ^= F2(R1, m_MK[13], m_RK[13]); R0 ^= F1(L0, m_MK[12], m_RK[12]); R1 ^= F1(L1, m_MK[12], m_RK[12]); L0 ^= F3(R0, m_MK[11], m_RK[11]); L1 ^= F3(R1, m_MK[11], m_RK[11]); R0 ^= F2(L0, m_MK[10], m_RK[10]); R1 ^= F2(L1, m_MK[10], m_RK[10]); L0 ^= F1(R0, m_MK[ 9], m_RK[ 9]); L1 ^= F1(R1, m_MK[ 9], m_RK[ 9]); R0 ^= F3(L0, m_MK[ 8], m_RK[ 8]); R1 ^= F3(L1, m_MK[ 8], m_RK[ 8]); L0 ^= F2(R0, m_MK[ 7], m_RK[ 7]); L1 ^= F2(R1, m_MK[ 7], m_RK[ 7]); R0 ^= F1(L0, m_MK[ 6], m_RK[ 6]); R1 ^= F1(L1, m_MK[ 6], m_RK[ 6]); L0 ^= F3(R0, m_MK[ 5], m_RK[ 5]); L1 ^= F3(R1, m_MK[ 5], m_RK[ 5]); R0 ^= F2(L0, m_MK[ 4], m_RK[ 4]); R1 ^= F2(L1, m_MK[ 4], m_RK[ 4]); L0 ^= F1(R0, m_MK[ 3], m_RK[ 3]); L1 ^= F1(R1, m_MK[ 3], m_RK[ 3]); R0 ^= F3(L0, m_MK[ 2], m_RK[ 2]); R1 ^= F3(L1, m_MK[ 2], m_RK[ 2]); L0 ^= F2(R0, m_MK[ 1], m_RK[ 1]); L1 ^= F2(R1, m_MK[ 1], m_RK[ 1]); R0 ^= F1(L0, m_MK[ 0], m_RK[ 0]); R1 ^= F1(L1, m_MK[ 0], m_RK[ 0]); store_be(out, R0, L0, R1, L1); blocks -= 2; out += 2 * BLOCK_SIZE; in += 2 * BLOCK_SIZE; } if(blocks) { uint32_t L, R; load_be(in, L, R); L ^= F1(R, m_MK[15], m_RK[15]); R ^= F3(L, m_MK[14], m_RK[14]); L ^= F2(R, m_MK[13], m_RK[13]); R ^= F1(L, m_MK[12], m_RK[12]); L ^= F3(R, m_MK[11], m_RK[11]); R ^= F2(L, m_MK[10], m_RK[10]); L ^= F1(R, m_MK[ 9], m_RK[ 9]); R ^= F3(L, m_MK[ 8], m_RK[ 8]); L ^= F2(R, m_MK[ 7], m_RK[ 7]); R ^= F1(L, m_MK[ 6], m_RK[ 6]); L ^= F3(R, m_MK[ 5], m_RK[ 5]); R ^= F2(L, m_MK[ 4], m_RK[ 4]); L ^= F1(R, m_MK[ 3], m_RK[ 3]); R ^= F3(L, m_MK[ 2], m_RK[ 2]); L ^= F2(R, m_MK[ 1], m_RK[ 1]); R ^= F1(L, m_MK[ 0], m_RK[ 0]); store_be(out, R, L); } } /* * CAST-128 Key Schedule */ void CAST_128::key_schedule(const uint8_t key[], size_t length) { m_MK.resize(48); m_RK.resize(48); secure_vector key16(16); copy_mem(key16.data(), key, length); secure_vector X(4); for(size_t i = 0; i != 4; ++i) X[i] = load_be(key16.data(), i); cast_ks(m_MK, X); secure_vector RK32(48); cast_ks(RK32, X); for(size_t i = 0; i != 16; ++i) m_RK[i] = RK32[i] % 32; } void CAST_128::clear() { zap(m_MK); zap(m_RK); } /* * S-Box Based Key Expansion */ void CAST_128::cast_ks(secure_vector& K, secure_vector& X) { alignas(64) static const uint32_t S5[256] = { 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; alignas(64) static const uint32_t S6[256] = { 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; alignas(64) static const uint32_t S7[256] = { 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; alignas(64) static const uint32_t S8[256] = { 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; class ByteReader final { public: uint8_t operator()(size_t i) const { return static_cast(m_X[i/4] >> (8*(3 - (i%4)))); } explicit ByteReader(const uint32_t* x) : m_X(x) {} private: const uint32_t* m_X; }; secure_vector Z(4); ByteReader x(X.data()), z(Z.data()); Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; K[ 0] = S5[z( 8)] ^ S6[z( 9)] ^ S7[z( 7)] ^ S8[z( 6)] ^ S5[z( 2)]; K[ 1] = S5[z(10)] ^ S6[z(11)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S6[z( 6)]; K[ 2] = S5[z(12)] ^ S6[z(13)] ^ S7[z( 3)] ^ S8[z( 2)] ^ S7[z( 9)]; K[ 3] = S5[z(14)] ^ S6[z(15)] ^ S7[z( 1)] ^ S8[z( 0)] ^ S8[z(12)]; X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; K[ 4] = S5[x( 3)] ^ S6[x( 2)] ^ S7[x(12)] ^ S8[x(13)] ^ S5[x( 8)]; K[ 5] = S5[x( 1)] ^ S6[x( 0)] ^ S7[x(14)] ^ S8[x(15)] ^ S6[x(13)]; K[ 6] = S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 8)] ^ S8[x( 9)] ^ S7[x( 3)]; K[ 7] = S5[x( 5)] ^ S6[x( 4)] ^ S7[x(10)] ^ S8[x(11)] ^ S8[x( 7)]; Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; K[ 8] = S5[z( 3)] ^ S6[z( 2)] ^ S7[z(12)] ^ S8[z(13)] ^ S5[z( 9)]; K[ 9] = S5[z( 1)] ^ S6[z( 0)] ^ S7[z(14)] ^ S8[z(15)] ^ S6[z(12)]; K[10] = S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 8)] ^ S8[z( 9)] ^ S7[z( 2)]; K[11] = S5[z( 5)] ^ S6[z( 4)] ^ S7[z(10)] ^ S8[z(11)] ^ S8[z( 6)]; X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; K[12] = S5[x( 8)] ^ S6[x( 9)] ^ S7[x( 7)] ^ S8[x( 6)] ^ S5[x( 3)]; K[13] = S5[x(10)] ^ S6[x(11)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S6[x( 7)]; K[14] = S5[x(12)] ^ S6[x(13)] ^ S7[x( 3)] ^ S8[x( 2)] ^ S7[x( 8)]; K[15] = S5[x(14)] ^ S6[x(15)] ^ S7[x( 1)] ^ S8[x( 0)] ^ S8[x(13)]; } } /* * CAST-256 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * CAST-256 Round Type 1 */ void round1(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) { const uint32_t T = rotl_var(MK + in, RK); out ^= (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) - CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)]; } /* * CAST-256 Round Type 2 */ void round2(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) { const uint32_t T = rotl_var(MK ^ in, RK); out ^= (CAST_SBOX1[get_byte(0, T)] - CAST_SBOX2[get_byte(1, T)] + CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)]; } /* * CAST-256 Round Type 3 */ void round3(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) { const uint32_t T = rotl_var(MK - in, RK); out ^= ((CAST_SBOX1[get_byte(0, T)] + CAST_SBOX2[get_byte(1, T)]) ^ CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)]; } } /* * CAST-256 Encryption */ void CAST_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint32_t A = load_be(in, 0); uint32_t B = load_be(in, 1); uint32_t C = load_be(in, 2); uint32_t D = load_be(in, 3); round1(C, D, m_MK[ 0], m_RK[ 0]); round2(B, C, m_MK[ 1], m_RK[ 1]); round3(A, B, m_MK[ 2], m_RK[ 2]); round1(D, A, m_MK[ 3], m_RK[ 3]); round1(C, D, m_MK[ 4], m_RK[ 4]); round2(B, C, m_MK[ 5], m_RK[ 5]); round3(A, B, m_MK[ 6], m_RK[ 6]); round1(D, A, m_MK[ 7], m_RK[ 7]); round1(C, D, m_MK[ 8], m_RK[ 8]); round2(B, C, m_MK[ 9], m_RK[ 9]); round3(A, B, m_MK[10], m_RK[10]); round1(D, A, m_MK[11], m_RK[11]); round1(C, D, m_MK[12], m_RK[12]); round2(B, C, m_MK[13], m_RK[13]); round3(A, B, m_MK[14], m_RK[14]); round1(D, A, m_MK[15], m_RK[15]); round1(C, D, m_MK[16], m_RK[16]); round2(B, C, m_MK[17], m_RK[17]); round3(A, B, m_MK[18], m_RK[18]); round1(D, A, m_MK[19], m_RK[19]); round1(C, D, m_MK[20], m_RK[20]); round2(B, C, m_MK[21], m_RK[21]); round3(A, B, m_MK[22], m_RK[22]); round1(D, A, m_MK[23], m_RK[23]); round1(D, A, m_MK[27], m_RK[27]); round3(A, B, m_MK[26], m_RK[26]); round2(B, C, m_MK[25], m_RK[25]); round1(C, D, m_MK[24], m_RK[24]); round1(D, A, m_MK[31], m_RK[31]); round3(A, B, m_MK[30], m_RK[30]); round2(B, C, m_MK[29], m_RK[29]); round1(C, D, m_MK[28], m_RK[28]); round1(D, A, m_MK[35], m_RK[35]); round3(A, B, m_MK[34], m_RK[34]); round2(B, C, m_MK[33], m_RK[33]); round1(C, D, m_MK[32], m_RK[32]); round1(D, A, m_MK[39], m_RK[39]); round3(A, B, m_MK[38], m_RK[38]); round2(B, C, m_MK[37], m_RK[37]); round1(C, D, m_MK[36], m_RK[36]); round1(D, A, m_MK[43], m_RK[43]); round3(A, B, m_MK[42], m_RK[42]); round2(B, C, m_MK[41], m_RK[41]); round1(C, D, m_MK[40], m_RK[40]); round1(D, A, m_MK[47], m_RK[47]); round3(A, B, m_MK[46], m_RK[46]); round2(B, C, m_MK[45], m_RK[45]); round1(C, D, m_MK[44], m_RK[44]); store_be(out, A, B, C, D); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * CAST-256 Decryption */ void CAST_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint32_t A = load_be(in, 0); uint32_t B = load_be(in, 1); uint32_t C = load_be(in, 2); uint32_t D = load_be(in, 3); round1(C, D, m_MK[44], m_RK[44]); round2(B, C, m_MK[45], m_RK[45]); round3(A, B, m_MK[46], m_RK[46]); round1(D, A, m_MK[47], m_RK[47]); round1(C, D, m_MK[40], m_RK[40]); round2(B, C, m_MK[41], m_RK[41]); round3(A, B, m_MK[42], m_RK[42]); round1(D, A, m_MK[43], m_RK[43]); round1(C, D, m_MK[36], m_RK[36]); round2(B, C, m_MK[37], m_RK[37]); round3(A, B, m_MK[38], m_RK[38]); round1(D, A, m_MK[39], m_RK[39]); round1(C, D, m_MK[32], m_RK[32]); round2(B, C, m_MK[33], m_RK[33]); round3(A, B, m_MK[34], m_RK[34]); round1(D, A, m_MK[35], m_RK[35]); round1(C, D, m_MK[28], m_RK[28]); round2(B, C, m_MK[29], m_RK[29]); round3(A, B, m_MK[30], m_RK[30]); round1(D, A, m_MK[31], m_RK[31]); round1(C, D, m_MK[24], m_RK[24]); round2(B, C, m_MK[25], m_RK[25]); round3(A, B, m_MK[26], m_RK[26]); round1(D, A, m_MK[27], m_RK[27]); round1(D, A, m_MK[23], m_RK[23]); round3(A, B, m_MK[22], m_RK[22]); round2(B, C, m_MK[21], m_RK[21]); round1(C, D, m_MK[20], m_RK[20]); round1(D, A, m_MK[19], m_RK[19]); round3(A, B, m_MK[18], m_RK[18]); round2(B, C, m_MK[17], m_RK[17]); round1(C, D, m_MK[16], m_RK[16]); round1(D, A, m_MK[15], m_RK[15]); round3(A, B, m_MK[14], m_RK[14]); round2(B, C, m_MK[13], m_RK[13]); round1(C, D, m_MK[12], m_RK[12]); round1(D, A, m_MK[11], m_RK[11]); round3(A, B, m_MK[10], m_RK[10]); round2(B, C, m_MK[ 9], m_RK[ 9]); round1(C, D, m_MK[ 8], m_RK[ 8]); round1(D, A, m_MK[ 7], m_RK[ 7]); round3(A, B, m_MK[ 6], m_RK[ 6]); round2(B, C, m_MK[ 5], m_RK[ 5]); round1(C, D, m_MK[ 4], m_RK[ 4]); round1(D, A, m_MK[ 3], m_RK[ 3]); round3(A, B, m_MK[ 2], m_RK[ 2]); round2(B, C, m_MK[ 1], m_RK[ 1]); round1(C, D, m_MK[ 0], m_RK[ 0]); store_be(out, A, B, C, D); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * CAST-256 Key Schedule */ void CAST_256::key_schedule(const uint8_t key[], size_t length) { static const uint32_t KEY_MASK[192] = { 0x5A827999, 0xC95C653A, 0x383650DB, 0xA7103C7C, 0x15EA281D, 0x84C413BE, 0xF39DFF5F, 0x6277EB00, 0xD151D6A1, 0x402BC242, 0xAF05ADE3, 0x1DDF9984, 0x8CB98525, 0xFB9370C6, 0x6A6D5C67, 0xD9474808, 0x482133A9, 0xB6FB1F4A, 0x25D50AEB, 0x94AEF68C, 0x0388E22D, 0x7262CDCE, 0xE13CB96F, 0x5016A510, 0xBEF090B1, 0x2DCA7C52, 0x9CA467F3, 0x0B7E5394, 0x7A583F35, 0xE9322AD6, 0x580C1677, 0xC6E60218, 0x35BFEDB9, 0xA499D95A, 0x1373C4FB, 0x824DB09C, 0xF1279C3D, 0x600187DE, 0xCEDB737F, 0x3DB55F20, 0xAC8F4AC1, 0x1B693662, 0x8A432203, 0xF91D0DA4, 0x67F6F945, 0xD6D0E4E6, 0x45AAD087, 0xB484BC28, 0x235EA7C9, 0x9238936A, 0x01127F0B, 0x6FEC6AAC, 0xDEC6564D, 0x4DA041EE, 0xBC7A2D8F, 0x2B541930, 0x9A2E04D1, 0x0907F072, 0x77E1DC13, 0xE6BBC7B4, 0x5595B355, 0xC46F9EF6, 0x33498A97, 0xA2237638, 0x10FD61D9, 0x7FD74D7A, 0xEEB1391B, 0x5D8B24BC, 0xCC65105D, 0x3B3EFBFE, 0xAA18E79F, 0x18F2D340, 0x87CCBEE1, 0xF6A6AA82, 0x65809623, 0xD45A81C4, 0x43346D65, 0xB20E5906, 0x20E844A7, 0x8FC23048, 0xFE9C1BE9, 0x6D76078A, 0xDC4FF32B, 0x4B29DECC, 0xBA03CA6D, 0x28DDB60E, 0x97B7A1AF, 0x06918D50, 0x756B78F1, 0xE4456492, 0x531F5033, 0xC1F93BD4, 0x30D32775, 0x9FAD1316, 0x0E86FEB7, 0x7D60EA58, 0xEC3AD5F9, 0x5B14C19A, 0xC9EEAD3B, 0x38C898DC, 0xA7A2847D, 0x167C701E, 0x85565BBF, 0xF4304760, 0x630A3301, 0xD1E41EA2, 0x40BE0A43, 0xAF97F5E4, 0x1E71E185, 0x8D4BCD26, 0xFC25B8C7, 0x6AFFA468, 0xD9D99009, 0x48B37BAA, 0xB78D674B, 0x266752EC, 0x95413E8D, 0x041B2A2E, 0x72F515CF, 0xE1CF0170, 0x50A8ED11, 0xBF82D8B2, 0x2E5CC453, 0x9D36AFF4, 0x0C109B95, 0x7AEA8736, 0xE9C472D7, 0x589E5E78, 0xC7784A19, 0x365235BA, 0xA52C215B, 0x14060CFC, 0x82DFF89D, 0xF1B9E43E, 0x6093CFDF, 0xCF6DBB80, 0x3E47A721, 0xAD2192C2, 0x1BFB7E63, 0x8AD56A04, 0xF9AF55A5, 0x68894146, 0xD7632CE7, 0x463D1888, 0xB5170429, 0x23F0EFCA, 0x92CADB6B, 0x01A4C70C, 0x707EB2AD, 0xDF589E4E, 0x4E3289EF, 0xBD0C7590, 0x2BE66131, 0x9AC04CD2, 0x099A3873, 0x78742414, 0xE74E0FB5, 0x5627FB56, 0xC501E6F7, 0x33DBD298, 0xA2B5BE39, 0x118FA9DA, 0x8069957B, 0xEF43811C, 0x5E1D6CBD, 0xCCF7585E, 0x3BD143FF, 0xAAAB2FA0, 0x19851B41, 0x885F06E2, 0xF738F283, 0x6612DE24, 0xD4ECC9C5, 0x43C6B566, 0xB2A0A107, 0x217A8CA8, 0x90547849, 0xFF2E63EA, 0x6E084F8B, 0xDCE23B2C, 0x4BBC26CD, 0xBA96126E, 0x296FFE0F, 0x9849E9B0, 0x0723D551, 0x75FDC0F2, 0xE4D7AC93, 0x53B19834, 0xC28B83D5, 0x31656F76, 0xA03F5B17, 0x0F1946B8 }; static const uint8_t KEY_ROT[32] = { 0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0A, 0x1B, 0x0C, 0x1D, 0x0E, 0x1F, 0x10, 0x01, 0x12, 0x03, 0x14, 0x05, 0x16, 0x07, 0x18, 0x09, 0x1A, 0x0B, 0x1C, 0x0D, 0x1E, 0x0F, 0x00, 0x11, 0x02 }; m_MK.resize(48); m_RK.resize(48); secure_vector K(8); for(size_t i = 0; i != length; ++i) K[i/4] = (K[i/4] << 8) + key[i]; uint32_t A = K[0], B = K[1], C = K[2], D = K[3], E = K[4], F = K[5], G = K[6], H = K[7]; for(size_t i = 0; i != 48; i += 4) { round1(G, H, KEY_MASK[4*i+ 0], KEY_ROT[(4*i+ 0) % 32]); round2(F, G, KEY_MASK[4*i+ 1], KEY_ROT[(4*i+ 1) % 32]); round3(E, F, KEY_MASK[4*i+ 2], KEY_ROT[(4*i+ 2) % 32]); round1(D, E, KEY_MASK[4*i+ 3], KEY_ROT[(4*i+ 3) % 32]); round2(C, D, KEY_MASK[4*i+ 4], KEY_ROT[(4*i+ 4) % 32]); round3(B, C, KEY_MASK[4*i+ 5], KEY_ROT[(4*i+ 5) % 32]); round1(A, B, KEY_MASK[4*i+ 6], KEY_ROT[(4*i+ 6) % 32]); round2(H, A, KEY_MASK[4*i+ 7], KEY_ROT[(4*i+ 7) % 32]); round1(G, H, KEY_MASK[4*i+ 8], KEY_ROT[(4*i+ 8) % 32]); round2(F, G, KEY_MASK[4*i+ 9], KEY_ROT[(4*i+ 9) % 32]); round3(E, F, KEY_MASK[4*i+10], KEY_ROT[(4*i+10) % 32]); round1(D, E, KEY_MASK[4*i+11], KEY_ROT[(4*i+11) % 32]); round2(C, D, KEY_MASK[4*i+12], KEY_ROT[(4*i+12) % 32]); round3(B, C, KEY_MASK[4*i+13], KEY_ROT[(4*i+13) % 32]); round1(A, B, KEY_MASK[4*i+14], KEY_ROT[(4*i+14) % 32]); round2(H, A, KEY_MASK[4*i+15], KEY_ROT[(4*i+15) % 32]); m_RK[i ] = (A % 32); m_RK[i+1] = (C % 32); m_RK[i+2] = (E % 32); m_RK[i+3] = (G % 32); m_MK[i ] = H; m_MK[i+1] = F; m_MK[i+2] = D; m_MK[i+3] = B; } } void CAST_256::clear() { zap(m_MK); zap(m_RK); } } /* * CBC Mode * (C) 1999-2007,2013,2017 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * (C) 2018 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : m_cipher(cipher), m_padding(padding), m_block_size(cipher->block_size()) { if(m_padding && !m_padding->valid_blocksize(m_block_size)) throw Invalid_Argument("Padding " + m_padding->name() + " cannot be used with " + cipher->name() + "/CBC"); } void CBC_Mode::clear() { m_cipher->clear(); reset(); } void CBC_Mode::reset() { m_state.clear(); } std::string CBC_Mode::name() const { if(m_padding) return cipher().name() + "/CBC/" + padding().name(); else return cipher().name() + "/CBC/CTS"; } size_t CBC_Mode::update_granularity() const { return cipher().parallel_bytes(); } Key_Length_Specification CBC_Mode::key_spec() const { return cipher().key_spec(); } size_t CBC_Mode::default_nonce_length() const { return block_size(); } bool CBC_Mode::valid_nonce_length(size_t n) const { return (n == 0 || n == block_size()); } void CBC_Mode::key_schedule(const uint8_t key[], size_t length) { m_cipher->set_key(key, length); m_state.clear(); } void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); /* * A nonce of zero length means carry the last ciphertext value over * as the new IV, as unfortunately some protocols require this. If * this is the first message then we use an IV of all zeros. */ if(nonce_len) m_state.assign(nonce, nonce + nonce_len); else if(m_state.empty()) m_state.resize(m_cipher->block_size()); // else leave the state alone } size_t CBC_Encryption::minimum_final_size() const { return 0; } size_t CBC_Encryption::output_length(size_t input_length) const { if(input_length == 0) return block_size(); else return round_up(input_length, block_size()); } size_t CBC_Encryption::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(state().empty() == false); const size_t BS = block_size(); BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks"); const size_t blocks = sz / BS; if(blocks > 0) { xor_buf(&buf[0], state_ptr(), BS); cipher().encrypt(&buf[0]); for(size_t i = 1; i != blocks; ++i) { xor_buf(&buf[BS*i], &buf[BS*(i-1)], BS); cipher().encrypt(&buf[BS*i]); } state().assign(&buf[BS*(blocks-1)], &buf[BS*blocks]); } return sz; } void CBC_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_STATE_CHECK(state().empty() == false); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t BS = block_size(); const size_t bytes_in_final_block = (buffer.size()-offset) % BS; padding().add_padding(buffer, bytes_in_final_block, BS); BOTAN_ASSERT_EQUAL(buffer.size() % BS, offset % BS, "Padded to block boundary"); update(buffer, offset); } bool CTS_Encryption::valid_nonce_length(size_t n) const { return (n == block_size()); } size_t CTS_Encryption::minimum_final_size() const { return block_size() + 1; } size_t CTS_Encryption::output_length(size_t input_length) const { return input_length; // no ciphertext expansion in CTS } void CTS_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_STATE_CHECK(state().empty() == false); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); uint8_t* buf = buffer.data() + offset; const size_t sz = buffer.size() - offset; const size_t BS = block_size(); if(sz < BS + 1) throw Encoding_Error(name() + ": insufficient data to encrypt"); if(sz % BS == 0) { update(buffer, offset); // swap last two blocks for(size_t i = 0; i != BS; ++i) std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); } else { const size_t full_blocks = ((sz / BS) - 1) * BS; const size_t final_bytes = sz - full_blocks; BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); buffer.resize(full_blocks + offset); update(buffer, offset); xor_buf(last.data(), state_ptr(), BS); cipher().encrypt(last.data()); for(size_t i = 0; i != final_bytes - BS; ++i) { last[i] ^= last[i + BS]; last[i + BS] ^= last[i]; } cipher().encrypt(last.data()); buffer += last; } } size_t CBC_Decryption::output_length(size_t input_length) const { return input_length; // precise for CTS, worst case otherwise } size_t CBC_Decryption::minimum_final_size() const { return block_size(); } size_t CBC_Decryption::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(state().empty() == false); const size_t BS = block_size(); BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); size_t blocks = sz / BS; while(blocks) { const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS); xor_buf(m_tempbuf.data(), state_ptr(), BS); xor_buf(&m_tempbuf[BS], buf, to_proc - BS); copy_mem(state_ptr(), buf + (to_proc - BS), BS); copy_mem(buf, m_tempbuf.data(), to_proc); buf += to_proc; blocks -= to_proc / BS; } return sz; } void CBC_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_STATE_CHECK(state().empty() == false); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; const size_t BS = block_size(); if(sz == 0 || sz % BS) throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); update(buffer, offset); const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); buffer.resize(buffer.size() - pad_bytes); // remove padding if(pad_bytes == 0 && padding().name() != "NoPadding") { throw Decoding_Error("Invalid CBC padding"); } } void CBC_Decryption::reset() { CBC_Mode::reset(); zeroise(m_tempbuf); } bool CTS_Decryption::valid_nonce_length(size_t n) const { return (n == block_size()); } size_t CTS_Decryption::minimum_final_size() const { return block_size() + 1; } void CTS_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_STATE_CHECK(state().empty() == false); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; const size_t BS = block_size(); if(sz < BS + 1) throw Encoding_Error(name() + ": insufficient data to decrypt"); if(sz % BS == 0) { // swap last two blocks for(size_t i = 0; i != BS; ++i) std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); update(buffer, offset); } else { const size_t full_blocks = ((sz / BS) - 1) * BS; const size_t final_bytes = sz - full_blocks; BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); buffer.resize(full_blocks + offset); update(buffer, offset); cipher().decrypt(last.data()); xor_buf(last.data(), &last[BS], final_bytes - BS); for(size_t i = 0; i != final_bytes - BS; ++i) std::swap(last[i], last[i + BS]); cipher().decrypt(last.data()); xor_buf(last.data(), state_ptr(), BS); buffer += last; } } } /* * CBC-MAC * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Update an CBC-MAC Calculation */ void CBC_MAC::add_data(const uint8_t input[], size_t length) { verify_key_set(m_state.empty() == false); size_t xored = std::min(output_length() - m_position, length); xor_buf(&m_state[m_position], input, xored); m_position += xored; if(m_position < output_length()) return; m_cipher->encrypt(m_state); input += xored; length -= xored; while(length >= output_length()) { xor_buf(m_state, input, output_length()); m_cipher->encrypt(m_state); input += output_length(); length -= output_length(); } xor_buf(m_state, input, length); m_position = length; } /* * Finalize an CBC-MAC Calculation */ void CBC_MAC::final_result(uint8_t mac[]) { verify_key_set(m_state.empty() == false); if(m_position) m_cipher->encrypt(m_state); copy_mem(mac, m_state.data(), m_state.size()); zeroise(m_state); m_position = 0; } /* * CBC-MAC Key Schedule */ void CBC_MAC::key_schedule(const uint8_t key[], size_t length) { m_state.resize(m_cipher->block_size()); m_cipher->set_key(key, length); } /* * Clear memory of sensitive data */ void CBC_MAC::clear() { m_cipher->clear(); zap(m_state); m_position = 0; } /* * Return the name of this type */ std::string CBC_MAC::name() const { return "CBC-MAC(" + m_cipher->name() + ")"; } /* * Return a clone of this object */ MessageAuthenticationCode* CBC_MAC::clone() const { return new CBC_MAC(m_cipher->clone()); } /* * CBC-MAC Constructor */ CBC_MAC::CBC_MAC(BlockCipher* cipher) : m_cipher(cipher) { } } /* * CCM Mode Encryption * (C) 2013,2018 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { // 128-bit cipher is intrinsic to CCM definition static const size_t CCM_BS = 16; /* * CCM_Mode Constructor */ CCM_Mode::CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L) : m_tag_size(tag_size), m_L(L), m_cipher(cipher) { if(m_cipher->block_size() != CCM_BS) throw Invalid_Argument(m_cipher->name() + " cannot be used with CCM mode"); if(L < 2 || L > 8) throw Invalid_Argument("Invalid CCM L value " + std::to_string(L)); if(tag_size < 4 || tag_size > 16 || tag_size % 2 != 0) throw Invalid_Argument("invalid CCM tag length " + std::to_string(tag_size)); } void CCM_Mode::clear() { m_cipher->clear(); reset(); } void CCM_Mode::reset() { m_nonce.clear(); m_msg_buf.clear(); m_ad_buf.clear(); } std::string CCM_Mode::name() const { return (m_cipher->name() + "/CCM(" + std::to_string(tag_size()) + "," + std::to_string(L())) + ")"; } bool CCM_Mode::valid_nonce_length(size_t n) const { return (n == (15-L())); } size_t CCM_Mode::default_nonce_length() const { return (15-L()); } size_t CCM_Mode::update_granularity() const { /* This value does not particularly matter as regardless CCM_Mode::update buffers all input, so in theory this could be 1. However as for instance Transform_Filter creates update_granularity() uint8_t buffers, use a somewhat large size to avoid bouncing on a tiny buffer. */ return m_cipher->parallel_bytes(); } Key_Length_Specification CCM_Mode::key_spec() const { return m_cipher->key_spec(); } void CCM_Mode::key_schedule(const uint8_t key[], size_t length) { m_cipher->set_key(key, length); } void CCM_Mode::set_associated_data(const uint8_t ad[], size_t length) { m_ad_buf.clear(); if(length) { // FIXME: support larger AD using length encoding rules BOTAN_ARG_CHECK(length < (0xFFFF - 0xFF), "Supported CCM AD length"); m_ad_buf.push_back(get_byte(0, static_cast(length))); m_ad_buf.push_back(get_byte(1, static_cast(length))); m_ad_buf += std::make_pair(ad, length); while(m_ad_buf.size() % CCM_BS) m_ad_buf.push_back(0); // pad with zeros to full block size } } void CCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); m_nonce.assign(nonce, nonce + nonce_len); m_msg_buf.clear(); } size_t CCM_Mode::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(m_nonce.size() > 0); m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz); return 0; // no output until finished } void CCM_Mode::encode_length(uint64_t len, uint8_t out[]) { const size_t len_bytes = L(); BOTAN_ASSERT_NOMSG(len_bytes >= 2 && len_bytes <= 8); for(size_t i = 0; i != len_bytes; ++i) out[len_bytes-1-i] = get_byte(sizeof(uint64_t)-1-i, len); if(len_bytes < 8 && (len >> (len_bytes*8)) > 0) throw Encoding_Error("CCM message length too long to encode in L field"); } void CCM_Mode::inc(secure_vector& C) { for(size_t i = 0; i != C.size(); ++i) if(++C[C.size()-i-1]) break; } secure_vector CCM_Mode::format_b0(size_t sz) { if(m_nonce.size() != 15-L()) throw Invalid_State("CCM mode must set nonce"); secure_vector B0(CCM_BS); const uint8_t b_flags = static_cast((m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1)); B0[0] = b_flags; copy_mem(&B0[1], m_nonce.data(), m_nonce.size()); encode_length(sz, &B0[m_nonce.size()+1]); return B0; } secure_vector CCM_Mode::format_c0() { if(m_nonce.size() != 15-L()) throw Invalid_State("CCM mode must set nonce"); secure_vector C(CCM_BS); const uint8_t a_flags = static_cast(L() - 1); C[0] = a_flags; copy_mem(&C[1], m_nonce.data(), m_nonce.size()); return C; } void CCM_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane"); buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; const secure_vector& ad = ad_buf(); BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple"); const BlockCipher& E = cipher(); secure_vector T(CCM_BS); E.encrypt(format_b0(sz), T); for(size_t i = 0; i != ad.size(); i += CCM_BS) { xor_buf(T.data(), &ad[i], CCM_BS); E.encrypt(T); } secure_vector C = format_c0(); secure_vector S0(CCM_BS); E.encrypt(C, S0); inc(C); secure_vector X(CCM_BS); const uint8_t* buf_end = &buf[sz]; while(buf != buf_end) { const size_t to_proc = std::min(CCM_BS, buf_end - buf); xor_buf(T.data(), buf, to_proc); E.encrypt(T); E.encrypt(C, X); xor_buf(buf, X.data(), to_proc); inc(C); buf += to_proc; } T ^= S0; buffer += std::make_pair(T.data(), tag_size()); reset(); } void CCM_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane"); buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); const secure_vector& ad = ad_buf(); BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple"); const BlockCipher& E = cipher(); secure_vector T(CCM_BS); E.encrypt(format_b0(sz - tag_size()), T); for(size_t i = 0; i != ad.size(); i += CCM_BS) { xor_buf(T.data(), &ad[i], CCM_BS); E.encrypt(T); } secure_vector C = format_c0(); secure_vector S0(CCM_BS); E.encrypt(C, S0); inc(C); secure_vector X(CCM_BS); const uint8_t* buf_end = &buf[sz - tag_size()]; while(buf != buf_end) { const size_t to_proc = std::min(CCM_BS, buf_end - buf); E.encrypt(C, X); xor_buf(buf, X.data(), to_proc); inc(C); xor_buf(T.data(), buf, to_proc); E.encrypt(T); buf += to_proc; } T ^= S0; if(!constant_time_compare(T.data(), buf_end, tag_size())) throw Invalid_Authentication_Tag("CCM tag check failed"); buffer.resize(buffer.size() - tag_size()); reset(); } } /* * CECPQ1 (x25519 + NewHope) * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void CECPQ1_offer(uint8_t send[CECPQ1_OFFER_BYTES], CECPQ1_key* offer_key_output, RandomNumberGenerator& rng) { offer_key_output->m_x25519 = rng.random_vec(32); curve25519_basepoint(send, offer_key_output->m_x25519.data()); newhope_keygen(send + 32, &offer_key_output->m_newhope, rng, Newhope_Mode::BoringSSL); } void CECPQ1_accept(uint8_t shared_key[CECPQ1_SHARED_KEY_BYTES], uint8_t send[CECPQ1_ACCEPT_BYTES], const uint8_t received[CECPQ1_OFFER_BYTES], RandomNumberGenerator& rng) { secure_vector x25519_key = rng.random_vec(32); curve25519_basepoint(send, x25519_key.data()); curve25519_donna(shared_key, x25519_key.data(), received); newhope_sharedb(shared_key + 32, send + 32, received + 32, rng, Newhope_Mode::BoringSSL); } void CECPQ1_finish(uint8_t shared_key[CECPQ1_SHARED_KEY_BYTES], const CECPQ1_key& offer_key, const uint8_t received[CECPQ1_ACCEPT_BYTES]) { curve25519_donna(shared_key, offer_key.m_x25519.data(), received); newhope_shareda(shared_key + 32, &offer_key.m_newhope, received + 32, Newhope_Mode::BoringSSL); } } /* * Certificate Store * (C) 1999-2019 Jack Lloyd * (C) 2019 Patrick Schmidt * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace { std::vector> decode_all_certificates(DataSource& source) { std::vector> pems; while(!source.end_of_data()) { std::string label; std::vector cert; try { cert = unlock(PEM_Code::decode(source, label)); if(label == "CERTIFICATE" || label == "X509 CERTIFICATE" || label == "TRUSTED CERTIFICATE") { pems.push_back(cert); } } catch(const Decoding_Error&) {} } return pems; } } Flatfile_Certificate_Store::Flatfile_Certificate_Store(const std::string& file, bool ignore_non_ca) { if(file.empty()) { throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store invalid file path"); } DataSource_Stream file_stream(file); for(const std::vector& der : decode_all_certificates(file_stream)) { std::shared_ptr cert = std::make_shared(der.data(), der.size()); /* * Various weird or misconfigured system roots include intermediate certificates, * or even stranger certificates which are not valid for cert issuance at all. * Previously this code would error on such cases as an obvious misconfiguration, * but we cannot fix the trust store. So instead just ignore any such certificate. */ if(cert->is_self_signed() && cert->is_CA_cert()) { m_all_subjects.push_back(cert->subject_dn()); m_dn_to_cert[cert->subject_dn()].push_back(cert); m_pubkey_sha1_to_cert.emplace(cert->subject_public_key_bitstring_sha1(), cert); m_subject_dn_sha256_to_cert.emplace(cert->raw_subject_dn_sha256(), cert); } else if(!ignore_non_ca) { throw Invalid_Argument("Flatfile_Certificate_Store received non CA cert " + cert->subject_dn().to_string()); } } if(m_all_subjects.empty()) { throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store cert file is empty"); } } std::vector Flatfile_Certificate_Store::all_subjects() const { return m_all_subjects; } std::vector> Flatfile_Certificate_Store::find_all_certs( const X509_DN& subject_dn, const std::vector& key_id) const { std::vector> found_certs; try { const auto certs = m_dn_to_cert.at(subject_dn); for(auto cert : certs) { if(key_id.empty() || key_id == cert->subject_key_id()) { found_certs.push_back(cert); } } } catch(const std::out_of_range&) { return {}; } return found_certs; } std::shared_ptr Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector& key_hash) const { if(key_hash.size() != 20) { throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_pubkey_sha1 invalid hash"); } auto found_cert = m_pubkey_sha1_to_cert.find(key_hash); if(found_cert != m_pubkey_sha1_to_cert.end()) { return found_cert->second; } return nullptr; } std::shared_ptr Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const { if(subject_hash.size() != 32) { throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256 invalid hash"); } auto found_cert = m_subject_dn_sha256_to_cert.find(subject_hash); if(found_cert != m_subject_dn_sha256_to_cert.end()) { return found_cert->second; } return nullptr; } std::shared_ptr Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const { BOTAN_UNUSED(subject); return {}; } } /* * Certificate Store in SQL * (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Certificate_Store_In_SQL::Certificate_Store_In_SQL(std::shared_ptr db, const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix) : m_rng(rng), m_database(db), m_prefix(table_prefix), m_password(passwd) { m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "certificates ( \ fingerprint BLOB PRIMARY KEY, \ subject_dn BLOB, \ key_id BLOB, \ priv_fingerprint BLOB, \ certificate BLOB UNIQUE NOT NULL\ )"); m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "keys (\ fingerprint BLOB PRIMARY KEY, \ key BLOB UNIQUE NOT NULL \ )"); m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "revoked (\ fingerprint BLOB PRIMARY KEY, \ reason BLOB NOT NULL, \ time BLOB NOT NULL \ )"); } // Certificate handling std::shared_ptr Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const { std::shared_ptr stmt; const std::vector dn_encoding = subject_dn.BER_encode(); if(key_id.empty()) { stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1 LIMIT 1"); stmt->bind(1, dn_encoding); } else { stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE\ subject_dn == ?1 AND (key_id == NULL OR key_id == ?2) LIMIT 1"); stmt->bind(1, dn_encoding); stmt->bind(2,key_id); } while(stmt->step()) { auto blob = stmt->get_blob(0); return std::make_shared(std::vector(blob.first, blob.first + blob.second)); } return std::shared_ptr(); } std::vector> Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn, const std::vector& key_id) const { std::vector> certs; std::shared_ptr stmt; const std::vector dn_encoding = subject_dn.BER_encode(); if(key_id.empty()) { stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1"); stmt->bind(1, dn_encoding); } else { stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE\ subject_dn == ?1 AND (key_id == NULL OR key_id == ?2)"); stmt->bind(1, dn_encoding); stmt->bind(2, key_id); } std::shared_ptr cert; while(stmt->step()) { auto blob = stmt->get_blob(0); certs.push_back(std::make_shared( std::vector(blob.first,blob.first + blob.second))); } return certs; } std::shared_ptr Certificate_Store_In_SQL::find_cert_by_pubkey_sha1(const std::vector& /*key_hash*/) const { throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_pubkey_sha1"); } std::shared_ptr Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256(const std::vector& /*subject_hash*/) const { throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256"); } std::shared_ptr Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const { auto all_crls = generate_crls(); for(auto crl: all_crls) { if(!crl.get_revoked().empty() && crl.issuer_dn() == subject.issuer_dn()) return std::shared_ptr(new X509_CRL(crl)); } return std::shared_ptr(); } std::vector Certificate_Store_In_SQL::all_subjects() const { std::vector ret; auto stmt = m_database->new_statement("SELECT subject_dn FROM " + m_prefix + "certificates"); while(stmt->step()) { auto blob = stmt->get_blob(0); BER_Decoder dec(blob.first,blob.second); X509_DN dn; dn.decode_from(dec); ret.push_back(dn); } return ret; } bool Certificate_Store_In_SQL::insert_cert(const X509_Certificate& cert) { const std::vector dn_encoding = cert.subject_dn().BER_encode(); const std::vector cert_encoding = cert.BER_encode(); auto stmt = m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix + "certificates (\ fingerprint, \ subject_dn, \ key_id, \ priv_fingerprint, \ certificate \ ) VALUES ( ?1, ?2, ?3, ?4, ?5 )"); stmt->bind(1,cert.fingerprint("SHA-256")); stmt->bind(2,dn_encoding); stmt->bind(3,cert.subject_key_id()); stmt->bind(4,std::vector()); stmt->bind(5,cert_encoding); stmt->spin(); return true; } bool Certificate_Store_In_SQL::remove_cert(const X509_Certificate& cert) { if(!find_cert(cert.subject_dn(),cert.subject_key_id())) return false; auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "certificates WHERE fingerprint == ?1"); stmt->bind(1,cert.fingerprint("SHA-256")); stmt->spin(); return true; } // Private key handling std::shared_ptr Certificate_Store_In_SQL::find_key(const X509_Certificate& cert) const { auto stmt = m_database->new_statement("SELECT key FROM " + m_prefix + "keys " "JOIN " + m_prefix + "certificates ON " + m_prefix + "keys.fingerprint == " + m_prefix + "certificates.priv_fingerprint " "WHERE " + m_prefix + "certificates.fingerprint == ?1"); stmt->bind(1,cert.fingerprint("SHA-256")); std::shared_ptr key; while(stmt->step()) { auto blob = stmt->get_blob(0); DataSource_Memory src(blob.first,blob.second); key.reset(PKCS8::load_key(src, m_rng, m_password)); } return key; } std::vector> Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const { auto fpr = key.fingerprint_private("SHA-256"); auto stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE priv_fingerprint == ?1"); stmt->bind(1,fpr); std::vector> certs; while(stmt->step()) { auto blob = stmt->get_blob(0); certs.push_back(std::make_shared( std::vector(blob.first,blob.first + blob.second))); } return certs; } bool Certificate_Store_In_SQL::insert_key(const X509_Certificate& cert, const Private_Key& key) { insert_cert(cert); if(find_key(cert)) return false; auto pkcs8 = PKCS8::BER_encode(key, m_rng, m_password); auto fpr = key.fingerprint_private("SHA-256"); auto stmt1 = m_database->new_statement( "INSERT OR REPLACE INTO " + m_prefix + "keys ( fingerprint, key ) VALUES ( ?1, ?2 )"); stmt1->bind(1,fpr); stmt1->bind(2,pkcs8.data(),pkcs8.size()); stmt1->spin(); auto stmt2 = m_database->new_statement( "UPDATE " + m_prefix + "certificates SET priv_fingerprint = ?1 WHERE fingerprint == ?2"); stmt2->bind(1,fpr); stmt2->bind(2,cert.fingerprint("SHA-256")); stmt2->spin(); return true; } void Certificate_Store_In_SQL::remove_key(const Private_Key& key) { auto fpr = key.fingerprint_private("SHA-256"); auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "keys WHERE fingerprint == ?1"); stmt->bind(1,fpr); stmt->spin(); } // Revocation void Certificate_Store_In_SQL::revoke_cert(const X509_Certificate& cert, CRL_Code code, const X509_Time& time) { insert_cert(cert); auto stmt1 = m_database->new_statement( "INSERT OR REPLACE INTO " + m_prefix + "revoked ( fingerprint, reason, time ) VALUES ( ?1, ?2, ?3 )"); stmt1->bind(1,cert.fingerprint("SHA-256")); stmt1->bind(2,code); if(time.time_is_set()) { stmt1->bind(3, time.BER_encode()); } else { stmt1->bind(3, static_cast(-1)); } stmt1->spin(); } void Certificate_Store_In_SQL::affirm_cert(const X509_Certificate& cert) { auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "revoked WHERE fingerprint == ?1"); stmt->bind(1,cert.fingerprint("SHA-256")); stmt->spin(); } std::vector Certificate_Store_In_SQL::generate_crls() const { auto stmt = m_database->new_statement( "SELECT certificate,reason,time FROM " + m_prefix + "revoked " "JOIN " + m_prefix + "certificates ON " + m_prefix + "certificates.fingerprint == " + m_prefix + "revoked.fingerprint"); std::map> crls; while(stmt->step()) { auto blob = stmt->get_blob(0); auto cert = X509_Certificate( std::vector(blob.first,blob.first + blob.second)); auto code = static_cast(stmt->get_size_t(1)); auto ent = CRL_Entry(cert,code); auto i = crls.find(cert.issuer_dn()); if(i == crls.end()) { crls.insert(std::make_pair(cert.issuer_dn(),std::vector({ent}))); } else { i->second.push_back(ent); } } std::vector ret; X509_Time t(std::chrono::system_clock::now()); for(auto p: crls) { ret.push_back(X509_CRL(p.first,t,t,p.second)); } return ret; } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_CERTSTOR_MACOS) #elif defined(BOTAN_HAS_CERTSTOR_WINDOWS) #elif defined(BOTAN_HAS_CERTSTOR_FLATFILE) && defined(BOTAN_SYSTEM_CERT_BUNDLE) #endif namespace Botan { System_Certificate_Store::System_Certificate_Store() { #if defined(BOTAN_HAS_CERTSTOR_MACOS) m_system_store = std::make_shared(); #elif defined(BOTAN_HAS_CERTSTOR_WINDOWS) m_system_store = std::make_shared(); #elif defined(BOTAN_HAS_CERTSTOR_FLATFILE) && defined(BOTAN_SYSTEM_CERT_BUNDLE) m_system_store = std::make_shared(BOTAN_SYSTEM_CERT_BUNDLE, true); #else throw Not_Implemented("No system certificate store available in this build"); #endif } std::shared_ptr System_Certificate_Store::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const { return m_system_store->find_cert(subject_dn, key_id); } std::vector> System_Certificate_Store::find_all_certs(const X509_DN& subject_dn, const std::vector& key_id) const { return m_system_store->find_all_certs(subject_dn, key_id); } std::shared_ptr System_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector& key_hash) const { return m_system_store->find_cert_by_pubkey_sha1(key_hash); } std::shared_ptr System_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const { return m_system_store->find_cert_by_raw_subject_dn_sha256(subject_hash); } std::shared_ptr System_Certificate_Store::find_crl_for(const X509_Certificate& subject) const { return m_system_store->find_crl_for(subject); } std::vector System_Certificate_Store::all_subjects() const { return m_system_store->all_subjects(); } } /* * Certificate Store * (C) 1999-2019 Jack Lloyd * (C) 2018-2019 Patrik Fiedler, Tim Oesterreich * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #define NOMINMAX 1 #define _WINSOCKAPI_ // stop windows.h including winsock.h #include #include #define WINCRYPT_UNUSED_PARAM 0 // for avoiding warnings when passing NULL to unused params in win32 api that accept integer types namespace Botan { namespace { using Cert_Pointer = std::shared_ptr; using Cert_Vector = std::vector; const std::array cert_store_names{"Root", "CA"}; /** * Abstract RAII wrapper for PCCERT_CONTEXT and HCERTSTORE * The Windows API partly takes care of those pointers destructions itself. * Especially, iteratively calling `CertFindCertificateInStore` with the previous PCCERT_CONTEXT * will free the context and return a new one. In this case, this guard takes care of freeing the context * in case of an exception and at the end of the iterative process. */ template class Handle_Guard { public: Handle_Guard(T context) : m_context(context) { } Handle_Guard(const Handle_Guard& rhs) = delete; Handle_Guard(Handle_Guard&& rhs) : m_context(std::move(rhs.m_context)) { rhs.m_context = nullptr; } ~Handle_Guard() { close(); } operator bool() const { return m_context != nullptr; } bool assign(T context) { m_context = context; return m_context != nullptr; } T& get() { return m_context; } const T& get() const { return m_context; } T operator->() { return m_context; } private: template typename std::enable_if::value>::type close() { if(m_context) { CertFreeCertificateContext(m_context); } } template typename std::enable_if::value>::type close() { if(m_context) { // second parameter is a flag that tells the store how to deallocate memory // using the default "0", this function works like decreasing the reference counter // in a shared_ptr CertCloseStore(m_context, 0); } } T m_context; }; HCERTSTORE open_cert_store(const char* cert_store_name) { auto store = CertOpenSystemStoreA(WINCRYPT_UNUSED_PARAM, cert_store_name); if(!store) { throw Botan::Internal_Error( "failed to open windows certificate store '" + std::string(cert_store_name) + "' (Error Code: " + std::to_string(::GetLastError()) + ")"); } return store; } Cert_Vector search_cert_stores(const _CRYPTOAPI_BLOB& blob, const DWORD& find_type, std::function filter, bool return_on_first_found) { Cert_Vector certs; for(const auto store_name : cert_store_names) { Handle_Guard windows_cert_store = open_cert_store(store_name); Handle_Guard cert_context = nullptr; while(cert_context.assign(CertFindCertificateInStore( windows_cert_store.get(), PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, WINCRYPT_UNUSED_PARAM, find_type, &blob, cert_context.get()))) { auto cert = std::make_shared(cert_context->pbCertEncoded, cert_context->cbCertEncoded); if(filter(certs, cert)) { if(return_on_first_found) { return {cert}; } certs.push_back(cert); } } } return certs; } bool already_contains_certificate(const Cert_Vector& certs, Cert_Pointer cert) { return std::any_of(certs.begin(), certs.end(), [&](std::shared_ptr c) { return *c == *cert; }); } Cert_Vector find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn, const std::vector& key_id, bool return_on_first_found) { _CRYPTOAPI_BLOB blob; DWORD find_type; std::vector dn_data; // if key_id is available, prefer searching that, as it should be "more unique" than the subject DN if(key_id.empty()) { find_type = CERT_FIND_SUBJECT_NAME; DER_Encoder encoder(dn_data); subject_dn.encode_into(encoder); blob.cbData = static_cast(dn_data.size()); blob.pbData = reinterpret_cast(dn_data.data()); } else { find_type = CERT_FIND_KEY_IDENTIFIER; blob.cbData = static_cast(key_id.size()); blob.pbData = const_cast(key_id.data()); } auto filter = [&](const Cert_Vector& certs, Cert_Pointer cert) { return !already_contains_certificate(certs, cert) && (key_id.empty() || cert->subject_dn() == subject_dn); }; return search_cert_stores(blob, find_type, filter, return_on_first_found); } } // namespace Certificate_Store_Windows::Certificate_Store_Windows() {} std::vector Certificate_Store_Windows::all_subjects() const { std::vector subject_dns; for(const auto store_name : cert_store_names) { Handle_Guard windows_cert_store = open_cert_store(store_name); Handle_Guard cert_context = nullptr; // Handle_Guard::assign exchanges the underlying pointer. No RAII is needed here, because the Windows API takes care of // freeing the previous context. while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get()))) { X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded); subject_dns.push_back(cert.subject_dn()); } } return subject_dns; } Cert_Pointer Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn, const std::vector& key_id) const { const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id, true); return certs.empty() ? nullptr : certs.front(); } Cert_Vector Certificate_Store_Windows::find_all_certs( const X509_DN& subject_dn, const std::vector& key_id) const { return find_cert_by_dn_and_key_id(subject_dn, key_id, false); } Cert_Pointer Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector& key_hash) const { if(key_hash.size() != 20) { throw Invalid_Argument("Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash"); } CRYPT_HASH_BLOB blob; blob.cbData = static_cast(key_hash.size()); blob.pbData = const_cast(key_hash.data()); auto filter = [](const Cert_Vector&, Cert_Pointer) { return true; }; const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true); return certs.empty() ? nullptr : certs.front(); } Cert_Pointer Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256( const std::vector& subject_hash) const { BOTAN_UNUSED(subject_hash); throw Not_Implemented("Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256"); } std::shared_ptr Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const { // TODO: this could be implemented by using the CertFindCRLInStore function BOTAN_UNUSED(subject); return {}; } } /* * CFB Mode * (C) 1999-2007,2013,2017 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { CFB_Mode::CFB_Mode(BlockCipher* cipher, size_t feedback_bits) : m_cipher(cipher), m_block_size(m_cipher->block_size()), m_feedback_bytes(feedback_bits ? feedback_bits / 8 : m_block_size) { if(feedback_bits % 8 || feedback() > cipher->block_size()) throw Invalid_Argument(name() + ": feedback bits " + std::to_string(feedback_bits) + " not supported"); } void CFB_Mode::clear() { m_cipher->clear(); m_keystream.clear(); reset(); } void CFB_Mode::reset() { m_state.clear(); zeroise(m_keystream); } std::string CFB_Mode::name() const { if(feedback() == cipher().block_size()) return cipher().name() + "/CFB"; else return cipher().name() + "/CFB(" + std::to_string(feedback()*8) + ")"; } size_t CFB_Mode::output_length(size_t input_length) const { return input_length; } size_t CFB_Mode::update_granularity() const { return feedback(); } size_t CFB_Mode::minimum_final_size() const { return 0; } Key_Length_Specification CFB_Mode::key_spec() const { return cipher().key_spec(); } size_t CFB_Mode::default_nonce_length() const { return block_size(); } bool CFB_Mode::valid_nonce_length(size_t n) const { return (n == 0 || n == block_size()); } void CFB_Mode::key_schedule(const uint8_t key[], size_t length) { m_cipher->set_key(key, length); m_keystream.resize(m_cipher->block_size()); } void CFB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); verify_key_set(!m_keystream.empty()); if(nonce_len == 0) { if(m_state.empty()) { throw Invalid_State("CFB requires a non-empty initial nonce"); } // No reason to encrypt state->keystream_buf, because no change } else { m_state.assign(nonce, nonce + nonce_len); cipher().encrypt(m_state, m_keystream); m_keystream_pos = 0; } } void CFB_Mode::shift_register() { const size_t shift = feedback(); const size_t carryover = block_size() - shift; if(carryover > 0) { copy_mem(m_state.data(), &m_state[shift], carryover); } copy_mem(&m_state[carryover], m_keystream.data(), shift); cipher().encrypt(m_state, m_keystream); m_keystream_pos = 0; } size_t CFB_Encryption::process(uint8_t buf[], size_t sz) { verify_key_set(!m_keystream.empty()); BOTAN_STATE_CHECK(m_state.empty() == false); const size_t shift = feedback(); size_t left = sz; if(m_keystream_pos != 0) { const size_t take = std::min(left, shift - m_keystream_pos); xor_buf(m_keystream.data() + m_keystream_pos, buf, take); copy_mem(buf, m_keystream.data() + m_keystream_pos, take); m_keystream_pos += take; left -= take; buf += take; if(m_keystream_pos == shift) { shift_register(); } } while(left >= shift) { xor_buf(m_keystream.data(), buf, shift); copy_mem(buf, m_keystream.data(), shift); left -= shift; buf += shift; shift_register(); } if(left > 0) { xor_buf(m_keystream.data(), buf, left); copy_mem(buf, m_keystream.data(), left); m_keystream_pos += left; } return sz; } void CFB_Encryption::finish(secure_vector& buffer, size_t offset) { update(buffer, offset); } namespace { inline void xor_copy(uint8_t buf[], uint8_t key_buf[], size_t len) { for(size_t i = 0; i != len; ++i) { uint8_t k = key_buf[i]; key_buf[i] = buf[i]; buf[i] ^= k; } } } size_t CFB_Decryption::process(uint8_t buf[], size_t sz) { verify_key_set(!m_keystream.empty()); BOTAN_STATE_CHECK(m_state.empty() == false); const size_t shift = feedback(); size_t left = sz; if(m_keystream_pos != 0) { const size_t take = std::min(left, shift - m_keystream_pos); xor_copy(buf, m_keystream.data() + m_keystream_pos, take); m_keystream_pos += take; left -= take; buf += take; if(m_keystream_pos == shift) { shift_register(); } } while(left >= shift) { xor_copy(buf, m_keystream.data(), shift); left -= shift; buf += shift; shift_register(); } if(left > 0) { xor_copy(buf, m_keystream.data(), left); m_keystream_pos += left; } return sz; } void CFB_Decryption::finish(secure_vector& buffer, size_t offset) { update(buffer, offset); } } /* * ChaCha * (C) 2014,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { #define CHACHA_QUARTER_ROUND(a, b, c, d) \ do { \ a += b; d ^= a; d = rotl<16>(d); \ c += d; b ^= c; b = rotl<12>(b); \ a += b; d ^= a; d = rotl<8>(d); \ c += d; b ^= c; b = rotl<7>(b); \ } while(0) /* * Generate HChaCha cipher stream (for XChaCha IV setup) */ void hchacha(uint32_t output[8], const uint32_t input[16], size_t rounds) { BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; for(size_t i = 0; i != rounds / 2; ++i) { CHACHA_QUARTER_ROUND(x00, x04, x08, x12); CHACHA_QUARTER_ROUND(x01, x05, x09, x13); CHACHA_QUARTER_ROUND(x02, x06, x10, x14); CHACHA_QUARTER_ROUND(x03, x07, x11, x15); CHACHA_QUARTER_ROUND(x00, x05, x10, x15); CHACHA_QUARTER_ROUND(x01, x06, x11, x12); CHACHA_QUARTER_ROUND(x02, x07, x08, x13); CHACHA_QUARTER_ROUND(x03, x04, x09, x14); } output[0] = x00; output[1] = x01; output[2] = x02; output[3] = x03; output[4] = x12; output[5] = x13; output[6] = x14; output[7] = x15; } } ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) { BOTAN_ARG_CHECK(m_rounds == 8 || m_rounds == 12 || m_rounds == 20, "ChaCha only supports 8, 12 or 20 rounds"); } std::string ChaCha::provider() const { #if defined(BOTAN_HAS_CHACHA_AVX2) if(CPUID::has_avx2()) { return "avx2"; } #endif #if defined(BOTAN_HAS_CHACHA_SIMD32) if(CPUID::has_simd_32()) { return "simd32"; } #endif return "base"; } //static void ChaCha::chacha_x8(uint8_t output[64*8], uint32_t input[16], size_t rounds) { BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); #if defined(BOTAN_HAS_CHACHA_AVX2) if(CPUID::has_avx2()) { return ChaCha::chacha_avx2_x8(output, input, rounds); } #endif #if defined(BOTAN_HAS_CHACHA_SIMD32) if(CPUID::has_simd_32()) { ChaCha::chacha_simd32_x4(output, input, rounds); ChaCha::chacha_simd32_x4(output + 4*64, input, rounds); return; } #endif // TODO interleave rounds for(size_t i = 0; i != 8; ++i) { uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; for(size_t r = 0; r != rounds / 2; ++r) { CHACHA_QUARTER_ROUND(x00, x04, x08, x12); CHACHA_QUARTER_ROUND(x01, x05, x09, x13); CHACHA_QUARTER_ROUND(x02, x06, x10, x14); CHACHA_QUARTER_ROUND(x03, x07, x11, x15); CHACHA_QUARTER_ROUND(x00, x05, x10, x15); CHACHA_QUARTER_ROUND(x01, x06, x11, x12); CHACHA_QUARTER_ROUND(x02, x07, x08, x13); CHACHA_QUARTER_ROUND(x03, x04, x09, x14); } x00 += input[0]; x01 += input[1]; x02 += input[2]; x03 += input[3]; x04 += input[4]; x05 += input[5]; x06 += input[6]; x07 += input[7]; x08 += input[8]; x09 += input[9]; x10 += input[10]; x11 += input[11]; x12 += input[12]; x13 += input[13]; x14 += input[14]; x15 += input[15]; store_le(x00, output + 64 * i + 4 * 0); store_le(x01, output + 64 * i + 4 * 1); store_le(x02, output + 64 * i + 4 * 2); store_le(x03, output + 64 * i + 4 * 3); store_le(x04, output + 64 * i + 4 * 4); store_le(x05, output + 64 * i + 4 * 5); store_le(x06, output + 64 * i + 4 * 6); store_le(x07, output + 64 * i + 4 * 7); store_le(x08, output + 64 * i + 4 * 8); store_le(x09, output + 64 * i + 4 * 9); store_le(x10, output + 64 * i + 4 * 10); store_le(x11, output + 64 * i + 4 * 11); store_le(x12, output + 64 * i + 4 * 12); store_le(x13, output + 64 * i + 4 * 13); store_le(x14, output + 64 * i + 4 * 14); store_le(x15, output + 64 * i + 4 * 15); input[12]++; input[13] += (input[12] == 0); } } #undef CHACHA_QUARTER_ROUND /* * Combine cipher stream with message */ void ChaCha::cipher(const uint8_t in[], uint8_t out[], size_t length) { verify_key_set(m_state.empty() == false); while(length >= m_buffer.size() - m_position) { const size_t available = m_buffer.size() - m_position; xor_buf(out, in, &m_buffer[m_position], available); chacha_x8(m_buffer.data(), m_state.data(), m_rounds); length -= available; in += available; out += available; m_position = 0; } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; } void ChaCha::write_keystream(uint8_t out[], size_t length) { verify_key_set(m_state.empty() == false); while(length >= m_buffer.size() - m_position) { const size_t available = m_buffer.size() - m_position; copy_mem(out, &m_buffer[m_position], available); chacha_x8(m_buffer.data(), m_state.data(), m_rounds); length -= available; out += available; m_position = 0; } copy_mem(out, &m_buffer[m_position], length); m_position += length; } void ChaCha::initialize_state() { static const uint32_t TAU[] = { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; static const uint32_t SIGMA[] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; m_state[4] = m_key[0]; m_state[5] = m_key[1]; m_state[6] = m_key[2]; m_state[7] = m_key[3]; if(m_key.size() == 4) { m_state[0] = TAU[0]; m_state[1] = TAU[1]; m_state[2] = TAU[2]; m_state[3] = TAU[3]; m_state[8] = m_key[0]; m_state[9] = m_key[1]; m_state[10] = m_key[2]; m_state[11] = m_key[3]; } else { m_state[0] = SIGMA[0]; m_state[1] = SIGMA[1]; m_state[2] = SIGMA[2]; m_state[3] = SIGMA[3]; m_state[8] = m_key[4]; m_state[9] = m_key[5]; m_state[10] = m_key[6]; m_state[11] = m_key[7]; } m_state[12] = 0; m_state[13] = 0; m_state[14] = 0; m_state[15] = 0; m_position = 0; } /* * ChaCha Key Schedule */ void ChaCha::key_schedule(const uint8_t key[], size_t length) { m_key.resize(length / 4); load_le(m_key.data(), key, m_key.size()); m_state.resize(16); const size_t chacha_parallelism = 8; // chacha_x8 const size_t chacha_block = 64; m_buffer.resize(chacha_parallelism * chacha_block); set_iv(nullptr, 0); } size_t ChaCha::default_iv_length() const { return 24; } Key_Length_Specification ChaCha::key_spec() const { return Key_Length_Specification(16, 32, 16); } StreamCipher* ChaCha::clone() const { return new ChaCha(m_rounds); } bool ChaCha::valid_iv_length(size_t iv_len) const { return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24); } void ChaCha::set_iv(const uint8_t iv[], size_t length) { verify_key_set(m_state.empty() == false); if(!valid_iv_length(length)) throw Invalid_IV_Length(name(), length); initialize_state(); if(length == 0) { // Treat zero length IV same as an all-zero IV m_state[14] = 0; m_state[15] = 0; } else if(length == 8) { m_state[14] = load_le(iv, 0); m_state[15] = load_le(iv, 1); } else if(length == 12) { m_state[13] = load_le(iv, 0); m_state[14] = load_le(iv, 1); m_state[15] = load_le(iv, 2); } else if(length == 24) { m_state[12] = load_le(iv, 0); m_state[13] = load_le(iv, 1); m_state[14] = load_le(iv, 2); m_state[15] = load_le(iv, 3); secure_vector hc(8); hchacha(hc.data(), m_state.data(), m_rounds); m_state[ 4] = hc[0]; m_state[ 5] = hc[1]; m_state[ 6] = hc[2]; m_state[ 7] = hc[3]; m_state[ 8] = hc[4]; m_state[ 9] = hc[5]; m_state[10] = hc[6]; m_state[11] = hc[7]; m_state[12] = 0; m_state[13] = 0; m_state[14] = load_le(iv, 4); m_state[15] = load_le(iv, 5); } chacha_x8(m_buffer.data(), m_state.data(), m_rounds); m_position = 0; } void ChaCha::clear() { zap(m_key); zap(m_state); zap(m_buffer); m_position = 0; } std::string ChaCha::name() const { return "ChaCha(" + std::to_string(m_rounds) + ")"; } void ChaCha::seek(uint64_t offset) { verify_key_set(m_state.empty() == false); // Find the block offset const uint64_t counter = offset / 64; uint8_t out[8]; store_le(counter, out); m_state[12] = load_le(out, 0); m_state[13] += load_le(out, 1); chacha_x8(m_buffer.data(), m_state.data(), m_rounds); m_position = offset % 64; } } /* * ChaCha20Poly1305 AEAD * (C) 2014,2016,2018 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { ChaCha20Poly1305_Mode::ChaCha20Poly1305_Mode() : m_chacha(StreamCipher::create("ChaCha")), m_poly1305(MessageAuthenticationCode::create("Poly1305")) { if(!m_chacha || !m_poly1305) throw Algorithm_Not_Found("ChaCha20Poly1305"); } bool ChaCha20Poly1305_Mode::valid_nonce_length(size_t n) const { return (n == 8 || n == 12 || n == 24); } void ChaCha20Poly1305_Mode::clear() { m_chacha->clear(); m_poly1305->clear(); reset(); } void ChaCha20Poly1305_Mode::reset() { m_ad.clear(); m_ctext_len = 0; m_nonce_len = 0; } void ChaCha20Poly1305_Mode::key_schedule(const uint8_t key[], size_t length) { m_chacha->set_key(key, length); } void ChaCha20Poly1305_Mode::set_associated_data(const uint8_t ad[], size_t length) { if(m_ctext_len > 0 || m_nonce_len > 0) throw Invalid_State("Cannot set AD for ChaCha20Poly1305 while processing a message"); m_ad.assign(ad, ad + length); } void ChaCha20Poly1305_Mode::update_len(size_t len) { uint8_t len8[8] = { 0 }; store_le(static_cast(len), len8); m_poly1305->update(len8, 8); } void ChaCha20Poly1305_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); m_ctext_len = 0; m_nonce_len = nonce_len; m_chacha->set_iv(nonce, nonce_len); uint8_t first_block[64]; m_chacha->write_keystream(first_block, sizeof(first_block)); m_poly1305->set_key(first_block, 32); // Remainder of first block is discarded secure_scrub_memory(first_block, sizeof(first_block)); m_poly1305->update(m_ad); if(cfrg_version()) { if(m_ad.size() % 16) { const uint8_t zeros[16] = { 0 }; m_poly1305->update(zeros, 16 - m_ad.size() % 16); } } else { update_len(m_ad.size()); } } size_t ChaCha20Poly1305_Encryption::process(uint8_t buf[], size_t sz) { m_chacha->cipher1(buf, sz); m_poly1305->update(buf, sz); // poly1305 of ciphertext m_ctext_len += sz; return sz; } void ChaCha20Poly1305_Encryption::finish(secure_vector& buffer, size_t offset) { update(buffer, offset); if(cfrg_version()) { if(m_ctext_len % 16) { const uint8_t zeros[16] = { 0 }; m_poly1305->update(zeros, 16 - m_ctext_len % 16); } update_len(m_ad.size()); } update_len(m_ctext_len); buffer.resize(buffer.size() + tag_size()); m_poly1305->final(&buffer[buffer.size() - tag_size()]); m_ctext_len = 0; m_nonce_len = 0; } size_t ChaCha20Poly1305_Decryption::process(uint8_t buf[], size_t sz) { m_poly1305->update(buf, sz); // poly1305 of ciphertext m_chacha->cipher1(buf, sz); m_ctext_len += sz; return sz; } void ChaCha20Poly1305_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); const size_t remaining = sz - tag_size(); if(remaining) { m_poly1305->update(buf, remaining); // poly1305 of ciphertext m_chacha->cipher1(buf, remaining); m_ctext_len += remaining; } if(cfrg_version()) { if(m_ctext_len % 16) { const uint8_t zeros[16] = { 0 }; m_poly1305->update(zeros, 16 - m_ctext_len % 16); } update_len(m_ad.size()); } update_len(m_ctext_len); uint8_t mac[16]; m_poly1305->final(mac); const uint8_t* included_tag = &buf[remaining]; m_ctext_len = 0; m_nonce_len = 0; if(!constant_time_compare(mac, included_tag, tag_size())) throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed"); buffer.resize(offset + remaining); } } /* * ChaCha_RNG * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { ChaCha_RNG::ChaCha_RNG() : Stateful_RNG() { m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); clear(); } ChaCha_RNG::ChaCha_RNG(const secure_vector& seed) : Stateful_RNG() { m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); clear(); add_entropy(seed.data(), seed.size()); } ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng, size_t reseed_interval) : Stateful_RNG(underlying_rng, reseed_interval) { m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); clear(); } ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng, Entropy_Sources& entropy_sources, size_t reseed_interval) : Stateful_RNG(underlying_rng, entropy_sources, reseed_interval) { m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); clear(); } ChaCha_RNG::ChaCha_RNG(Entropy_Sources& entropy_sources, size_t reseed_interval) : Stateful_RNG(entropy_sources, reseed_interval) { m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); clear(); } void ChaCha_RNG::clear_state() { m_hmac->set_key(std::vector(m_hmac->output_length(), 0x00)); m_chacha->set_key(m_hmac->final()); } void ChaCha_RNG::generate_output(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) { if(input_len > 0) { update(input, input_len); } m_chacha->write_keystream(output, output_len); } void ChaCha_RNG::update(const uint8_t input[], size_t input_len) { m_hmac->update(input, input_len); m_chacha->set_key(m_hmac->final()); secure_vector mac_key(m_hmac->output_length()); m_chacha->write_keystream(mac_key.data(), mac_key.size()); m_hmac->set_key(mac_key); } size_t ChaCha_RNG::security_level() const { return 256; } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { //static void ChaCha::chacha_simd32_x4(uint8_t output[64*4], uint32_t state[16], size_t rounds) { BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); const SIMD_4x32 CTR0 = SIMD_4x32(0, 1, 2, 3); const uint32_t C = 0xFFFFFFFF - state[12]; const SIMD_4x32 CTR1 = SIMD_4x32(0, C < 1, C < 2, C < 3); SIMD_4x32 R00 = SIMD_4x32::splat(state[ 0]); SIMD_4x32 R01 = SIMD_4x32::splat(state[ 1]); SIMD_4x32 R02 = SIMD_4x32::splat(state[ 2]); SIMD_4x32 R03 = SIMD_4x32::splat(state[ 3]); SIMD_4x32 R04 = SIMD_4x32::splat(state[ 4]); SIMD_4x32 R05 = SIMD_4x32::splat(state[ 5]); SIMD_4x32 R06 = SIMD_4x32::splat(state[ 6]); SIMD_4x32 R07 = SIMD_4x32::splat(state[ 7]); SIMD_4x32 R08 = SIMD_4x32::splat(state[ 8]); SIMD_4x32 R09 = SIMD_4x32::splat(state[ 9]); SIMD_4x32 R10 = SIMD_4x32::splat(state[10]); SIMD_4x32 R11 = SIMD_4x32::splat(state[11]); SIMD_4x32 R12 = SIMD_4x32::splat(state[12]) + CTR0; SIMD_4x32 R13 = SIMD_4x32::splat(state[13]) + CTR1; SIMD_4x32 R14 = SIMD_4x32::splat(state[14]); SIMD_4x32 R15 = SIMD_4x32::splat(state[15]); for(size_t r = 0; r != rounds / 2; ++r) { R00 += R04; R01 += R05; R02 += R06; R03 += R07; R12 ^= R00; R13 ^= R01; R14 ^= R02; R15 ^= R03; R12 = R12.rotl<16>(); R13 = R13.rotl<16>(); R14 = R14.rotl<16>(); R15 = R15.rotl<16>(); R08 += R12; R09 += R13; R10 += R14; R11 += R15; R04 ^= R08; R05 ^= R09; R06 ^= R10; R07 ^= R11; R04 = R04.rotl<12>(); R05 = R05.rotl<12>(); R06 = R06.rotl<12>(); R07 = R07.rotl<12>(); R00 += R04; R01 += R05; R02 += R06; R03 += R07; R12 ^= R00; R13 ^= R01; R14 ^= R02; R15 ^= R03; R12 = R12.rotl<8>(); R13 = R13.rotl<8>(); R14 = R14.rotl<8>(); R15 = R15.rotl<8>(); R08 += R12; R09 += R13; R10 += R14; R11 += R15; R04 ^= R08; R05 ^= R09; R06 ^= R10; R07 ^= R11; R04 = R04.rotl<7>(); R05 = R05.rotl<7>(); R06 = R06.rotl<7>(); R07 = R07.rotl<7>(); R00 += R05; R01 += R06; R02 += R07; R03 += R04; R15 ^= R00; R12 ^= R01; R13 ^= R02; R14 ^= R03; R15 = R15.rotl<16>(); R12 = R12.rotl<16>(); R13 = R13.rotl<16>(); R14 = R14.rotl<16>(); R10 += R15; R11 += R12; R08 += R13; R09 += R14; R05 ^= R10; R06 ^= R11; R07 ^= R08; R04 ^= R09; R05 = R05.rotl<12>(); R06 = R06.rotl<12>(); R07 = R07.rotl<12>(); R04 = R04.rotl<12>(); R00 += R05; R01 += R06; R02 += R07; R03 += R04; R15 ^= R00; R12 ^= R01; R13 ^= R02; R14 ^= R03; R15 = R15.rotl<8>(); R12 = R12.rotl<8>(); R13 = R13.rotl<8>(); R14 = R14.rotl<8>(); R10 += R15; R11 += R12; R08 += R13; R09 += R14; R05 ^= R10; R06 ^= R11; R07 ^= R08; R04 ^= R09; R05 = R05.rotl<7>(); R06 = R06.rotl<7>(); R07 = R07.rotl<7>(); R04 = R04.rotl<7>(); } R00 += SIMD_4x32::splat(state[0]); R01 += SIMD_4x32::splat(state[1]); R02 += SIMD_4x32::splat(state[2]); R03 += SIMD_4x32::splat(state[3]); R04 += SIMD_4x32::splat(state[4]); R05 += SIMD_4x32::splat(state[5]); R06 += SIMD_4x32::splat(state[6]); R07 += SIMD_4x32::splat(state[7]); R08 += SIMD_4x32::splat(state[8]); R09 += SIMD_4x32::splat(state[9]); R10 += SIMD_4x32::splat(state[10]); R11 += SIMD_4x32::splat(state[11]); R12 += SIMD_4x32::splat(state[12]) + CTR0; R13 += SIMD_4x32::splat(state[13]) + CTR1; R14 += SIMD_4x32::splat(state[14]); R15 += SIMD_4x32::splat(state[15]); SIMD_4x32::transpose(R00, R01, R02, R03); SIMD_4x32::transpose(R04, R05, R06, R07); SIMD_4x32::transpose(R08, R09, R10, R11); SIMD_4x32::transpose(R12, R13, R14, R15); R00.store_le(output + 0*16); R04.store_le(output + 1*16); R08.store_le(output + 2*16); R12.store_le(output + 3*16); R01.store_le(output + 4*16); R05.store_le(output + 5*16); R09.store_le(output + 6*16); R13.store_le(output + 7*16); R02.store_le(output + 8*16); R06.store_le(output + 9*16); R10.store_le(output + 10*16); R14.store_le(output + 11*16); R03.store_le(output + 12*16); R07.store_le(output + 13*16); R11.store_le(output + 14*16); R15.store_le(output + 15*16); state[12] += 4; if(state[12] < 4) state[13]++; } } /* * CMAC * (C) 1999-2007,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Perform CMAC's multiplication in GF(2^n) */ secure_vector CMAC::poly_double(const secure_vector& in) { secure_vector out(in.size()); poly_double_n(out.data(), in.data(), out.size()); return out; } /* * Update an CMAC Calculation */ void CMAC::add_data(const uint8_t input[], size_t length) { const size_t bs = output_length(); buffer_insert(m_buffer, m_position, input, length); if(m_position + length > bs) { xor_buf(m_state, m_buffer, bs); m_cipher->encrypt(m_state); input += (bs - m_position); length -= (bs - m_position); while(length > bs) { xor_buf(m_state, input, bs); m_cipher->encrypt(m_state); input += bs; length -= bs; } copy_mem(m_buffer.data(), input, length); m_position = 0; } m_position += length; } /* * Finalize an CMAC Calculation */ void CMAC::final_result(uint8_t mac[]) { xor_buf(m_state, m_buffer, m_position); if(m_position == output_length()) { xor_buf(m_state, m_B, output_length()); } else { m_state[m_position] ^= 0x80; xor_buf(m_state, m_P, output_length()); } m_cipher->encrypt(m_state); copy_mem(mac, m_state.data(), output_length()); zeroise(m_state); zeroise(m_buffer); m_position = 0; } /* * CMAC Key Schedule */ void CMAC::key_schedule(const uint8_t key[], size_t length) { clear(); m_cipher->set_key(key, length); m_cipher->encrypt(m_B); poly_double_n(m_B.data(), m_B.size()); poly_double_n(m_P.data(), m_B.data(), m_P.size()); } /* * Clear memory of sensitive data */ void CMAC::clear() { m_cipher->clear(); zeroise(m_state); zeroise(m_buffer); zeroise(m_B); zeroise(m_P); m_position = 0; } /* * Return the name of this type */ std::string CMAC::name() const { return "CMAC(" + m_cipher->name() + ")"; } /* * Return a clone of this object */ MessageAuthenticationCode* CMAC::clone() const { return new CMAC(m_cipher->clone()); } /* * CMAC Constructor */ CMAC::CMAC(BlockCipher* cipher) : m_cipher(cipher), m_block_size(m_cipher->block_size()) { if(poly_double_supported_size(m_block_size) == false) { throw Invalid_Argument("CMAC cannot use the " + std::to_string(m_block_size * 8) + " bit cipher " + m_cipher->name()); } m_state.resize(output_length()); m_buffer.resize(output_length()); m_B.resize(output_length()); m_P.resize(output_length()); m_position = 0; } } /* * Comb4P hash combiner * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void comb4p_round(secure_vector& out, const secure_vector& in, uint8_t round_no, HashFunction& h1, HashFunction& h2) { h1.update(round_no); h2.update(round_no); h1.update(in.data(), in.size()); h2.update(in.data(), in.size()); secure_vector h_buf = h1.final(); xor_buf(out.data(), h_buf.data(), std::min(out.size(), h_buf.size())); h_buf = h2.final(); xor_buf(out.data(), h_buf.data(), std::min(out.size(), h_buf.size())); } } Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) : m_hash1(h1), m_hash2(h2) { if(m_hash1->name() == m_hash2->name()) throw Invalid_Argument("Comb4P: Must use two distinct hashes"); if(m_hash1->output_length() != m_hash2->output_length()) throw Invalid_Argument("Comb4P: Incompatible hashes " + m_hash1->name() + " and " + m_hash2->name()); clear(); } size_t Comb4P::hash_block_size() const { if(m_hash1->hash_block_size() == m_hash2->hash_block_size()) return m_hash1->hash_block_size(); /* * Return LCM of the block sizes? This would probably be OK for * HMAC, which is the main thing relying on knowing the block size. */ return 0; } void Comb4P::clear() { m_hash1->clear(); m_hash2->clear(); // Prep for processing next message, if any m_hash1->update(0); m_hash2->update(0); } std::unique_ptr Comb4P::copy_state() const { std::unique_ptr copy(new Comb4P); copy->m_hash1 = m_hash1->copy_state(); copy->m_hash2 = m_hash2->copy_state(); // work around GCC 4.8 bug return std::unique_ptr(copy.release()); } void Comb4P::add_data(const uint8_t input[], size_t length) { m_hash1->update(input, length); m_hash2->update(input, length); } void Comb4P::final_result(uint8_t out[]) { secure_vector h1 = m_hash1->final(); secure_vector h2 = m_hash2->final(); // First round xor_buf(h1.data(), h2.data(), std::min(h1.size(), h2.size())); // Second round comb4p_round(h2, h1, 1, *m_hash1, *m_hash2); // Third round comb4p_round(h1, h2, 2, *m_hash1, *m_hash2); copy_mem(out , h1.data(), h1.size()); copy_mem(out + h1.size(), h2.data(), h2.size()); // Prep for processing next message, if any m_hash1->update(0); m_hash2->update(0); } } /* * Runtime CPU detection * (C) 2009,2010,2013,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { bool CPUID::has_simd_32() { #if defined(BOTAN_TARGET_SUPPORTS_SSE2) return CPUID::has_sse2(); #elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) return CPUID::has_altivec(); #elif defined(BOTAN_TARGET_SUPPORTS_NEON) return CPUID::has_neon(); #else return true; #endif } //static std::string CPUID::to_string() { std::vector flags; #define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0) #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) CPUID_PRINT(sse2); CPUID_PRINT(ssse3); CPUID_PRINT(sse41); CPUID_PRINT(sse42); CPUID_PRINT(avx2); CPUID_PRINT(avx512f); CPUID_PRINT(avx512dq); CPUID_PRINT(avx512bw); CPUID_PRINT(avx512_icelake); CPUID_PRINT(rdtsc); CPUID_PRINT(bmi1); CPUID_PRINT(bmi2); CPUID_PRINT(adx); CPUID_PRINT(aes_ni); CPUID_PRINT(clmul); CPUID_PRINT(rdrand); CPUID_PRINT(rdseed); CPUID_PRINT(intel_sha); CPUID_PRINT(avx512_aes); CPUID_PRINT(avx512_clmul); #endif #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) CPUID_PRINT(altivec); CPUID_PRINT(power_crypto); CPUID_PRINT(darn_rng); #endif #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) CPUID_PRINT(neon); CPUID_PRINT(arm_sve); CPUID_PRINT(arm_sha1); CPUID_PRINT(arm_sha2); CPUID_PRINT(arm_aes); CPUID_PRINT(arm_pmull); CPUID_PRINT(arm_sha2_512); CPUID_PRINT(arm_sha3); CPUID_PRINT(arm_sm3); CPUID_PRINT(arm_sm4); #endif #undef CPUID_PRINT return string_join(flags, ' '); } //static void CPUID::print(std::ostream& o) { o << "CPUID flags: " << CPUID::to_string() << "\n"; } //static void CPUID::initialize() { state() = CPUID_Data(); } CPUID::CPUID_Data::CPUID_Data() { m_cache_line_size = 0; m_processor_features = 0; #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) m_processor_features = detect_cpu_features(&m_cache_line_size); #endif m_processor_features |= CPUID::CPUID_INITIALIZED_BIT; if(m_cache_line_size == 0) m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; m_endian_status = runtime_check_endian(); } //static CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian() { // Check runtime endian const uint32_t endian32 = 0x01234567; const uint8_t* e8 = reinterpret_cast(&endian32); CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown; if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) { endian = CPUID::Endian_Status::Big; } else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) { endian = CPUID::Endian_Status::Little; } else { throw Internal_Error("Unexpected endian at runtime, neither big nor little"); } // If we were compiled with a known endian, verify it matches at runtime #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match"); #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match"); #endif return endian; } std::vector CPUID::bit_from_string(const std::string& tok) { #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) if(tok == "sse2" || tok == "simd") return {Botan::CPUID::CPUID_SSE2_BIT}; if(tok == "ssse3") return {Botan::CPUID::CPUID_SSSE3_BIT}; if(tok == "sse41") return {Botan::CPUID::CPUID_SSE41_BIT}; if(tok == "sse42") return {Botan::CPUID::CPUID_SSE42_BIT}; // aes_ni is the string printed on the console when running "botan cpuid" if(tok == "aesni" || tok == "aes_ni") return {Botan::CPUID::CPUID_AESNI_BIT}; if(tok == "clmul") return {Botan::CPUID::CPUID_CLMUL_BIT}; if(tok == "avx2") return {Botan::CPUID::CPUID_AVX2_BIT}; if(tok == "avx512f") return {Botan::CPUID::CPUID_AVX512F_BIT}; if(tok == "avx512_icelake") return {Botan::CPUID::CPUID_AVX512_ICL_BIT}; // there were two if statements testing "sha" and "intel_sha" separately; combined if(tok == "sha" || tok=="intel_sha") return {Botan::CPUID::CPUID_SHA_BIT}; if(tok == "rdtsc") return {Botan::CPUID::CPUID_RDTSC_BIT}; if(tok == "bmi1") return {Botan::CPUID::CPUID_BMI1_BIT}; if(tok == "bmi2") return {Botan::CPUID::CPUID_BMI2_BIT}; if(tok == "adx") return {Botan::CPUID::CPUID_ADX_BIT}; if(tok == "rdrand") return {Botan::CPUID::CPUID_RDRAND_BIT}; if(tok == "rdseed") return {Botan::CPUID::CPUID_RDSEED_BIT}; if(tok == "avx512_aes") return {Botan::CPUID::CPUID_AVX512_AES_BIT}; if(tok == "avx512_clmul") return {Botan::CPUID::CPUID_AVX512_CLMUL_BIT}; #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) if(tok == "altivec" || tok == "simd") return {Botan::CPUID::CPUID_ALTIVEC_BIT}; if(tok == "power_crypto") return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT}; if(tok == "darn_rng") return {Botan::CPUID::CPUID_DARN_BIT}; #elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) if(tok == "neon" || tok == "simd") return {Botan::CPUID::CPUID_ARM_NEON_BIT}; if(tok == "arm_sve") return {Botan::CPUID::CPUID_ARM_SVE_BIT}; if(tok == "armv8sha1" || tok == "arm_sha1") return {Botan::CPUID::CPUID_ARM_SHA1_BIT}; if(tok == "armv8sha2" || tok == "arm_sha2") return {Botan::CPUID::CPUID_ARM_SHA2_BIT}; if(tok == "armv8aes" || tok == "arm_aes") return {Botan::CPUID::CPUID_ARM_AES_BIT}; if(tok == "armv8pmull" || tok == "arm_pmull") return {Botan::CPUID::CPUID_ARM_PMULL_BIT}; if(tok == "armv8sha3" || tok == "arm_sha3") return {Botan::CPUID::CPUID_ARM_SHA3_BIT}; if(tok == "armv8sha2_512" || tok == "arm_sha2_512") return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT}; if(tok == "armv8sm3" || tok == "arm_sm3") return {Botan::CPUID::CPUID_ARM_SM3_BIT}; if(tok == "armv8sm4" || tok == "arm_sm4") return {Botan::CPUID::CPUID_ARM_SM4_BIT}; #else BOTAN_UNUSED(tok); #endif return {}; } } /* * Runtime CPU detection for ARM * (C) 2009,2010,2013,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) #if defined(BOTAN_TARGET_OS_IS_IOS) #include #include #else #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) #include #endif #endif #endif namespace Botan { #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) #if defined(BOTAN_TARGET_OS_IS_IOS) namespace { uint64_t flags_by_ios_machine_type(const std::string& machine) { /* * This relies on a map of known machine names to features. This * will quickly grow out of date as new products are introduced, but * is apparently the best we can do for iOS. */ struct version_info { std::string name; size_t min_version_neon; size_t min_version_armv8; }; static const version_info min_versions[] = { { "iPhone", 2, 6 }, { "iPad", 1, 4 }, { "iPod", 4, 7 }, { "AppleTV", 2, 5 }, }; if(machine.size() < 3) return 0; auto comma = machine.find(','); // Simulator, or something we don't know about if(comma == std::string::npos) return 0; std::string product = machine.substr(0, comma); size_t version = 0; size_t place = 1; while(product.size() > 1 && ::isdigit(product.back())) { const size_t digit = product.back() - '0'; version += digit * place; place *= 10; product.pop_back(); } if(version == 0) return 0; for(const version_info& info : min_versions) { if(info.name != product) continue; if(version >= info.min_version_armv8) { return CPUID::CPUID_ARM_AES_BIT | CPUID::CPUID_ARM_PMULL_BIT | CPUID::CPUID_ARM_SHA1_BIT | CPUID::CPUID_ARM_SHA2_BIT | CPUID::CPUID_ARM_NEON_BIT; } if(version >= info.min_version_neon) return CPUID::CPUID_ARM_NEON_BIT; } // Some other product we don't know about return 0; } } #endif uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) { BOTAN_UNUSED(cache_line_size); uint64_t detected_features = 0; #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) /* * On systems with getauxval these bits should normally be defined * in bits/auxv.h but some buggy? glibc installs seem to miss them. * These following values are all fixed, for the Linux ELF format, * so we just hardcode them in ARM_hwcap_bit enum. */ enum ARM_hwcap_bit { #if defined(BOTAN_TARGET_ARCH_IS_ARM32) NEON_bit = (1 << 12), AES_bit = (1 << 0), PMULL_bit = (1 << 1), SHA1_bit = (1 << 2), SHA2_bit = (1 << 3), ARCH_hwcap_neon = 16, // AT_HWCAP ARCH_hwcap_crypto = 26, // AT_HWCAP2 #elif defined(BOTAN_TARGET_ARCH_IS_ARM64) NEON_bit = (1 << 1), AES_bit = (1 << 3), PMULL_bit = (1 << 4), SHA1_bit = (1 << 5), SHA2_bit = (1 << 6), SHA3_bit = (1 << 17), SM3_bit = (1 << 18), SM4_bit = (1 << 19), SHA2_512_bit = (1 << 21), SVE_bit = (1 << 22), ARCH_hwcap_neon = 16, // AT_HWCAP ARCH_hwcap_crypto = 16, // AT_HWCAP #endif }; #if defined(AT_DCACHEBSIZE) // Exists only on Linux const unsigned long dcache_line = OS::get_auxval(AT_DCACHEBSIZE); // plausibility check if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128) *cache_line_size = static_cast(dcache_line); #endif const unsigned long hwcap_neon = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_neon); if(hwcap_neon & ARM_hwcap_bit::NEON_bit) detected_features |= CPUID::CPUID_ARM_NEON_BIT; /* On aarch64 this ends up calling getauxval twice with AT_HWCAP It doesn't seem worth optimizing this out, since getauxval is just reading a field in the ELF header. */ const unsigned long hwcap_crypto = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_crypto); if(hwcap_crypto & ARM_hwcap_bit::AES_bit) detected_features |= CPUID::CPUID_ARM_AES_BIT; if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit) detected_features |= CPUID::CPUID_ARM_PMULL_BIT; if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit) detected_features |= CPUID::CPUID_ARM_SHA1_BIT; if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit) detected_features |= CPUID::CPUID_ARM_SHA2_BIT; #if defined(BOTAN_TARGET_ARCH_IS_ARM64) if(hwcap_crypto & ARM_hwcap_bit::SHA3_bit) detected_features |= CPUID::CPUID_ARM_SHA3_BIT; if(hwcap_crypto & ARM_hwcap_bit::SM3_bit) detected_features |= CPUID::CPUID_ARM_SM3_BIT; if(hwcap_crypto & ARM_hwcap_bit::SM4_bit) detected_features |= CPUID::CPUID_ARM_SM4_BIT; if(hwcap_crypto & ARM_hwcap_bit::SHA2_512_bit) detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT; if(hwcap_crypto & ARM_hwcap_bit::SVE_bit) detected_features |= CPUID::CPUID_ARM_SVE_BIT; #endif #elif defined(BOTAN_TARGET_OS_IS_IOS) char machine[64] = { 0 }; size_t size = sizeof(machine) - 1; ::sysctlbyname("hw.machine", machine, &size, nullptr, 0); detected_features = flags_by_ios_machine_type(machine); // No way to detect cache line size on iOS? #elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64) /* No getauxval API available, fall back on probe functions. We only bother with Aarch64 here to simplify the code and because going to extreme contortions to support detect NEON on devices that probably don't support it doesn't seem worthwhile. NEON registers v0-v7 are caller saved in Aarch64 */ auto neon_probe = []() noexcept -> int { asm("and v0.16b, v0.16b, v0.16b"); return 1; }; auto aes_probe = []() noexcept -> int { asm(".word 0x4e284800"); return 1; }; auto pmull_probe = []() noexcept -> int { asm(".word 0x0ee0e000"); return 1; }; auto sha1_probe = []() noexcept -> int { asm(".word 0x5e280800"); return 1; }; auto sha2_probe = []() noexcept -> int { asm(".word 0x5e282800"); return 1; }; // Only bother running the crypto detection if we found NEON if(OS::run_cpu_instruction_probe(neon_probe) == 1) { detected_features |= CPUID::CPUID_ARM_NEON_BIT; if(OS::run_cpu_instruction_probe(aes_probe) == 1) detected_features |= CPUID::CPUID_ARM_AES_BIT; if(OS::run_cpu_instruction_probe(pmull_probe) == 1) detected_features |= CPUID::CPUID_ARM_PMULL_BIT; if(OS::run_cpu_instruction_probe(sha1_probe) == 1) detected_features |= CPUID::CPUID_ARM_SHA1_BIT; if(OS::run_cpu_instruction_probe(sha2_probe) == 1) detected_features |= CPUID::CPUID_ARM_SHA2_BIT; } #endif return detected_features; } #endif } /* * Runtime CPU detection for POWER/PowerPC * (C) 2009,2010,2013,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) /* * On macOS and OpenBSD ppc, use sysctl to detect AltiVec */ #if defined(BOTAN_TARGET_OS_IS_MACOS) #include #elif defined(BOTAN_TARGET_OS_IS_OPENBSD) #include #include #include #endif #endif namespace Botan { #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) /* * PowerPC specific block: check for AltiVec using either * sysctl or by reading processor version number register. */ uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) { BOTAN_UNUSED(cache_line_size); #if defined(BOTAN_TARGET_OS_IS_MACOS) || defined(BOTAN_TARGET_OS_IS_OPENBSD) // On macOS and OpenBSD, use sysctl int sels[2] = { #if defined(BOTAN_TARGET_OS_IS_OPENBSD) CTL_MACHDEP, CPU_ALTIVEC #else CTL_HW, HW_VECTORUNIT #endif }; int vector_type = 0; size_t length = sizeof(vector_type); int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0); if(error == 0 && vector_type > 0) return CPUID::CPUID_ALTIVEC_BIT; #elif (defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_HAS_ELF_AUX_INFO)) && defined(BOTAN_TARGET_ARCH_IS_PPC64) enum PPC_hwcap_bit { ALTIVEC_bit = (1 << 28), CRYPTO_bit = (1 << 25), DARN_bit = (1 << 21), ARCH_hwcap_altivec = 16, // AT_HWCAP ARCH_hwcap_crypto = 26, // AT_HWCAP2 }; uint64_t detected_features = 0; const unsigned long hwcap_altivec = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_altivec); if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit) detected_features |= CPUID::CPUID_ALTIVEC_BIT; const unsigned long hwcap_crypto = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_crypto); if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit) detected_features |= CPUID::CPUID_POWER_CRYPTO_BIT; if(hwcap_crypto & PPC_hwcap_bit::DARN_bit) detected_features |= CPUID::CPUID_DARN_BIT; return detected_features; #else /* On PowerPC, MSR 287 is PVR, the Processor Version Number Normally it is only accessible to ring 0, but Linux and NetBSD (others, too, maybe?) will trap and emulate it for us. */ int pvr = OS::run_cpu_instruction_probe([]() noexcept -> int { uint32_t pvr = 0; asm volatile("mfspr %0, 287" : "=r" (pvr)); // Top 16 bits suffice to identify the model return static_cast(pvr >> 16); }); if(pvr > 0) { const uint16_t ALTIVEC_PVR[] = { 0x003E, // IBM POWER6 0x003F, // IBM POWER7 0x004A, // IBM POWER7p 0x004B, // IBM POWER8E 0x004C, // IBM POWER8 NVL 0x004D, // IBM POWER8 0x004E, // IBM POWER9 0x000C, // G4-7400 0x0039, // G5 970 0x003C, // G5 970FX 0x0044, // G5 970MP 0x0070, // Cell PPU 0, // end }; for(size_t i = 0; ALTIVEC_PVR[i]; ++i) { if(pvr == ALTIVEC_PVR[i]) return CPUID::CPUID_ALTIVEC_BIT; } return 0; } // TODO try direct instruction probing #endif return 0; } #endif } /* * Runtime CPU detection for x86 * (C) 2009,2010,2013,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) #if defined(BOTAN_BUILD_COMPILER_IS_MSVC) #include #elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) #include #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) #include #endif #endif namespace Botan { #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) { #if defined(BOTAN_BUILD_COMPILER_IS_MSVC) #define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) #elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) #define X86_CPUID(type, out) do { __cpuid(out, type); } while(0) #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) #elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && defined(BOTAN_USE_GCC_INLINE_ASM) #define X86_CPUID(type, out) \ asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ : "0" (type)) #define X86_CPUID_SUBLEVEL(type, level, out) \ asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ : "0" (type), "2" (level)) #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) #define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0) #define X86_CPUID_SUBLEVEL(type, level, out) \ do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0) #else #warning "No way of calling x86 cpuid instruction for this compiler" #define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0) #define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0) #endif uint64_t features_detected = 0; uint32_t cpuid[4] = { 0 }; // CPUID 0: vendor identification, max sublevel X86_CPUID(0, cpuid); const uint32_t max_supported_sublevel = cpuid[0]; const uint32_t INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 }; const uint32_t AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 }; const bool is_intel = same_mem(cpuid + 1, INTEL_CPUID, 3); const bool is_amd = same_mem(cpuid + 1, AMD_CPUID, 3); if(max_supported_sublevel >= 1) { // CPUID 1: feature bits X86_CPUID(1, cpuid); const uint64_t flags0 = (static_cast(cpuid[2]) << 32) | cpuid[3]; enum x86_CPUID_1_bits : uint64_t { RDTSC = (1ULL << 4), SSE2 = (1ULL << 26), CLMUL = (1ULL << 33), SSSE3 = (1ULL << 41), SSE41 = (1ULL << 51), SSE42 = (1ULL << 52), AESNI = (1ULL << 57), RDRAND = (1ULL << 62) }; if(flags0 & x86_CPUID_1_bits::RDTSC) features_detected |= CPUID::CPUID_RDTSC_BIT; if(flags0 & x86_CPUID_1_bits::SSE2) features_detected |= CPUID::CPUID_SSE2_BIT; if(flags0 & x86_CPUID_1_bits::CLMUL) features_detected |= CPUID::CPUID_CLMUL_BIT; if(flags0 & x86_CPUID_1_bits::SSSE3) features_detected |= CPUID::CPUID_SSSE3_BIT; if(flags0 & x86_CPUID_1_bits::SSE41) features_detected |= CPUID::CPUID_SSE41_BIT; if(flags0 & x86_CPUID_1_bits::SSE42) features_detected |= CPUID::CPUID_SSE42_BIT; if(flags0 & x86_CPUID_1_bits::AESNI) features_detected |= CPUID::CPUID_AESNI_BIT; if(flags0 & x86_CPUID_1_bits::RDRAND) features_detected |= CPUID::CPUID_RDRAND_BIT; } if(is_intel) { // Intel cache line size is in cpuid(1) output *cache_line_size = 8 * get_byte(2, cpuid[1]); } else if(is_amd) { // AMD puts it in vendor zone X86_CPUID(0x80000005, cpuid); *cache_line_size = get_byte(3, cpuid[2]); } if(max_supported_sublevel >= 7) { clear_mem(cpuid, 4); X86_CPUID_SUBLEVEL(7, 0, cpuid); enum x86_CPUID_7_bits : uint64_t { BMI1 = (1ULL << 3), AVX2 = (1ULL << 5), BMI2 = (1ULL << 8), AVX512_F = (1ULL << 16), AVX512_DQ = (1ULL << 17), RDSEED = (1ULL << 18), ADX = (1ULL << 19), AVX512_IFMA = (1ULL << 21), SHA = (1ULL << 29), AVX512_BW = (1ULL << 30), AVX512_VL = (1ULL << 31), AVX512_VBMI = (1ULL << 33), AVX512_VBMI2 = (1ULL << 38), AVX512_VAES = (1ULL << 41), AVX512_VCLMUL = (1ULL << 42), AVX512_VBITALG = (1ULL << 44), }; const uint64_t flags7 = (static_cast(cpuid[2]) << 32) | cpuid[1]; if(flags7 & x86_CPUID_7_bits::AVX2) features_detected |= CPUID::CPUID_AVX2_BIT; if(flags7 & x86_CPUID_7_bits::BMI1) { features_detected |= CPUID::CPUID_BMI1_BIT; /* We only set the BMI2 bit if BMI1 is also supported, so BMI2 code can safely use both extensions. No known processor implements BMI2 but not BMI1. */ if(flags7 & x86_CPUID_7_bits::BMI2) features_detected |= CPUID::CPUID_BMI2_BIT; } if(flags7 & x86_CPUID_7_bits::AVX512_F) { features_detected |= CPUID::CPUID_AVX512F_BIT; if(flags7 & x86_CPUID_7_bits::AVX512_DQ) features_detected |= CPUID::CPUID_AVX512DQ_BIT; if(flags7 & x86_CPUID_7_bits::AVX512_BW) features_detected |= CPUID::CPUID_AVX512BW_BIT; const uint64_t ICELAKE_FLAGS = x86_CPUID_7_bits::AVX512_F | x86_CPUID_7_bits::AVX512_DQ | x86_CPUID_7_bits::AVX512_IFMA | x86_CPUID_7_bits::AVX512_BW | x86_CPUID_7_bits::AVX512_VL | x86_CPUID_7_bits::AVX512_VBMI | x86_CPUID_7_bits::AVX512_VBMI2 | x86_CPUID_7_bits::AVX512_VBITALG; if((flags7 & ICELAKE_FLAGS) == ICELAKE_FLAGS) features_detected |= CPUID::CPUID_AVX512_ICL_BIT; if(flags7 & x86_CPUID_7_bits::AVX512_VAES) features_detected |= CPUID::CPUID_AVX512_AES_BIT; if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL) features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT; } if(flags7 & x86_CPUID_7_bits::RDSEED) features_detected |= CPUID::CPUID_RDSEED_BIT; if(flags7 & x86_CPUID_7_bits::ADX) features_detected |= CPUID::CPUID_ADX_BIT; if(flags7 & x86_CPUID_7_bits::SHA) features_detected |= CPUID::CPUID_SHA_BIT; } #undef X86_CPUID #undef X86_CPUID_SUBLEVEL /* * If we don't have access to CPUID, we can still safely assume that * any x86-64 processor has SSE2 and RDTSC */ #if defined(BOTAN_TARGET_ARCH_IS_X86_64) if(features_detected == 0) { features_detected |= CPUID::CPUID_SSE2_BIT; features_detected |= CPUID::CPUID_RDTSC_BIT; } #endif return features_detected; } #endif } /* * CRC24 * (C) 1999-2007 Jack Lloyd * (C) 2017 [Ribose Inc](https://www.ribose.com). Performed by Krzysztof Kwiatkowski. * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { alignas(64) const uint32_t CRC24_T0[256] = { 0x00000000, 0x00FB4C86, 0x000DD58A, 0x00F6990C, 0x00E1E693, 0x001AAA15, 0x00EC3319, 0x00177F9F, 0x003981A1, 0x00C2CD27, 0x0034542B, 0x00CF18AD, 0x00D86732, 0x00232BB4, 0x00D5B2B8, 0x002EFE3E, 0x00894EC5, 0x00720243, 0x00849B4F, 0x007FD7C9, 0x0068A856, 0x0093E4D0, 0x00657DDC, 0x009E315A, 0x00B0CF64, 0x004B83E2, 0x00BD1AEE, 0x00465668, 0x005129F7, 0x00AA6571, 0x005CFC7D, 0x00A7B0FB, 0x00E9D10C, 0x00129D8A, 0x00E40486, 0x001F4800, 0x0008379F, 0x00F37B19, 0x0005E215, 0x00FEAE93, 0x00D050AD, 0x002B1C2B, 0x00DD8527, 0x0026C9A1, 0x0031B63E, 0x00CAFAB8, 0x003C63B4, 0x00C72F32, 0x00609FC9, 0x009BD34F, 0x006D4A43, 0x009606C5, 0x0081795A, 0x007A35DC, 0x008CACD0, 0x0077E056, 0x00591E68, 0x00A252EE, 0x0054CBE2, 0x00AF8764, 0x00B8F8FB, 0x0043B47D, 0x00B52D71, 0x004E61F7, 0x00D2A319, 0x0029EF9F, 0x00DF7693, 0x00243A15, 0x0033458A, 0x00C8090C, 0x003E9000, 0x00C5DC86, 0x00EB22B8, 0x00106E3E, 0x00E6F732, 0x001DBBB4, 0x000AC42B, 0x00F188AD, 0x000711A1, 0x00FC5D27, 0x005BEDDC, 0x00A0A15A, 0x00563856, 0x00AD74D0, 0x00BA0B4F, 0x004147C9, 0x00B7DEC5, 0x004C9243, 0x00626C7D, 0x009920FB, 0x006FB9F7, 0x0094F571, 0x00838AEE, 0x0078C668, 0x008E5F64, 0x007513E2, 0x003B7215, 0x00C03E93, 0x0036A79F, 0x00CDEB19, 0x00DA9486, 0x0021D800, 0x00D7410C, 0x002C0D8A, 0x0002F3B4, 0x00F9BF32, 0x000F263E, 0x00F46AB8, 0x00E31527, 0x001859A1, 0x00EEC0AD, 0x00158C2B, 0x00B23CD0, 0x00497056, 0x00BFE95A, 0x0044A5DC, 0x0053DA43, 0x00A896C5, 0x005E0FC9, 0x00A5434F, 0x008BBD71, 0x0070F1F7, 0x008668FB, 0x007D247D, 0x006A5BE2, 0x00911764, 0x00678E68, 0x009CC2EE, 0x00A44733, 0x005F0BB5, 0x00A992B9, 0x0052DE3F, 0x0045A1A0, 0x00BEED26, 0x0048742A, 0x00B338AC, 0x009DC692, 0x00668A14, 0x00901318, 0x006B5F9E, 0x007C2001, 0x00876C87, 0x0071F58B, 0x008AB90D, 0x002D09F6, 0x00D64570, 0x0020DC7C, 0x00DB90FA, 0x00CCEF65, 0x0037A3E3, 0x00C13AEF, 0x003A7669, 0x00148857, 0x00EFC4D1, 0x00195DDD, 0x00E2115B, 0x00F56EC4, 0x000E2242, 0x00F8BB4E, 0x0003F7C8, 0x004D963F, 0x00B6DAB9, 0x004043B5, 0x00BB0F33, 0x00AC70AC, 0x00573C2A, 0x00A1A526, 0x005AE9A0, 0x0074179E, 0x008F5B18, 0x0079C214, 0x00828E92, 0x0095F10D, 0x006EBD8B, 0x00982487, 0x00636801, 0x00C4D8FA, 0x003F947C, 0x00C90D70, 0x003241F6, 0x00253E69, 0x00DE72EF, 0x0028EBE3, 0x00D3A765, 0x00FD595B, 0x000615DD, 0x00F08CD1, 0x000BC057, 0x001CBFC8, 0x00E7F34E, 0x00116A42, 0x00EA26C4, 0x0076E42A, 0x008DA8AC, 0x007B31A0, 0x00807D26, 0x009702B9, 0x006C4E3F, 0x009AD733, 0x00619BB5, 0x004F658B, 0x00B4290D, 0x0042B001, 0x00B9FC87, 0x00AE8318, 0x0055CF9E, 0x00A35692, 0x00581A14, 0x00FFAAEF, 0x0004E669, 0x00F27F65, 0x000933E3, 0x001E4C7C, 0x00E500FA, 0x001399F6, 0x00E8D570, 0x00C62B4E, 0x003D67C8, 0x00CBFEC4, 0x0030B242, 0x0027CDDD, 0x00DC815B, 0x002A1857, 0x00D154D1, 0x009F3526, 0x006479A0, 0x0092E0AC, 0x0069AC2A, 0x007ED3B5, 0x00859F33, 0x0073063F, 0x00884AB9, 0x00A6B487, 0x005DF801, 0x00AB610D, 0x00502D8B, 0x00475214, 0x00BC1E92, 0x004A879E, 0x00B1CB18, 0x00167BE3, 0x00ED3765, 0x001BAE69, 0x00E0E2EF, 0x00F79D70, 0x000CD1F6, 0x00FA48FA, 0x0001047C, 0x002FFA42, 0x00D4B6C4, 0x00222FC8, 0x00D9634E, 0x00CE1CD1, 0x00355057, 0x00C3C95B, 0x003885DD }; alignas(64) const uint32_t CRC24_T1[256] = { 0x00000000, 0x00488F66, 0x00901ECD, 0x00D891AB, 0x00DB711C, 0x0093FE7A, 0x004B6FD1, 0x0003E0B7, 0x00B6E338, 0x00FE6C5E, 0x0026FDF5, 0x006E7293, 0x006D9224, 0x00251D42, 0x00FD8CE9, 0x00B5038F, 0x006CC771, 0x00244817, 0x00FCD9BC, 0x00B456DA, 0x00B7B66D, 0x00FF390B, 0x0027A8A0, 0x006F27C6, 0x00DA2449, 0x0092AB2F, 0x004A3A84, 0x0002B5E2, 0x00015555, 0x0049DA33, 0x00914B98, 0x00D9C4FE, 0x00D88EE3, 0x00900185, 0x0048902E, 0x00001F48, 0x0003FFFF, 0x004B7099, 0x0093E132, 0x00DB6E54, 0x006E6DDB, 0x0026E2BD, 0x00FE7316, 0x00B6FC70, 0x00B51CC7, 0x00FD93A1, 0x0025020A, 0x006D8D6C, 0x00B44992, 0x00FCC6F4, 0x0024575F, 0x006CD839, 0x006F388E, 0x0027B7E8, 0x00FF2643, 0x00B7A925, 0x0002AAAA, 0x004A25CC, 0x0092B467, 0x00DA3B01, 0x00D9DBB6, 0x009154D0, 0x0049C57B, 0x00014A1D, 0x004B5141, 0x0003DE27, 0x00DB4F8C, 0x0093C0EA, 0x0090205D, 0x00D8AF3B, 0x00003E90, 0x0048B1F6, 0x00FDB279, 0x00B53D1F, 0x006DACB4, 0x002523D2, 0x0026C365, 0x006E4C03, 0x00B6DDA8, 0x00FE52CE, 0x00279630, 0x006F1956, 0x00B788FD, 0x00FF079B, 0x00FCE72C, 0x00B4684A, 0x006CF9E1, 0x00247687, 0x00917508, 0x00D9FA6E, 0x00016BC5, 0x0049E4A3, 0x004A0414, 0x00028B72, 0x00DA1AD9, 0x009295BF, 0x0093DFA2, 0x00DB50C4, 0x0003C16F, 0x004B4E09, 0x0048AEBE, 0x000021D8, 0x00D8B073, 0x00903F15, 0x00253C9A, 0x006DB3FC, 0x00B52257, 0x00FDAD31, 0x00FE4D86, 0x00B6C2E0, 0x006E534B, 0x0026DC2D, 0x00FF18D3, 0x00B797B5, 0x006F061E, 0x00278978, 0x002469CF, 0x006CE6A9, 0x00B47702, 0x00FCF864, 0x0049FBEB, 0x0001748D, 0x00D9E526, 0x00916A40, 0x00928AF7, 0x00DA0591, 0x0002943A, 0x004A1B5C, 0x0096A282, 0x00DE2DE4, 0x0006BC4F, 0x004E3329, 0x004DD39E, 0x00055CF8, 0x00DDCD53, 0x00954235, 0x002041BA, 0x0068CEDC, 0x00B05F77, 0x00F8D011, 0x00FB30A6, 0x00B3BFC0, 0x006B2E6B, 0x0023A10D, 0x00FA65F3, 0x00B2EA95, 0x006A7B3E, 0x0022F458, 0x002114EF, 0x00699B89, 0x00B10A22, 0x00F98544, 0x004C86CB, 0x000409AD, 0x00DC9806, 0x00941760, 0x0097F7D7, 0x00DF78B1, 0x0007E91A, 0x004F667C, 0x004E2C61, 0x0006A307, 0x00DE32AC, 0x0096BDCA, 0x00955D7D, 0x00DDD21B, 0x000543B0, 0x004DCCD6, 0x00F8CF59, 0x00B0403F, 0x0068D194, 0x00205EF2, 0x0023BE45, 0x006B3123, 0x00B3A088, 0x00FB2FEE, 0x0022EB10, 0x006A6476, 0x00B2F5DD, 0x00FA7ABB, 0x00F99A0C, 0x00B1156A, 0x006984C1, 0x00210BA7, 0x00940828, 0x00DC874E, 0x000416E5, 0x004C9983, 0x004F7934, 0x0007F652, 0x00DF67F9, 0x0097E89F, 0x00DDF3C3, 0x00957CA5, 0x004DED0E, 0x00056268, 0x000682DF, 0x004E0DB9, 0x00969C12, 0x00DE1374, 0x006B10FB, 0x00239F9D, 0x00FB0E36, 0x00B38150, 0x00B061E7, 0x00F8EE81, 0x00207F2A, 0x0068F04C, 0x00B134B2, 0x00F9BBD4, 0x00212A7F, 0x0069A519, 0x006A45AE, 0x0022CAC8, 0x00FA5B63, 0x00B2D405, 0x0007D78A, 0x004F58EC, 0x0097C947, 0x00DF4621, 0x00DCA696, 0x009429F0, 0x004CB85B, 0x0004373D, 0x00057D20, 0x004DF246, 0x009563ED, 0x00DDEC8B, 0x00DE0C3C, 0x0096835A, 0x004E12F1, 0x00069D97, 0x00B39E18, 0x00FB117E, 0x002380D5, 0x006B0FB3, 0x0068EF04, 0x00206062, 0x00F8F1C9, 0x00B07EAF, 0x0069BA51, 0x00213537, 0x00F9A49C, 0x00B12BFA, 0x00B2CB4D, 0x00FA442B, 0x0022D580, 0x006A5AE6, 0x00DF5969, 0x0097D60F, 0x004F47A4, 0x0007C8C2, 0x00042875, 0x004CA713, 0x009436B8, 0x00DCB9DE }; alignas(64) const uint32_t CRC24_T2[256] = { 0x00000000, 0x00D70983, 0x00555F80, 0x00825603, 0x0051F286, 0x0086FB05, 0x0004AD06, 0x00D3A485, 0x0059A88B, 0x008EA108, 0x000CF70B, 0x00DBFE88, 0x00085A0D, 0x00DF538E, 0x005D058D, 0x008A0C0E, 0x00491C91, 0x009E1512, 0x001C4311, 0x00CB4A92, 0x0018EE17, 0x00CFE794, 0x004DB197, 0x009AB814, 0x0010B41A, 0x00C7BD99, 0x0045EB9A, 0x0092E219, 0x0041469C, 0x00964F1F, 0x0014191C, 0x00C3109F, 0x006974A4, 0x00BE7D27, 0x003C2B24, 0x00EB22A7, 0x00388622, 0x00EF8FA1, 0x006DD9A2, 0x00BAD021, 0x0030DC2F, 0x00E7D5AC, 0x006583AF, 0x00B28A2C, 0x00612EA9, 0x00B6272A, 0x00347129, 0x00E378AA, 0x00206835, 0x00F761B6, 0x007537B5, 0x00A23E36, 0x00719AB3, 0x00A69330, 0x0024C533, 0x00F3CCB0, 0x0079C0BE, 0x00AEC93D, 0x002C9F3E, 0x00FB96BD, 0x00283238, 0x00FF3BBB, 0x007D6DB8, 0x00AA643B, 0x0029A4CE, 0x00FEAD4D, 0x007CFB4E, 0x00ABF2CD, 0x00785648, 0x00AF5FCB, 0x002D09C8, 0x00FA004B, 0x00700C45, 0x00A705C6, 0x002553C5, 0x00F25A46, 0x0021FEC3, 0x00F6F740, 0x0074A143, 0x00A3A8C0, 0x0060B85F, 0x00B7B1DC, 0x0035E7DF, 0x00E2EE5C, 0x00314AD9, 0x00E6435A, 0x00641559, 0x00B31CDA, 0x003910D4, 0x00EE1957, 0x006C4F54, 0x00BB46D7, 0x0068E252, 0x00BFEBD1, 0x003DBDD2, 0x00EAB451, 0x0040D06A, 0x0097D9E9, 0x00158FEA, 0x00C28669, 0x001122EC, 0x00C62B6F, 0x00447D6C, 0x009374EF, 0x001978E1, 0x00CE7162, 0x004C2761, 0x009B2EE2, 0x00488A67, 0x009F83E4, 0x001DD5E7, 0x00CADC64, 0x0009CCFB, 0x00DEC578, 0x005C937B, 0x008B9AF8, 0x00583E7D, 0x008F37FE, 0x000D61FD, 0x00DA687E, 0x00506470, 0x00876DF3, 0x00053BF0, 0x00D23273, 0x000196F6, 0x00D69F75, 0x0054C976, 0x0083C0F5, 0x00A9041B, 0x007E0D98, 0x00FC5B9B, 0x002B5218, 0x00F8F69D, 0x002FFF1E, 0x00ADA91D, 0x007AA09E, 0x00F0AC90, 0x0027A513, 0x00A5F310, 0x0072FA93, 0x00A15E16, 0x00765795, 0x00F40196, 0x00230815, 0x00E0188A, 0x00371109, 0x00B5470A, 0x00624E89, 0x00B1EA0C, 0x0066E38F, 0x00E4B58C, 0x0033BC0F, 0x00B9B001, 0x006EB982, 0x00ECEF81, 0x003BE602, 0x00E84287, 0x003F4B04, 0x00BD1D07, 0x006A1484, 0x00C070BF, 0x0017793C, 0x00952F3F, 0x004226BC, 0x00918239, 0x00468BBA, 0x00C4DDB9, 0x0013D43A, 0x0099D834, 0x004ED1B7, 0x00CC87B4, 0x001B8E37, 0x00C82AB2, 0x001F2331, 0x009D7532, 0x004A7CB1, 0x00896C2E, 0x005E65AD, 0x00DC33AE, 0x000B3A2D, 0x00D89EA8, 0x000F972B, 0x008DC128, 0x005AC8AB, 0x00D0C4A5, 0x0007CD26, 0x00859B25, 0x005292A6, 0x00813623, 0x00563FA0, 0x00D469A3, 0x00036020, 0x0080A0D5, 0x0057A956, 0x00D5FF55, 0x0002F6D6, 0x00D15253, 0x00065BD0, 0x00840DD3, 0x00530450, 0x00D9085E, 0x000E01DD, 0x008C57DE, 0x005B5E5D, 0x0088FAD8, 0x005FF35B, 0x00DDA558, 0x000AACDB, 0x00C9BC44, 0x001EB5C7, 0x009CE3C4, 0x004BEA47, 0x00984EC2, 0x004F4741, 0x00CD1142, 0x001A18C1, 0x009014CF, 0x00471D4C, 0x00C54B4F, 0x001242CC, 0x00C1E649, 0x0016EFCA, 0x0094B9C9, 0x0043B04A, 0x00E9D471, 0x003EDDF2, 0x00BC8BF1, 0x006B8272, 0x00B826F7, 0x006F2F74, 0x00ED7977, 0x003A70F4, 0x00B07CFA, 0x00677579, 0x00E5237A, 0x00322AF9, 0x00E18E7C, 0x003687FF, 0x00B4D1FC, 0x0063D87F, 0x00A0C8E0, 0x0077C163, 0x00F59760, 0x00229EE3, 0x00F13A66, 0x002633E5, 0x00A465E6, 0x00736C65, 0x00F9606B, 0x002E69E8, 0x00AC3FEB, 0x007B3668, 0x00A892ED, 0x007F9B6E, 0x00FDCD6D, 0x002AC4EE }; alignas(64) const uint32_t CRC24_T3[256] = { 0x00000000, 0x00520936, 0x00A4126C, 0x00F61B5A, 0x004825D8, 0x001A2CEE, 0x00EC37B4, 0x00BE3E82, 0x006B0636, 0x00390F00, 0x00CF145A, 0x009D1D6C, 0x002323EE, 0x00712AD8, 0x00873182, 0x00D538B4, 0x00D60C6C, 0x0084055A, 0x00721E00, 0x00201736, 0x009E29B4, 0x00CC2082, 0x003A3BD8, 0x006832EE, 0x00BD0A5A, 0x00EF036C, 0x00191836, 0x004B1100, 0x00F52F82, 0x00A726B4, 0x00513DEE, 0x000334D8, 0x00AC19D8, 0x00FE10EE, 0x00080BB4, 0x005A0282, 0x00E43C00, 0x00B63536, 0x00402E6C, 0x0012275A, 0x00C71FEE, 0x009516D8, 0x00630D82, 0x003104B4, 0x008F3A36, 0x00DD3300, 0x002B285A, 0x0079216C, 0x007A15B4, 0x00281C82, 0x00DE07D8, 0x008C0EEE, 0x0032306C, 0x0060395A, 0x00962200, 0x00C42B36, 0x00111382, 0x00431AB4, 0x00B501EE, 0x00E708D8, 0x0059365A, 0x000B3F6C, 0x00FD2436, 0x00AF2D00, 0x00A37F36, 0x00F17600, 0x00076D5A, 0x0055646C, 0x00EB5AEE, 0x00B953D8, 0x004F4882, 0x001D41B4, 0x00C87900, 0x009A7036, 0x006C6B6C, 0x003E625A, 0x00805CD8, 0x00D255EE, 0x00244EB4, 0x00764782, 0x0075735A, 0x00277A6C, 0x00D16136, 0x00836800, 0x003D5682, 0x006F5FB4, 0x009944EE, 0x00CB4DD8, 0x001E756C, 0x004C7C5A, 0x00BA6700, 0x00E86E36, 0x005650B4, 0x00045982, 0x00F242D8, 0x00A04BEE, 0x000F66EE, 0x005D6FD8, 0x00AB7482, 0x00F97DB4, 0x00474336, 0x00154A00, 0x00E3515A, 0x00B1586C, 0x006460D8, 0x003669EE, 0x00C072B4, 0x00927B82, 0x002C4500, 0x007E4C36, 0x0088576C, 0x00DA5E5A, 0x00D96A82, 0x008B63B4, 0x007D78EE, 0x002F71D8, 0x00914F5A, 0x00C3466C, 0x00355D36, 0x00675400, 0x00B26CB4, 0x00E06582, 0x00167ED8, 0x004477EE, 0x00FA496C, 0x00A8405A, 0x005E5B00, 0x000C5236, 0x0046FF6C, 0x0014F65A, 0x00E2ED00, 0x00B0E436, 0x000EDAB4, 0x005CD382, 0x00AAC8D8, 0x00F8C1EE, 0x002DF95A, 0x007FF06C, 0x0089EB36, 0x00DBE200, 0x0065DC82, 0x0037D5B4, 0x00C1CEEE, 0x0093C7D8, 0x0090F300, 0x00C2FA36, 0x0034E16C, 0x0066E85A, 0x00D8D6D8, 0x008ADFEE, 0x007CC4B4, 0x002ECD82, 0x00FBF536, 0x00A9FC00, 0x005FE75A, 0x000DEE6C, 0x00B3D0EE, 0x00E1D9D8, 0x0017C282, 0x0045CBB4, 0x00EAE6B4, 0x00B8EF82, 0x004EF4D8, 0x001CFDEE, 0x00A2C36C, 0x00F0CA5A, 0x0006D100, 0x0054D836, 0x0081E082, 0x00D3E9B4, 0x0025F2EE, 0x0077FBD8, 0x00C9C55A, 0x009BCC6C, 0x006DD736, 0x003FDE00, 0x003CEAD8, 0x006EE3EE, 0x0098F8B4, 0x00CAF182, 0x0074CF00, 0x0026C636, 0x00D0DD6C, 0x0082D45A, 0x0057ECEE, 0x0005E5D8, 0x00F3FE82, 0x00A1F7B4, 0x001FC936, 0x004DC000, 0x00BBDB5A, 0x00E9D26C, 0x00E5805A, 0x00B7896C, 0x00419236, 0x00139B00, 0x00ADA582, 0x00FFACB4, 0x0009B7EE, 0x005BBED8, 0x008E866C, 0x00DC8F5A, 0x002A9400, 0x00789D36, 0x00C6A3B4, 0x0094AA82, 0x0062B1D8, 0x0030B8EE, 0x00338C36, 0x00618500, 0x00979E5A, 0x00C5976C, 0x007BA9EE, 0x0029A0D8, 0x00DFBB82, 0x008DB2B4, 0x00588A00, 0x000A8336, 0x00FC986C, 0x00AE915A, 0x0010AFD8, 0x0042A6EE, 0x00B4BDB4, 0x00E6B482, 0x00499982, 0x001B90B4, 0x00ED8BEE, 0x00BF82D8, 0x0001BC5A, 0x0053B56C, 0x00A5AE36, 0x00F7A700, 0x00229FB4, 0x00709682, 0x00868DD8, 0x00D484EE, 0x006ABA6C, 0x0038B35A, 0x00CEA800, 0x009CA136, 0x009F95EE, 0x00CD9CD8, 0x003B8782, 0x00698EB4, 0x00D7B036, 0x0085B900, 0x0073A25A, 0x0021AB6C, 0x00F493D8, 0x00A69AEE, 0x005081B4, 0x00028882, 0x00BCB600, 0x00EEBF36, 0x0018A46C, 0x004AAD5A }; inline uint32_t process8(uint32_t crc, uint8_t data) { return (crc >> 8) ^ CRC24_T0[(crc & 0xff) ^ data]; } inline uint32_t process32(uint32_t crc, uint32_t word) { crc ^= word; crc = CRC24_T3[(crc >> 0) & 0xff] ^ CRC24_T2[(crc >> 8) & 0xff] ^ CRC24_T1[(crc >> 16) & 0xff] ^ CRC24_T0[(crc >> 24) & 0xff]; return crc; } } std::unique_ptr CRC24::copy_state() const { return std::unique_ptr(new CRC24(*this)); } /* * Update a CRC24 Checksum * * Implementation uses Slicing-by-N algorithm described in * "Novel Table Lookup-Based Algorithms for High-Performance * CRC Generation", by M.Kounavis. * * This algorithm uses 4 precomputed look-up tables. First * table T0 is computed same way as in a method proposed * by D. Sarwate (1988). Then T_1, T2 and T3 are computed * in following way: * * T1[j] = (T0[j] >> 8) ^ T0[ T0[j] & 0xFF ] * T2[j] = (T1[j] >> 8) ^ T0[ T1[j] & 0xFF ] * T3[j] = (T2[j] >> 8) ^ T0[ T2[j] & 0xFF ] * */ void CRC24::add_data(const uint8_t input[], size_t length) { uint32_t d[4]; uint32_t tmp = m_crc; // Input is word aligned if WA & input == 0 static const uint8_t WA = (BOTAN_MP_WORD_BITS/8) - 1; // Ensure input is word aligned before processing in parallel for(;length && (reinterpret_cast(input) & WA); length--) tmp = process8(tmp, *input++); while(length >= 16) { load_le(d, input, 4); tmp = process32(tmp, d[0]); tmp = process32(tmp, d[1]); tmp = process32(tmp, d[2]); tmp = process32(tmp, d[3]); input += 16; length -= 16; } while(length--) tmp = process8(tmp, *input++); m_crc = tmp & 0xffffff; } /* * Finalize a CRC24 Checksum */ void CRC24::final_result(uint8_t output[]) { output[0] = get_byte(3, m_crc); output[1] = get_byte(2, m_crc); output[2] = get_byte(1, m_crc); clear(); } } /* * CRC32 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr CRC32::copy_state() const { return std::unique_ptr(new CRC32(*this)); } namespace { const uint32_t CRC32_T0[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; } /* * Update a CRC32 Checksum */ void CRC32::add_data(const uint8_t input[], size_t length) { uint32_t tmp = m_crc; while(length >= 16) { tmp = CRC32_T0[(tmp ^ input[ 0]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 1]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 2]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 3]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 4]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 5]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 6]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 7]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 8]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[ 9]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[10]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[11]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[12]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[13]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[14]) & 0xFF] ^ (tmp >> 8); tmp = CRC32_T0[(tmp ^ input[15]) & 0xFF] ^ (tmp >> 8); input += 16; length -= 16; } for(size_t i = 0; i != length; ++i) tmp = CRC32_T0[(tmp ^ input[i]) & 0xFF] ^ (tmp >> 8); m_crc = tmp; } /* * Finalize a CRC32 Checksum */ void CRC32::final_result(uint8_t output[]) { m_crc ^= 0xFFFFFFFF; store_be(m_crc, output); clear(); } } /* * Cryptobox Message Routines * (C) 2009 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace CryptoBox { namespace { /* First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits for later use as flags, etc if needed */ const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400; const size_t VERSION_CODE_LEN = 4; const size_t CIPHER_KEY_LEN = 32; const size_t CIPHER_IV_LEN = 16; const size_t MAC_KEY_LEN = 32; const size_t MAC_OUTPUT_LEN = 20; const size_t PBKDF_SALT_LEN = 10; const size_t PBKDF_ITERATIONS = 8 * 1024; const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN; const size_t CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN; } std::string encrypt(const uint8_t input[], size_t input_len, const std::string& passphrase, RandomNumberGenerator& rng) { /* Output format is: version # (4 bytes) salt (10 bytes) mac (20 bytes) ciphertext */ secure_vector out_buf(CRYPTOBOX_HEADER_LEN + input_len); for(size_t i = 0; i != VERSION_CODE_LEN; ++i) out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE); rng.randomize(&out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN); // space left for MAC here if(input_len > 0) copy_mem(&out_buf[CRYPTOBOX_HEADER_LEN], input, input_len); // Generate the keys and IV std::unique_ptr pbkdf(PBKDF::create_or_throw("PBKDF2(HMAC(SHA-512))")); OctetString master_key = pbkdf->derive_key( CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN, passphrase, &out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN, PBKDF_ITERATIONS); const uint8_t* mk = master_key.begin(); const uint8_t* cipher_key = mk; const uint8_t* mac_key = mk + CIPHER_KEY_LEN; const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN; // Now encrypt and authenticate std::unique_ptr ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", ENCRYPTION); ctr->set_key(cipher_key, CIPHER_KEY_LEN); ctr->start(iv, CIPHER_IV_LEN); ctr->finish(out_buf, CRYPTOBOX_HEADER_LEN); std::unique_ptr hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); hmac->set_key(mac_key, MAC_KEY_LEN); if(input_len > 0) hmac->update(&out_buf[CRYPTOBOX_HEADER_LEN], input_len); // Can't write directly because of MAC truncation secure_vector mac = hmac->final(); copy_mem(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], mac.data(), MAC_OUTPUT_LEN); return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE"); } secure_vector decrypt_bin(const uint8_t input[], size_t input_len, const std::string& passphrase) { DataSource_Memory input_src(input, input_len); secure_vector ciphertext = PEM_Code::decode_check_label(input_src, "BOTAN CRYPTOBOX MESSAGE"); if(ciphertext.size() < CRYPTOBOX_HEADER_LEN) throw Decoding_Error("Invalid CryptoBox input"); for(size_t i = 0; i != VERSION_CODE_LEN; ++i) if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE)) throw Decoding_Error("Bad CryptoBox version"); const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN]; const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN]; std::unique_ptr pbkdf(PBKDF::create_or_throw("PBKDF2(HMAC(SHA-512))")); OctetString master_key = pbkdf->derive_key( PBKDF_OUTPUT_LEN, passphrase, pbkdf_salt, PBKDF_SALT_LEN, PBKDF_ITERATIONS); const uint8_t* mk = master_key.begin(); const uint8_t* cipher_key = mk; const uint8_t* mac_key = mk + CIPHER_KEY_LEN; const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN; // Now authenticate and decrypt std::unique_ptr hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); hmac->set_key(mac_key, MAC_KEY_LEN); if(ciphertext.size() > CRYPTOBOX_HEADER_LEN) { hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN], ciphertext.size() - CRYPTOBOX_HEADER_LEN); } secure_vector computed_mac = hmac->final(); if(!constant_time_compare(computed_mac.data(), box_mac, MAC_OUTPUT_LEN)) throw Decoding_Error("CryptoBox integrity failure"); std::unique_ptr ctr(Cipher_Mode::create_or_throw("Serpent/CTR-BE", DECRYPTION)); ctr->set_key(cipher_key, CIPHER_KEY_LEN); ctr->start(iv, CIPHER_IV_LEN); ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN); ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN); return ciphertext; } secure_vector decrypt_bin(const std::string& input, const std::string& passphrase) { return decrypt_bin(cast_char_ptr_to_uint8(input.data()), input.size(), passphrase); } std::string decrypt(const uint8_t input[], size_t input_len, const std::string& passphrase) { const secure_vector bin = decrypt_bin(input, input_len, passphrase); return std::string(cast_uint8_ptr_to_char(&bin[0]), bin.size()); } std::string decrypt(const std::string& input, const std::string& passphrase) { return decrypt(cast_char_ptr_to_uint8(input.data()), input.size(), passphrase); } } } /* * Counter mode * (C) 1999-2011,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { CTR_BE::CTR_BE(BlockCipher* ciph) : m_cipher(ciph), m_block_size(m_cipher->block_size()), m_ctr_size(m_block_size), m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), m_counter(m_cipher->parallel_bytes()), m_pad(m_counter.size()), m_pad_pos(0) { } CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) : m_cipher(cipher), m_block_size(m_cipher->block_size()), m_ctr_size(ctr_size), m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), m_counter(m_cipher->parallel_bytes()), m_pad(m_counter.size()), m_pad_pos(0) { BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size, "Invalid CTR-BE counter size"); } void CTR_BE::clear() { m_cipher->clear(); zeroise(m_pad); zeroise(m_counter); zap(m_iv); m_pad_pos = 0; } size_t CTR_BE::default_iv_length() const { return m_block_size; } bool CTR_BE::valid_iv_length(size_t iv_len) const { return (iv_len <= m_block_size); } Key_Length_Specification CTR_BE::key_spec() const { return m_cipher->key_spec(); } CTR_BE* CTR_BE::clone() const { return new CTR_BE(m_cipher->clone(), m_ctr_size); } void CTR_BE::key_schedule(const uint8_t key[], size_t key_len) { m_cipher->set_key(key, key_len); // Set a default all-zeros IV set_iv(nullptr, 0); } std::string CTR_BE::name() const { if(m_ctr_size == m_block_size) return ("CTR-BE(" + m_cipher->name() + ")"); else return ("CTR-BE(" + m_cipher->name() + "," + std::to_string(m_ctr_size) + ")"); } void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length) { verify_key_set(m_iv.empty() == false); const uint8_t* pad_bits = &m_pad[0]; const size_t pad_size = m_pad.size(); if(m_pad_pos > 0) { const size_t avail = pad_size - m_pad_pos; const size_t take = std::min(length, avail); xor_buf(out, in, pad_bits + m_pad_pos, take); length -= take; in += take; out += take; m_pad_pos += take; if(take == avail) { add_counter(m_ctr_blocks); m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); m_pad_pos = 0; } } while(length >= pad_size) { xor_buf(out, in, pad_bits, pad_size); length -= pad_size; in += pad_size; out += pad_size; add_counter(m_ctr_blocks); m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); } xor_buf(out, in, pad_bits, length); m_pad_pos += length; } void CTR_BE::set_iv(const uint8_t iv[], size_t iv_len) { if(!valid_iv_length(iv_len)) throw Invalid_IV_Length(name(), iv_len); m_iv.resize(m_block_size); zeroise(m_iv); buffer_insert(m_iv, 0, iv, iv_len); seek(0); } void CTR_BE::add_counter(const uint64_t counter) { const size_t ctr_size = m_ctr_size; const size_t ctr_blocks = m_ctr_blocks; const size_t BS = m_block_size; if(ctr_size == 4) { const size_t off = (BS - 4); const uint32_t low32 = static_cast(counter + load_be(&m_counter[off], 0)); for(size_t i = 0; i != ctr_blocks; ++i) { store_be(uint32_t(low32 + i), &m_counter[i*BS+off]); } } else if(ctr_size == 8) { const size_t off = (BS - 8); const uint64_t low64 = counter + load_be(&m_counter[off], 0); for(size_t i = 0; i != ctr_blocks; ++i) { store_be(uint64_t(low64 + i), &m_counter[i*BS+off]); } } else if(ctr_size == 16) { const size_t off = (BS - 16); uint64_t b0 = load_be(&m_counter[off], 0); uint64_t b1 = load_be(&m_counter[off], 1); b1 += counter; b0 += (b1 < counter) ? 1 : 0; // carry for(size_t i = 0; i != ctr_blocks; ++i) { store_be(b0, &m_counter[i*BS+off]); store_be(b1, &m_counter[i*BS+off+8]); b1 += 1; b0 += (b1 == 0); // carry } } else { for(size_t i = 0; i != ctr_blocks; ++i) { uint64_t local_counter = counter; uint16_t carry = static_cast(local_counter); for(size_t j = 0; (carry || local_counter) && j != ctr_size; ++j) { const size_t off = i*BS + (BS-1-j); const uint16_t cnt = static_cast(m_counter[off]) + carry; m_counter[off] = static_cast(cnt); local_counter = (local_counter >> 8); carry = (cnt >> 8) + static_cast(local_counter); } } } } void CTR_BE::seek(uint64_t offset) { verify_key_set(m_iv.empty() == false); const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size()); zeroise(m_counter); buffer_insert(m_counter, 0, m_iv); const size_t BS = m_block_size; // Set m_counter blocks to IV, IV + 1, ... IV + n if(m_ctr_size == 4 && BS >= 8) { const uint32_t low32 = load_be(&m_counter[BS-4], 0); if(m_ctr_blocks >= 4 && is_power_of_2(m_ctr_blocks)) { size_t written = 1; while(written < m_ctr_blocks) { copy_mem(&m_counter[written*BS], &m_counter[0], BS*written); written *= 2; } } else { for(size_t i = 1; i != m_ctr_blocks; ++i) { copy_mem(&m_counter[i*BS], &m_counter[0], BS - 4); } } for(size_t i = 1; i != m_ctr_blocks; ++i) { const uint32_t c = static_cast(low32 + i); store_be(c, &m_counter[(BS-4)+i*BS]); } } else { // do everything sequentially: for(size_t i = 1; i != m_ctr_blocks; ++i) { buffer_insert(m_counter, i*BS, &m_counter[(i-1)*BS], BS); for(size_t j = 0; j != m_ctr_size; ++j) if(++m_counter[i*BS + (BS - 1 - j)]) break; } } if(base_counter > 0) add_counter(base_counter); m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); m_pad_pos = offset % m_counter.size(); } } /* * Curve25519 * (C) 2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void curve25519_basepoint(uint8_t mypublic[32], const uint8_t secret[32]) { const uint8_t basepoint[32] = { 9 }; curve25519_donna(mypublic, secret, basepoint); } namespace { void size_check(size_t size, const char* thing) { if(size != 32) throw Decoding_Error("Invalid size " + std::to_string(size) + " for Curve25519 " + thing); } secure_vector curve25519(const secure_vector& secret, const uint8_t pubval[32]) { secure_vector out(32); curve25519_donna(out.data(), secret.data(), pubval); return out; } } AlgorithmIdentifier Curve25519_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); } bool Curve25519_PublicKey::check_key(RandomNumberGenerator&, bool) const { return true; // no tests possible? } Curve25519_PublicKey::Curve25519_PublicKey(const AlgorithmIdentifier&, const std::vector& key_bits) { m_public = key_bits; size_check(m_public.size(), "public key"); } std::vector Curve25519_PublicKey::public_key_bits() const { return m_public; } Curve25519_PrivateKey::Curve25519_PrivateKey(const secure_vector& secret_key) { if(secret_key.size() != 32) throw Decoding_Error("Invalid size for Curve25519 private key"); m_public.resize(32); m_private = secret_key; curve25519_basepoint(m_public.data(), m_private.data()); } Curve25519_PrivateKey::Curve25519_PrivateKey(RandomNumberGenerator& rng) { m_private = rng.random_vec(32); m_public.resize(32); curve25519_basepoint(m_public.data(), m_private.data()); } Curve25519_PrivateKey::Curve25519_PrivateKey(const AlgorithmIdentifier&, const secure_vector& key_bits) { BER_Decoder(key_bits).decode(m_private, OCTET_STRING).discard_remaining(); size_check(m_private.size(), "private key"); m_public.resize(32); curve25519_basepoint(m_public.data(), m_private.data()); } secure_vector Curve25519_PrivateKey::private_key_bits() const { return DER_Encoder().encode(m_private, OCTET_STRING).get_contents(); } bool Curve25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const { std::vector public_point(32); curve25519_basepoint(public_point.data(), m_private.data()); return public_point == m_public; } secure_vector Curve25519_PrivateKey::agree(const uint8_t w[], size_t w_len) const { size_check(w_len, "public value"); return curve25519(m_private, w); } namespace { /** * Curve25519 operation */ class Curve25519_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF { public: Curve25519_KA_Operation(const Curve25519_PrivateKey& key, const std::string& kdf) : PK_Ops::Key_Agreement_with_KDF(kdf), m_key(key) {} size_t agreed_value_size() const override { return 32; } secure_vector raw_agree(const uint8_t w[], size_t w_len) override { return m_key.agree(w, w_len); } private: const Curve25519_PrivateKey& m_key; }; } std::unique_ptr Curve25519_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new Curve25519_KA_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } } /* * Based on curve25519-donna-c64.c from github.com/agl/curve25519-donna * revision 80ad9b9930c9baef5829dd2a235b6b7646d32a8e * * Further changes * (C) 2014,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ /* Copyright 2008, Google Inc. * All rights reserved. * * Code released into the public domain. * * curve25519-donna: Curve25519 elliptic curve, public key function * * https://code.google.com/p/curve25519-donna/ * * Adam Langley * * Derived from public domain C code by Daniel J. Bernstein * * More information about curve25519 can be found here * https://cr.yp.to/ecdh.html * * djb's sample implementation of curve25519 is written in a special assembly * language called qhasm and uses the floating point registers. * * This is, almost, a clean room reimplementation from the curve25519 paper. It * uses many of the tricks described therein. Only the crecip function is taken * from the sample implementation. */ namespace Botan { namespace { #if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) typedef donna128 uint128_t; #endif /* Sum two numbers: output += in */ inline void fsum(uint64_t out[5], const uint64_t in[5]) { out[0] += in[0]; out[1] += in[1]; out[2] += in[2]; out[3] += in[3]; out[4] += in[4]; } /* Find the difference of two numbers: out = in - out * (note the order of the arguments!) * * Assumes that out[i] < 2**52 * On return, out[i] < 2**55 */ inline void fdifference_backwards(uint64_t out[5], const uint64_t in[5]) { /* 152 is 19 << 3 */ const uint64_t two54m152 = (static_cast(1) << 54) - 152; const uint64_t two54m8 = (static_cast(1) << 54) - 8; out[0] = in[0] + two54m152 - out[0]; out[1] = in[1] + two54m8 - out[1]; out[2] = in[2] + two54m8 - out[2]; out[3] = in[3] + two54m8 - out[3]; out[4] = in[4] + two54m8 - out[4]; } inline void fadd_sub(uint64_t x[5], uint64_t y[5]) { // TODO merge these and avoid the tmp array uint64_t tmp[5]; copy_mem(tmp, y, 5); fsum(y, x); fdifference_backwards(x, tmp); // does x - z } /* Multiply a number by a scalar: out = in * scalar */ inline void fscalar_product(uint64_t out[5], const uint64_t in[5], const uint64_t scalar) { uint128_t a = uint128_t(in[0]) * scalar; out[0] = a & 0x7ffffffffffff; a = uint128_t(in[1]) * scalar + carry_shift(a, 51); out[1] = a & 0x7ffffffffffff; a = uint128_t(in[2]) * scalar + carry_shift(a, 51); out[2] = a & 0x7ffffffffffff; a = uint128_t(in[3]) * scalar + carry_shift(a, 51); out[3] = a & 0x7ffffffffffff; a = uint128_t(in[4]) * scalar + carry_shift(a, 51); out[4] = a & 0x7ffffffffffff; out[0] += carry_shift(a, 51) * 19; } /* Multiply two numbers: out = in2 * in * * out must be distinct to both inputs. The inputs are reduced coefficient * form, the output is not. * * Assumes that in[i] < 2**55 and likewise for in2. * On return, out[i] < 2**52 */ inline void fmul(uint64_t out[5], const uint64_t in[5], const uint64_t in2[5]) { const uint128_t s0 = in2[0]; const uint128_t s1 = in2[1]; const uint128_t s2 = in2[2]; const uint128_t s3 = in2[3]; const uint128_t s4 = in2[4]; uint64_t r0 = in[0]; uint64_t r1 = in[1]; uint64_t r2 = in[2]; uint64_t r3 = in[3]; uint64_t r4 = in[4]; uint128_t t0 = r0 * s0; uint128_t t1 = r0 * s1 + r1 * s0; uint128_t t2 = r0 * s2 + r2 * s0 + r1 * s1; uint128_t t3 = r0 * s3 + r3 * s0 + r1 * s2 + r2 * s1; uint128_t t4 = r0 * s4 + r4 * s0 + r3 * s1 + r1 * s3 + r2 * s2; r4 *= 19; r1 *= 19; r2 *= 19; r3 *= 19; t0 += r4 * s1 + r1 * s4 + r2 * s3 + r3 * s2; t1 += r4 * s2 + r2 * s4 + r3 * s3; t2 += r4 * s3 + r3 * s4; t3 += r4 * s4; r0 = t0 & 0x7ffffffffffff; t1 += carry_shift(t0, 51); r1 = t1 & 0x7ffffffffffff; t2 += carry_shift(t1, 51); r2 = t2 & 0x7ffffffffffff; t3 += carry_shift(t2, 51); r3 = t3 & 0x7ffffffffffff; t4 += carry_shift(t3, 51); r4 = t4 & 0x7ffffffffffff; uint64_t c = carry_shift(t4, 51); r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; r2 += c; out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; } inline void fsquare(uint64_t out[5], const uint64_t in[5], size_t count = 1) { uint64_t r0 = in[0]; uint64_t r1 = in[1]; uint64_t r2 = in[2]; uint64_t r3 = in[3]; uint64_t r4 = in[4]; for(size_t i = 0; i != count; ++i) { const uint64_t d0 = r0 * 2; const uint64_t d1 = r1 * 2; const uint64_t d2 = r2 * 2 * 19; const uint64_t d419 = r4 * 19; const uint64_t d4 = d419 * 2; uint128_t t0 = uint128_t(r0) * r0 + uint128_t(d4) * r1 + uint128_t(d2) * (r3 ); uint128_t t1 = uint128_t(d0) * r1 + uint128_t(d4) * r2 + uint128_t(r3) * (r3 * 19); uint128_t t2 = uint128_t(d0) * r2 + uint128_t(r1) * r1 + uint128_t(d4) * (r3 ); uint128_t t3 = uint128_t(d0) * r3 + uint128_t(d1) * r2 + uint128_t(r4) * (d419 ); uint128_t t4 = uint128_t(d0) * r4 + uint128_t(d1) * r3 + uint128_t(r2) * (r2 ); r0 = t0 & 0x7ffffffffffff; t1 += carry_shift(t0, 51); r1 = t1 & 0x7ffffffffffff; t2 += carry_shift(t1, 51); r2 = t2 & 0x7ffffffffffff; t3 += carry_shift(t2, 51); r3 = t3 & 0x7ffffffffffff; t4 += carry_shift(t3, 51); r4 = t4 & 0x7ffffffffffff; uint64_t c = carry_shift(t4, 51); r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; r2 += c; } out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; } /* Take a little-endian, 32-byte number and expand it into polynomial form */ inline void fexpand(uint64_t *out, const uint8_t *in) { out[0] = load_le(in, 0) & 0x7ffffffffffff; out[1] = (load_le(in+6, 0) >> 3) & 0x7ffffffffffff; out[2] = (load_le(in+12, 0) >> 6) & 0x7ffffffffffff; out[3] = (load_le(in+19, 0) >> 1) & 0x7ffffffffffff; out[4] = (load_le(in+24, 0) >> 12) & 0x7ffffffffffff; } /* Take a fully reduced polynomial form number and contract it into a * little-endian, 32-byte array */ inline void fcontract(uint8_t *out, const uint64_t input[5]) { uint128_t t0 = input[0]; uint128_t t1 = input[1]; uint128_t t2 = input[2]; uint128_t t3 = input[3]; uint128_t t4 = input[4]; for(size_t i = 0; i != 2; ++i) { t1 += t0 >> 51; t0 &= 0x7ffffffffffff; t2 += t1 >> 51; t1 &= 0x7ffffffffffff; t3 += t2 >> 51; t2 &= 0x7ffffffffffff; t4 += t3 >> 51; t3 &= 0x7ffffffffffff; t0 += (t4 >> 51) * 19; t4 &= 0x7ffffffffffff; } /* now t is between 0 and 2^255-1, properly carried. */ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ t0 += 19; t1 += t0 >> 51; t0 &= 0x7ffffffffffff; t2 += t1 >> 51; t1 &= 0x7ffffffffffff; t3 += t2 >> 51; t2 &= 0x7ffffffffffff; t4 += t3 >> 51; t3 &= 0x7ffffffffffff; t0 += (t4 >> 51) * 19; t4 &= 0x7ffffffffffff; /* now between 19 and 2^255-1 in both cases, and offset by 19. */ t0 += 0x8000000000000 - 19; t1 += 0x8000000000000 - 1; t2 += 0x8000000000000 - 1; t3 += 0x8000000000000 - 1; t4 += 0x8000000000000 - 1; /* now between 2^255 and 2^256-20, and offset by 2^255. */ t1 += t0 >> 51; t0 &= 0x7ffffffffffff; t2 += t1 >> 51; t1 &= 0x7ffffffffffff; t3 += t2 >> 51; t2 &= 0x7ffffffffffff; t4 += t3 >> 51; t3 &= 0x7ffffffffffff; t4 &= 0x7ffffffffffff; store_le(out, combine_lower(t0, 0, t1, 51), combine_lower(t1, 13, t2, 38), combine_lower(t2, 26, t3, 25), combine_lower(t3, 39, t4, 12)); } /* Input: Q, Q', Q-Q' * Out: 2Q, Q+Q' * * result.two_q (2*Q): long form * result.q_plus_q_dash (Q + Q): long form * in_q: short form, destroyed * in_q_dash: short form, destroyed * in_q_minus_q_dash: short form, preserved */ void fmonty(uint64_t result_two_q_x[5], uint64_t result_two_q_z[5], uint64_t result_q_plus_q_dash_x[5], uint64_t result_q_plus_q_dash_z[5], uint64_t in_q_x[5], uint64_t in_q_z[5], uint64_t in_q_dash_x[5], uint64_t in_q_dash_z[5], const uint64_t q_minus_q_dash[5]) { uint64_t zzz[5]; uint64_t xx[5]; uint64_t zz[5]; uint64_t xxprime[5]; uint64_t zzprime[5]; uint64_t zzzprime[5]; fadd_sub(in_q_z, in_q_x); fadd_sub(in_q_dash_z, in_q_dash_x); fmul(xxprime, in_q_dash_x, in_q_z); fmul(zzprime, in_q_dash_z, in_q_x); fadd_sub(zzprime, xxprime); fsquare(result_q_plus_q_dash_x, xxprime); fsquare(zzzprime, zzprime); fmul(result_q_plus_q_dash_z, zzzprime, q_minus_q_dash); fsquare(xx, in_q_x); fsquare(zz, in_q_z); fmul(result_two_q_x, xx, zz); fdifference_backwards(zz, xx); // does zz = xx - zz fscalar_product(zzz, zz, 121665); fsum(zzz, xx); fmul(result_two_q_z, zz, zzz); } /* * Maybe swap the contents of two uint64_t arrays (@a and @b), * Param @iswap is assumed to be either 0 or 1 * * This function performs the swap without leaking any side-channel * information. */ inline void swap_conditional(uint64_t a[5], uint64_t b[5], uint64_t c[5], uint64_t d[5], uint64_t iswap) { const uint64_t swap = 0 - iswap; for(size_t i = 0; i < 5; ++i) { const uint64_t x0 = swap & (a[i] ^ b[i]); const uint64_t x1 = swap & (c[i] ^ d[i]); a[i] ^= x0; b[i] ^= x0; c[i] ^= x1; d[i] ^= x1; } } /* Calculates nQ where Q is the x-coordinate of a point on the curve * * resultx/resultz: the x/z coordinate of the resulting curve point (short form) * n: a little endian, 32-byte number * q: a point of the curve (short form) */ void cmult(uint64_t resultx[5], uint64_t resultz[5], const uint8_t n[32], const uint64_t q[5]) { uint64_t a[5] = {0}; // nqpqx uint64_t b[5] = {1}; // npqpz uint64_t c[5] = {1}; // nqx uint64_t d[5] = {0}; // nqz uint64_t e[5] = {0}; // npqqx2 uint64_t f[5] = {1}; // npqqz2 uint64_t g[5] = {0}; // nqx2 uint64_t h[5] = {1}; // nqz2 copy_mem(a, q, 5); for(size_t i = 0; i < 32; ++i) { const uint64_t bit0 = (n[31 - i] >> 7) & 1; const uint64_t bit1 = (n[31 - i] >> 6) & 1; const uint64_t bit2 = (n[31 - i] >> 5) & 1; const uint64_t bit3 = (n[31 - i] >> 4) & 1; const uint64_t bit4 = (n[31 - i] >> 3) & 1; const uint64_t bit5 = (n[31 - i] >> 2) & 1; const uint64_t bit6 = (n[31 - i] >> 1) & 1; const uint64_t bit7 = (n[31 - i] >> 0) & 1; swap_conditional(c, a, d, b, bit0); fmonty(g, h, e, f, c, d, a, b, q); swap_conditional(g, e, h, f, bit0 ^ bit1); fmonty(c, d, a, b, g, h, e, f, q); swap_conditional(c, a, d, b, bit1 ^ bit2); fmonty(g, h, e, f, c, d, a, b, q); swap_conditional(g, e, h, f, bit2 ^ bit3); fmonty(c, d, a, b, g, h, e, f, q); swap_conditional(c, a, d, b, bit3 ^ bit4); fmonty(g, h, e, f, c, d, a, b, q); swap_conditional(g, e, h, f, bit4 ^ bit5); fmonty(c, d, a, b, g, h, e, f, q); swap_conditional(c, a, d, b, bit5 ^ bit6); fmonty(g, h, e, f, c, d, a, b, q); swap_conditional(g, e, h, f, bit6 ^ bit7); fmonty(c, d, a, b, g, h, e, f, q); swap_conditional(c, a, d, b, bit7); } copy_mem(resultx, c, 5); copy_mem(resultz, d, 5); } // ----------------------------------------------------------------------------- // Shamelessly copied from djb's code, tightened a little // ----------------------------------------------------------------------------- void crecip(uint64_t out[5], const uint64_t z[5]) { uint64_t a[5]; uint64_t b[5]; uint64_t c[5]; uint64_t t0[5]; fsquare(a, z); // 2 fsquare(t0, a, 2); // 8 fmul(b, t0, z); // 9 fmul(a, b, a); // 11 fsquare(t0, a); // 22 fmul(b, t0, b); // 2^5 - 2^0 = 31 fsquare(t0, b, 5); // 2^10 - 2^5 fmul(b, t0, b); // 2^10 - 2^0 fsquare(t0, b, 10); // 2^20 - 2^10 fmul(c, t0, b); // 2^20 - 2^0 fsquare(t0, c, 20); // 2^40 - 2^20 fmul(t0, t0, c); // 2^40 - 2^0 fsquare(t0, t0, 10); // 2^50 - 2^10 fmul(b, t0, b); // 2^50 - 2^0 fsquare(t0, b, 50); // 2^100 - 2^50 fmul(c, t0, b); // 2^100 - 2^0 fsquare(t0, c, 100); // 2^200 - 2^100 fmul(t0, t0, c); // 2^200 - 2^0 fsquare(t0, t0, 50); // 2^250 - 2^50 fmul(t0, t0, b); // 2^250 - 2^0 fsquare(t0, t0, 5); // 2^255 - 2^5 fmul(out, t0, a); // 2^255 - 21 } } void curve25519_donna(uint8_t mypublic[32], const uint8_t secret[32], const uint8_t basepoint[32]) { CT::poison(secret, 32); CT::poison(basepoint, 32); uint64_t bp[5], x[5], z[5], zmone[5]; uint8_t e[32]; copy_mem(e, secret, 32); e[ 0] &= 248; e[31] &= 127; e[31] |= 64; fexpand(bp, basepoint); cmult(x, z, e, bp); crecip(zmone, z); fmul(z, x, zmone); fcontract(mypublic, z); CT::unpoison(secret, 32); CT::unpoison(basepoint, 32); CT::unpoison(mypublic, 32); } } /* * DES * (C) 1999-2008,2018 Jack Lloyd * * Based on a public domain implemenation by Phil Karn (who in turn * credited Richard Outerbridge and Jim Gillogly) * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * DES Key Schedule */ void des_key_schedule(uint32_t round_key[32], const uint8_t key[8]) { static const uint8_t ROT[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; uint32_t C = ((key[7] & 0x80) << 20) | ((key[6] & 0x80) << 19) | ((key[5] & 0x80) << 18) | ((key[4] & 0x80) << 17) | ((key[3] & 0x80) << 16) | ((key[2] & 0x80) << 15) | ((key[1] & 0x80) << 14) | ((key[0] & 0x80) << 13) | ((key[7] & 0x40) << 13) | ((key[6] & 0x40) << 12) | ((key[5] & 0x40) << 11) | ((key[4] & 0x40) << 10) | ((key[3] & 0x40) << 9) | ((key[2] & 0x40) << 8) | ((key[1] & 0x40) << 7) | ((key[0] & 0x40) << 6) | ((key[7] & 0x20) << 6) | ((key[6] & 0x20) << 5) | ((key[5] & 0x20) << 4) | ((key[4] & 0x20) << 3) | ((key[3] & 0x20) << 2) | ((key[2] & 0x20) << 1) | ((key[1] & 0x20) ) | ((key[0] & 0x20) >> 1) | ((key[7] & 0x10) >> 1) | ((key[6] & 0x10) >> 2) | ((key[5] & 0x10) >> 3) | ((key[4] & 0x10) >> 4); uint32_t D = ((key[7] & 0x02) << 26) | ((key[6] & 0x02) << 25) | ((key[5] & 0x02) << 24) | ((key[4] & 0x02) << 23) | ((key[3] & 0x02) << 22) | ((key[2] & 0x02) << 21) | ((key[1] & 0x02) << 20) | ((key[0] & 0x02) << 19) | ((key[7] & 0x04) << 17) | ((key[6] & 0x04) << 16) | ((key[5] & 0x04) << 15) | ((key[4] & 0x04) << 14) | ((key[3] & 0x04) << 13) | ((key[2] & 0x04) << 12) | ((key[1] & 0x04) << 11) | ((key[0] & 0x04) << 10) | ((key[7] & 0x08) << 8) | ((key[6] & 0x08) << 7) | ((key[5] & 0x08) << 6) | ((key[4] & 0x08) << 5) | ((key[3] & 0x08) << 4) | ((key[2] & 0x08) << 3) | ((key[1] & 0x08) << 2) | ((key[0] & 0x08) << 1) | ((key[3] & 0x10) >> 1) | ((key[2] & 0x10) >> 2) | ((key[1] & 0x10) >> 3) | ((key[0] & 0x10) >> 4); for(size_t i = 0; i != 16; ++i) { C = ((C << ROT[i]) | (C >> (28-ROT[i]))) & 0x0FFFFFFF; D = ((D << ROT[i]) | (D >> (28-ROT[i]))) & 0x0FFFFFFF; round_key[2*i ] = ((C & 0x00000010) << 22) | ((C & 0x00000800) << 17) | ((C & 0x00000020) << 16) | ((C & 0x00004004) << 15) | ((C & 0x00000200) << 11) | ((C & 0x00020000) << 10) | ((C & 0x01000000) >> 6) | ((C & 0x00100000) >> 4) | ((C & 0x00010000) << 3) | ((C & 0x08000000) >> 2) | ((C & 0x00800000) << 1) | ((D & 0x00000010) << 8) | ((D & 0x00000002) << 7) | ((D & 0x00000001) << 2) | ((D & 0x00000200) ) | ((D & 0x00008000) >> 2) | ((D & 0x00000088) >> 3) | ((D & 0x00001000) >> 7) | ((D & 0x00080000) >> 9) | ((D & 0x02020000) >> 14) | ((D & 0x00400000) >> 21); round_key[2*i+1] = ((C & 0x00000001) << 28) | ((C & 0x00000082) << 18) | ((C & 0x00002000) << 14) | ((C & 0x00000100) << 10) | ((C & 0x00001000) << 9) | ((C & 0x00040000) << 6) | ((C & 0x02400000) << 4) | ((C & 0x00008000) << 2) | ((C & 0x00200000) >> 1) | ((C & 0x04000000) >> 10) | ((D & 0x00000020) << 6) | ((D & 0x00000100) ) | ((D & 0x00000800) >> 1) | ((D & 0x00000040) >> 3) | ((D & 0x00010000) >> 4) | ((D & 0x00000400) >> 5) | ((D & 0x00004000) >> 10) | ((D & 0x04000000) >> 13) | ((D & 0x00800000) >> 14) | ((D & 0x00100000) >> 18) | ((D & 0x01000000) >> 24) | ((D & 0x08000000) >> 26); } } inline uint32_t spbox(uint32_t T0, uint32_t T1) { return DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; } /* * DES Encryption */ inline void des_encrypt(uint32_t& Lr, uint32_t& Rr, const uint32_t round_key[32]) { uint32_t L = Lr; uint32_t R = Rr; for(size_t i = 0; i != 16; i += 2) { L ^= spbox(rotr<4>(R) ^ round_key[2*i ], R ^ round_key[2*i+1]); R ^= spbox(rotr<4>(L) ^ round_key[2*i+2], L ^ round_key[2*i+3]); } Lr = L; Rr = R; } inline void des_encrypt_x2(uint32_t& L0r, uint32_t& R0r, uint32_t& L1r, uint32_t& R1r, const uint32_t round_key[32]) { uint32_t L0 = L0r; uint32_t R0 = R0r; uint32_t L1 = L1r; uint32_t R1 = R1r; for(size_t i = 0; i != 16; i += 2) { L0 ^= spbox(rotr<4>(R0) ^ round_key[2*i ], R0 ^ round_key[2*i+1]); L1 ^= spbox(rotr<4>(R1) ^ round_key[2*i ], R1 ^ round_key[2*i+1]); R0 ^= spbox(rotr<4>(L0) ^ round_key[2*i+2], L0 ^ round_key[2*i+3]); R1 ^= spbox(rotr<4>(L1) ^ round_key[2*i+2], L1 ^ round_key[2*i+3]); } L0r = L0; R0r = R0; L1r = L1; R1r = R1; } /* * DES Decryption */ inline void des_decrypt(uint32_t& Lr, uint32_t& Rr, const uint32_t round_key[32]) { uint32_t L = Lr; uint32_t R = Rr; for(size_t i = 16; i != 0; i -= 2) { L ^= spbox(rotr<4>(R) ^ round_key[2*i - 2], R ^ round_key[2*i - 1]); R ^= spbox(rotr<4>(L) ^ round_key[2*i - 4], L ^ round_key[2*i - 3]); } Lr = L; Rr = R; } inline void des_decrypt_x2(uint32_t& L0r, uint32_t& R0r, uint32_t& L1r, uint32_t& R1r, const uint32_t round_key[32]) { uint32_t L0 = L0r; uint32_t R0 = R0r; uint32_t L1 = L1r; uint32_t R1 = R1r; for(size_t i = 16; i != 0; i -= 2) { L0 ^= spbox(rotr<4>(R0) ^ round_key[2*i - 2], R0 ^ round_key[2*i - 1]); L1 ^= spbox(rotr<4>(R1) ^ round_key[2*i - 2], R1 ^ round_key[2*i - 1]); R0 ^= spbox(rotr<4>(L0) ^ round_key[2*i - 4], L0 ^ round_key[2*i - 3]); R1 ^= spbox(rotr<4>(L1) ^ round_key[2*i - 4], L1 ^ round_key[2*i - 3]); } L0r = L0; R0r = R0; L1r = L1; R1r = R1; } inline void des_IP(uint32_t& L, uint32_t& R, const uint8_t block[]) { // IP sequence by Wei Dai, taken from public domain Crypto++ L = load_be(block, 0); R = load_be(block, 1); uint32_t T; R = rotl<4>(R); T = (L ^ R) & 0xF0F0F0F0; L ^= T; R = rotr<20>(R ^ T); T = (L ^ R) & 0xFFFF0000; L ^= T; R = rotr<18>(R ^ T); T = (L ^ R) & 0x33333333; L ^= T; R = rotr<6>(R ^ T); T = (L ^ R) & 0x00FF00FF; L ^= T; R = rotl<9>(R ^ T); T = (L ^ R) & 0xAAAAAAAA; L = rotl<1>(L ^ T); R ^= T; } inline void des_FP(uint32_t L, uint32_t R, uint8_t out[]) { // FP sequence by Wei Dai, taken from public domain Crypto++ uint32_t T; R = rotr<1>(R); T = (L ^ R) & 0xAAAAAAAA; R ^= T; L = rotr<9>(L ^ T); T = (L ^ R) & 0x00FF00FF; R ^= T; L = rotl<6>(L ^ T); T = (L ^ R) & 0x33333333; R ^= T; L = rotl<18>(L ^ T); T = (L ^ R) & 0xFFFF0000; R ^= T; L = rotl<20>(L ^ T); T = (L ^ R) & 0xF0F0F0F0; R ^= T; L = rotr<4>(L ^ T); store_be(out, R, L); } } /* * DES Encryption */ void DES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_round_key.empty() == false); while(blocks >= 2) { uint32_t L0, R0; uint32_t L1, R1; des_IP(L0, R0, in); des_IP(L1, R1, in + BLOCK_SIZE); des_encrypt_x2(L0, R0, L1, R1, m_round_key.data()); des_FP(L0, R0, out); des_FP(L1, R1, out + BLOCK_SIZE); in += 2*BLOCK_SIZE; out += 2*BLOCK_SIZE; blocks -= 2; } for(size_t i = 0; i < blocks; ++i) { uint32_t L, R; des_IP(L, R, in + BLOCK_SIZE*i); des_encrypt(L, R, m_round_key.data()); des_FP(L, R, out + BLOCK_SIZE*i); } } /* * DES Decryption */ void DES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_round_key.empty() == false); while(blocks >= 2) { uint32_t L0, R0; uint32_t L1, R1; des_IP(L0, R0, in); des_IP(L1, R1, in + BLOCK_SIZE); des_decrypt_x2(L0, R0, L1, R1, m_round_key.data()); des_FP(L0, R0, out); des_FP(L1, R1, out + BLOCK_SIZE); in += 2*BLOCK_SIZE; out += 2*BLOCK_SIZE; blocks -= 2; } for(size_t i = 0; i < blocks; ++i) { uint32_t L, R; des_IP(L, R, in + BLOCK_SIZE*i); des_decrypt(L, R, m_round_key.data()); des_FP(L, R, out + BLOCK_SIZE*i); } } /* * DES Key Schedule */ void DES::key_schedule(const uint8_t key[], size_t) { m_round_key.resize(32); des_key_schedule(m_round_key.data(), key); } void DES::clear() { zap(m_round_key); } /* * TripleDES Encryption */ void TripleDES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_round_key.empty() == false); while(blocks >= 2) { uint32_t L0, R0; uint32_t L1, R1; des_IP(L0, R0, in); des_IP(L1, R1, in + BLOCK_SIZE); des_encrypt_x2(L0, R0, L1, R1, &m_round_key[0]); des_decrypt_x2(R0, L0, R1, L1, &m_round_key[32]); des_encrypt_x2(L0, R0, L1, R1, &m_round_key[64]); des_FP(L0, R0, out); des_FP(L1, R1, out + BLOCK_SIZE); in += 2*BLOCK_SIZE; out += 2*BLOCK_SIZE; blocks -= 2; } for(size_t i = 0; i != blocks; ++i) { uint32_t L, R; des_IP(L, R, in + BLOCK_SIZE*i); des_encrypt(L, R, &m_round_key[0]); des_decrypt(R, L, &m_round_key[32]); des_encrypt(L, R, &m_round_key[64]); des_FP(L, R, out + BLOCK_SIZE*i); } } /* * TripleDES Decryption */ void TripleDES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_round_key.empty() == false); while(blocks >= 2) { uint32_t L0, R0; uint32_t L1, R1; des_IP(L0, R0, in); des_IP(L1, R1, in + BLOCK_SIZE); des_decrypt_x2(L0, R0, L1, R1, &m_round_key[64]); des_encrypt_x2(R0, L0, R1, L1, &m_round_key[32]); des_decrypt_x2(L0, R0, L1, R1, &m_round_key[0]); des_FP(L0, R0, out); des_FP(L1, R1, out + BLOCK_SIZE); in += 2*BLOCK_SIZE; out += 2*BLOCK_SIZE; blocks -= 2; } for(size_t i = 0; i != blocks; ++i) { uint32_t L, R; des_IP(L, R, in + BLOCK_SIZE*i); des_decrypt(L, R, &m_round_key[64]); des_encrypt(R, L, &m_round_key[32]); des_decrypt(L, R, &m_round_key[0]); des_FP(L, R, out + BLOCK_SIZE*i); } } /* * TripleDES Key Schedule */ void TripleDES::key_schedule(const uint8_t key[], size_t length) { m_round_key.resize(3*32); des_key_schedule(&m_round_key[0], key); des_key_schedule(&m_round_key[32], key + 8); if(length == 24) des_key_schedule(&m_round_key[64], key + 16); else copy_mem(&m_round_key[64], &m_round_key[0], 32); } void TripleDES::clear() { zap(m_round_key); } } /* * Substitution/Permutation Tables for DES * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { alignas(64) const uint32_t DES_SPBOX1[256] = { 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; alignas(64) const uint32_t DES_SPBOX2[256] = { 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; alignas(64) const uint32_t DES_SPBOX3[256] = { 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; alignas(64) const uint32_t DES_SPBOX4[256] = { 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; alignas(64) const uint32_t DES_SPBOX5[256] = { 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; alignas(64) const uint32_t DES_SPBOX6[256] = { 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; alignas(64) const uint32_t DES_SPBOX7[256] = { 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; alignas(64) const uint32_t DES_SPBOX8[256] = { 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; } /* * DES * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * DESX Encryption */ void DESX::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_K1.empty() == false); for(size_t i = 0; i != blocks; ++i) { xor_buf(out, in, m_K1.data(), BLOCK_SIZE); m_des.encrypt(out); xor_buf(out, m_K2.data(), BLOCK_SIZE); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * DESX Decryption */ void DESX::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_K1.empty() == false); for(size_t i = 0; i != blocks; ++i) { xor_buf(out, in, m_K2.data(), BLOCK_SIZE); m_des.decrypt(out); xor_buf(out, m_K1.data(), BLOCK_SIZE); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * DESX Key Schedule */ void DESX::key_schedule(const uint8_t key[], size_t) { m_K1.assign(key, key + 8); m_des.set_key(key + 8, 8); m_K2.assign(key + 16, key + 24); } void DESX::clear() { m_des.clear(); zap(m_K1); zap(m_K2); } } /* * Diffie-Hellman * (C) 1999-2007,2016,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * DH_PublicKey Constructor */ DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) { m_group = grp; m_y = y1; } /* * Return the public value for key agreement */ std::vector DH_PublicKey::public_value() const { return unlock(BigInt::encode_1363(m_y, group_p().bytes())); } /* * Create a DH private key */ DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, const BigInt& x_arg) { m_group = grp; if(x_arg == 0) { const size_t exp_bits = grp.exponent_bits(); m_x.randomize(rng, exp_bits); m_y = m_group.power_g_p(m_x, exp_bits); } else { m_x = x_arg; if(m_y == 0) m_y = m_group.power_g_p(m_x, grp.p_bits()); } } /* * Load a DH private key */ DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits) : DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) { if(m_y.is_zero()) { m_y = m_group.power_g_p(m_x, m_group.p_bits()); } } /* * Return the public value for key agreement */ std::vector DH_PrivateKey::public_value() const { return DH_PublicKey::public_value(); } namespace { /** * DH operation */ class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF { public: DH_KA_Operation(const DH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : PK_Ops::Key_Agreement_with_KDF(kdf), m_p(key.group_p()), m_x(key.get_x()), m_x_bits(m_x.bits()), m_monty_p(key.get_group().monty_params_p()), m_blinder(m_p, rng, [](const BigInt& k) { return k; }, [this](const BigInt& k) { return powermod_x_p(inverse_mod(k, m_p)); }) {} size_t agreed_value_size() const override { return m_p.bytes(); } secure_vector raw_agree(const uint8_t w[], size_t w_len) override; private: BigInt powermod_x_p(const BigInt& v) const { const size_t powm_window = 4; auto powm_v_p = monty_precompute(m_monty_p, v, powm_window); return monty_execute(*powm_v_p, m_x, m_x_bits); } const BigInt& m_p; const BigInt& m_x; const size_t m_x_bits; std::shared_ptr m_monty_p; Blinder m_blinder; }; secure_vector DH_KA_Operation::raw_agree(const uint8_t w[], size_t w_len) { BigInt v = BigInt::decode(w, w_len); if(v <= 1 || v >= m_p - 1) throw Invalid_Argument("DH agreement - invalid key provided"); v = m_blinder.blind(v); v = powermod_x_p(v); v = m_blinder.unblind(v); return BigInt::encode_1363(v, m_p.bytes()); } } std::unique_ptr DH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new DH_KA_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } } /* * DL Scheme * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t DL_Scheme_PublicKey::key_length() const { return m_group.p_bits(); } size_t DL_Scheme_PublicKey::estimated_strength() const { return m_group.estimated_strength(); } AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), m_group.DER_encode(group_format())); } std::vector DL_Scheme_PublicKey::public_key_bits() const { std::vector output; DER_Encoder(output).encode(m_y); return output; } DL_Scheme_PublicKey::DL_Scheme_PublicKey(const DL_Group& group, const BigInt& y) : m_y(y), m_group(group) { } DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, const std::vector& key_bits, DL_Group::Format format) : m_group(alg_id.get_parameters(), format) { BER_Decoder(key_bits).decode(m_y); } secure_vector DL_Scheme_PrivateKey::private_key_bits() const { return DER_Encoder().encode(m_x).get_contents(); } DL_Scheme_PrivateKey::DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits, DL_Group::Format format) { m_group.BER_decode(alg_id.get_parameters(), format); BER_Decoder(key_bits).decode(m_x); } /* * Check Public DL Parameters */ bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng, bool strong) const { return m_group.verify_group(rng, strong) && m_group.verify_public_element(m_y); } /* * Check DL Scheme Private Parameters */ bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { return m_group.verify_group(rng, strong) && m_group.verify_element_pair(m_y, m_x); } } /* * Discrete Logarithm Parameters * (C) 1999-2008,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { class DL_Group_Data final { public: DL_Group_Data(const BigInt& p, const BigInt& q, const BigInt& g, DL_Group_Source source) : m_p(p), m_q(q), m_g(g), m_mod_p(p), m_mod_q(q), m_monty_params(std::make_shared(m_p, m_mod_p)), m_monty(monty_precompute(m_monty_params, m_g, /*window bits=*/4)), m_p_bits(p.bits()), m_q_bits(q.bits()), m_estimated_strength(dl_work_factor(m_p_bits)), m_exponent_bits(dl_exponent_size(m_p_bits)), m_source(source) { } ~DL_Group_Data() = default; DL_Group_Data(const DL_Group_Data& other) = delete; DL_Group_Data& operator=(const DL_Group_Data& other) = delete; const BigInt& p() const { return m_p; } const BigInt& q() const { return m_q; } const BigInt& g() const { return m_g; } BigInt mod_p(const BigInt& x) const { return m_mod_p.reduce(x); } BigInt multiply_mod_p(const BigInt& x, const BigInt& y) const { return m_mod_p.multiply(x, y); } BigInt mod_q(const BigInt& x) const { return m_mod_q.reduce(x); } BigInt multiply_mod_q(const BigInt& x, const BigInt& y) const { return m_mod_q.multiply(x, y); } BigInt square_mod_q(const BigInt& x) const { return m_mod_q.square(x); } std::shared_ptr monty_params_p() const { return m_monty_params; } size_t p_bits() const { return m_p_bits; } size_t q_bits() const { return m_q_bits; } size_t p_bytes() const { return (m_p_bits + 7) / 8; } size_t q_bytes() const { return (m_q_bits + 7) / 8; } size_t estimated_strength() const { return m_estimated_strength; } size_t exponent_bits() const { return m_exponent_bits; } BigInt power_g_p(const BigInt& k, size_t max_k_bits) const { return monty_execute(*m_monty, k, max_k_bits); } bool q_is_set() const { return m_q_bits > 0; } void assert_q_is_set(const std::string& function) const { if(q_is_set() == false) throw Invalid_State("DL_Group::" + function + " q is not set for this group"); } DL_Group_Source source() const { return m_source; } private: BigInt m_p; BigInt m_q; BigInt m_g; Modular_Reducer m_mod_p; Modular_Reducer m_mod_q; std::shared_ptr m_monty_params; std::shared_ptr m_monty; size_t m_p_bits; size_t m_q_bits; size_t m_estimated_strength; size_t m_exponent_bits; DL_Group_Source m_source; }; //static std::shared_ptr DL_Group::BER_decode_DL_group(const uint8_t data[], size_t data_len, DL_Group::Format format, DL_Group_Source source) { BigInt p, q, g; BER_Decoder decoder(data, data_len); BER_Decoder ber = decoder.start_cons(SEQUENCE); if(format == DL_Group::ANSI_X9_57) { ber.decode(p) .decode(q) .decode(g) .verify_end(); } else if(format == DL_Group::ANSI_X9_42) { ber.decode(p) .decode(g) .decode(q) .discard_remaining(); } else if(format == DL_Group::PKCS_3) { // q is left as zero ber.decode(p) .decode(g) .discard_remaining(); } else throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); return std::make_shared(p, q, g, source); } //static std::shared_ptr DL_Group::load_DL_group_info(const char* p_str, const char* q_str, const char* g_str) { const BigInt p(p_str); const BigInt q(q_str); const BigInt g(g_str); return std::make_shared(p, q, g, DL_Group_Source::Builtin); } //static std::shared_ptr DL_Group::load_DL_group_info(const char* p_str, const char* g_str) { const BigInt p(p_str); const BigInt q = (p - 1) / 2; const BigInt g(g_str); return std::make_shared(p, q, g, DL_Group_Source::Builtin); } namespace { DL_Group::Format pem_label_to_dl_format(const std::string& label) { if(label == "DH PARAMETERS") return DL_Group::PKCS_3; else if(label == "DSA PARAMETERS") return DL_Group::ANSI_X9_57; else if(label == "X942 DH PARAMETERS" || label == "X9.42 DH PARAMETERS") return DL_Group::ANSI_X9_42; else throw Decoding_Error("DL_Group: Invalid PEM label " + label); } } /* * DL_Group Constructor */ DL_Group::DL_Group(const std::string& str) { // Either a name or a PEM block, try name first m_data = DL_group_info(str); if(m_data == nullptr) { try { std::string label; const std::vector ber = unlock(PEM_Code::decode(str, label)); Format format = pem_label_to_dl_format(label); m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource); } catch(...) {} } if(m_data == nullptr) throw Invalid_Argument("DL_Group: Unknown group " + str); } namespace { /* * Create generator of the q-sized subgroup (DSA style generator) */ BigInt make_dsa_generator(const BigInt& p, const BigInt& q) { BigInt e, r; vartime_divide(p - 1, q, e, r); if(e == 0 || r > 0) throw Invalid_Argument("make_dsa_generator q does not divide p-1"); for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) { // TODO precompute! BigInt g = power_mod(PRIMES[i], e, p); if(g > 1) return g; } throw Internal_Error("DL_Group: Couldn't create a suitable generator"); } } /* * DL_Group Constructor */ DL_Group::DL_Group(RandomNumberGenerator& rng, PrimeType type, size_t pbits, size_t qbits) { if(pbits < 1024) throw Invalid_Argument("DL_Group: prime size " + std::to_string(pbits) + " is too small"); if(type == Strong) { if(qbits != 0 && qbits != pbits - 1) throw Invalid_Argument("Cannot create strong-prime DL_Group with specified q bits"); const BigInt p = random_safe_prime(rng, pbits); const BigInt q = (p - 1) / 2; /* Always choose a generator that is quadratic reside mod p, this forces g to be a generator of the subgroup of size q. */ BigInt g = 2; if(jacobi(g, p) != 1) { // prime table does not contain 2 for(size_t i = 0; i < PRIME_TABLE_SIZE; ++i) { g = PRIMES[i]; if(jacobi(g, p) == 1) break; } } m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); } else if(type == Prime_Subgroup) { if(qbits == 0) qbits = dl_exponent_size(pbits); const BigInt q = random_prime(rng, qbits); Modular_Reducer mod_2q(2*q); BigInt X; BigInt p; while(p.bits() != pbits || !is_prime(p, rng, 128, true)) { X.randomize(rng, pbits); p = X - mod_2q.reduce(X) + 1; } const BigInt g = make_dsa_generator(p, q); m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); } else if(type == DSA_Kosherizer) { if(qbits == 0) qbits = ((pbits <= 1024) ? 160 : 256); BigInt p, q; generate_dsa_primes(rng, p, q, pbits, qbits); const BigInt g = make_dsa_generator(p, q); m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); } else { throw Invalid_Argument("DL_Group unknown PrimeType"); } } /* * DL_Group Constructor */ DL_Group::DL_Group(RandomNumberGenerator& rng, const std::vector& seed, size_t pbits, size_t qbits) { BigInt p, q; if(!generate_dsa_primes(rng, p, q, pbits, qbits, seed)) throw Invalid_Argument("DL_Group: The seed given does not generate a DSA group"); BigInt g = make_dsa_generator(p, q); m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); } /* * DL_Group Constructor */ DL_Group::DL_Group(const BigInt& p, const BigInt& g) { m_data = std::make_shared(p, 0, g, DL_Group_Source::ExternalSource); } /* * DL_Group Constructor */ DL_Group::DL_Group(const BigInt& p, const BigInt& q, const BigInt& g) { m_data = std::make_shared(p, q, g, DL_Group_Source::ExternalSource); } const DL_Group_Data& DL_Group::data() const { if(m_data) return *m_data; throw Invalid_State("DL_Group uninitialized"); } bool DL_Group::verify_public_element(const BigInt& y) const { const BigInt& p = get_p(); const BigInt& q = get_q(); if(y <= 1 || y >= p) return false; if(q.is_zero() == false) { if(power_mod(y, q, p) != 1) return false; } return true; } bool DL_Group::verify_element_pair(const BigInt& y, const BigInt& x) const { const BigInt& p = get_p(); if(y <= 1 || y >= p || x <= 1 || x >= p) return false; if(y != power_g_p(x)) return false; return true; } /* * Verify the parameters */ bool DL_Group::verify_group(RandomNumberGenerator& rng, bool strong) const { const bool from_builtin = (source() == DL_Group_Source::Builtin); if(!strong && from_builtin) return true; const BigInt& p = get_p(); const BigInt& q = get_q(); const BigInt& g = get_g(); if(g < 2 || p < 3 || q < 0) return false; const size_t test_prob = 128; const bool is_randomly_generated = (source() != DL_Group_Source::ExternalSource); if(q != 0) { if((p - 1) % q != 0) { return false; } if(this->power_g_p(q) != 1) { return false; } if(!is_prime(q, rng, test_prob, is_randomly_generated)) { return false; } } if(!is_prime(p, rng, test_prob, is_randomly_generated)) { return false; } return true; } /* * Return the prime */ const BigInt& DL_Group::get_p() const { return data().p(); } /* * Return the generator */ const BigInt& DL_Group::get_g() const { return data().g(); } /* * Return the subgroup */ const BigInt& DL_Group::get_q() const { return data().q(); } std::shared_ptr DL_Group::monty_params_p() const { return data().monty_params_p(); } size_t DL_Group::p_bits() const { return data().p_bits(); } size_t DL_Group::p_bytes() const { return data().p_bytes(); } size_t DL_Group::q_bits() const { data().assert_q_is_set("q_bits"); return data().q_bits(); } size_t DL_Group::q_bytes() const { data().assert_q_is_set("q_bytes"); return data().q_bytes(); } size_t DL_Group::estimated_strength() const { return data().estimated_strength(); } size_t DL_Group::exponent_bits() const { return data().exponent_bits(); } BigInt DL_Group::inverse_mod_p(const BigInt& x) const { // precompute?? return inverse_mod(x, get_p()); } BigInt DL_Group::mod_p(const BigInt& x) const { return data().mod_p(x); } BigInt DL_Group::multiply_mod_p(const BigInt& x, const BigInt& y) const { return data().multiply_mod_p(x, y); } BigInt DL_Group::inverse_mod_q(const BigInt& x) const { data().assert_q_is_set("inverse_mod_q"); // precompute?? return inverse_mod(x, get_q()); } BigInt DL_Group::mod_q(const BigInt& x) const { data().assert_q_is_set("mod_q"); return data().mod_q(x); } BigInt DL_Group::multiply_mod_q(const BigInt& x, const BigInt& y) const { data().assert_q_is_set("multiply_mod_q"); return data().multiply_mod_q(x, y); } BigInt DL_Group::multiply_mod_q(const BigInt& x, const BigInt& y, const BigInt& z) const { data().assert_q_is_set("multiply_mod_q"); return data().multiply_mod_q(data().multiply_mod_q(x, y), z); } BigInt DL_Group::square_mod_q(const BigInt& x) const { data().assert_q_is_set("square_mod_q"); return data().square_mod_q(x); } BigInt DL_Group::multi_exponentiate(const BigInt& x, const BigInt& y, const BigInt& z) const { return monty_multi_exp(data().monty_params_p(), get_g(), x, y, z); } BigInt DL_Group::power_g_p(const BigInt& x) const { return data().power_g_p(x, x.bits()); } BigInt DL_Group::power_g_p(const BigInt& x, size_t max_x_bits) const { return data().power_g_p(x, max_x_bits); } DL_Group_Source DL_Group::source() const { return data().source(); } /* * DER encode the parameters */ std::vector DL_Group::DER_encode(Format format) const { if(get_q().is_zero() && (format == ANSI_X9_57 || format == ANSI_X9_42)) throw Encoding_Error("Cannot encode DL_Group in ANSI formats when q param is missing"); std::vector output; DER_Encoder der(output); if(format == ANSI_X9_57) { der.start_cons(SEQUENCE) .encode(get_p()) .encode(get_q()) .encode(get_g()) .end_cons(); } else if(format == ANSI_X9_42) { der.start_cons(SEQUENCE) .encode(get_p()) .encode(get_g()) .encode(get_q()) .end_cons(); } else if(format == PKCS_3) { der.start_cons(SEQUENCE) .encode(get_p()) .encode(get_g()) .end_cons(); } else throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); return output; } /* * PEM encode the parameters */ std::string DL_Group::PEM_encode(Format format) const { const std::vector encoding = DER_encode(format); if(format == PKCS_3) return PEM_Code::encode(encoding, "DH PARAMETERS"); else if(format == ANSI_X9_57) return PEM_Code::encode(encoding, "DSA PARAMETERS"); else if(format == ANSI_X9_42) return PEM_Code::encode(encoding, "X9.42 DH PARAMETERS"); else throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); } DL_Group::DL_Group(const uint8_t ber[], size_t ber_len, Format format) { m_data = BER_decode_DL_group(ber, ber_len, format, DL_Group_Source::ExternalSource); } void DL_Group::BER_decode(const std::vector& ber, Format format) { m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource); } //static DL_Group DL_Group::DL_Group_from_PEM(const std::string& pem) { std::string label; const std::vector ber = unlock(PEM_Code::decode(pem, label)); Format format = pem_label_to_dl_format(label); return DL_Group(ber, format); } /* * Decode PEM encoded parameters */ void DL_Group::PEM_decode(const std::string& pem) { std::string label; const std::vector ber = unlock(PEM_Code::decode(pem, label)); Format format = pem_label_to_dl_format(label); m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource); } //static std::string DL_Group::PEM_for_named_group(const std::string& name) { DL_Group group(name); DL_Group::Format format = group.get_q().is_zero() ? DL_Group::PKCS_3 : DL_Group::ANSI_X9_42; return group.PEM_encode(format); } } /* * List of discrete log groups * (C) 2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { //static std::shared_ptr DL_Group::DL_group_info(const std::string& name) { /* TLS FFDHE groups */ if(name == "ffdhe/ietf/2048") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF", "0x2"); } if(name == "ffdhe/ietf/3072") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", "0x2"); } if(name == "ffdhe/ietf/4096") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6AFFFFFFFFFFFFFFFF", "0x2"); } if(name == "ffdhe/ietf/6144") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", "0x2"); } if(name == "ffdhe/ietf/8192") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C8381E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665CB2C0F1CC01BD70229388839D2AF05E454504AC78B7582822846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA4571EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88CD68C8BB7C5C6424CFFFFFFFFFFFFFFFF", "0x2"); } /* IETF IPsec groups */ if(name == "modp/ietf/1024") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", "0x2"); } if(name == "modp/ietf/1536") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", "0x2"); } if(name == "modp/ietf/2048") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", "0x2"); } if(name == "modp/ietf/3072") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", "0x2"); } if(name == "modp/ietf/4096") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", "0x2"); } if(name == "modp/ietf/6144") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", "0x2"); } if(name == "modp/ietf/8192") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", "0x2"); } /* SRP groups SRP groups have a p st (p-1)/2 is prime, but g is not a generator of subgroup of size q, so set q == 0 to bypass generator check Missing q doesn't matter for SRP, and nothing but SRP should be using these parameters. */ if(name == "modp/srp/1024") { return load_DL_group_info("0xEEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", "0", "0x2"); } if(name == "modp/srp/1536") { return load_DL_group_info("0x9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", "0", "0x2"); } if(name == "modp/srp/2048") { return load_DL_group_info("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", "0", "0x2"); } if(name == "modp/srp/3072") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", "0", "0x5"); } if(name == "modp/srp/4096") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", "0", "0x5"); } if(name == "modp/srp/6144") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", "0", "0x5"); } if(name == "modp/srp/8192") { return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", "0", "0x13"); } /* DSA groups */ if(name == "dsa/jce/1024") { return load_DL_group_info("0xFD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB593D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC3023554135A169132F675F3AE2B61D72AEFF22203199DD14801C7", "0x9760508F15230BCCB292B982A2EB840BF0581CF5", "0x469603512E30278CD3947595DB22EEC9826A6322ADC97344F41D740C325724C8F9EFBAA7D4D803FF8C609DCD100EBC5BDFCFAD7C6A425FAEA786EA2050EBE98351EA1FDA1FDF24D6947AA6B9AA23766953802F4D7D4A8ECBA06D19768A2491FFB16D0EF9C43A99B5F71672FF6F0A24B444D0736D04D38A1A1322DAF6CDD88C9D"); } if(name == "dsa/botan/2048") { return load_DL_group_info("0x91C48A4FDFBCF7C02AE95E7DA126122B5DD2864F559B87E8E74A286D52F59BD1DE68DFD645D0E00C60C080031891980374EEB594A532BFD67B9A09EAC4B8663A07910E68F39465FB7040D25DF13932EBAC4347A530ECBA61C854F9B880D3C0C3660080587C45566DADE26BD5A394BE093B4C0F24B5AFFEF8EC6C5B3E57FB89025A9BC16769932131E16D3C94EFCAB18D0DF061203CC53E6103BC72D5594BFD40CA65380F44A9A851DCB075495FC033A8A58071A1BD78FE052F66555648EB4B719D2AFE8B4880F8DAD6F15818BA178F89274C870BE9B96EB08C46C40040CC2EFE1DFB1B1868DD319DE3C34A32A63AB6EB1224209A419680CC7902D1728D4DF9E1", "0x8CD7D450F86F0AD94EEE4CE469A8756D1EBD1058241943EAFFB0B354585E924D", "0xD9F5E0761B4DBD1833D6AB1A961A0996C5F22303F72D84C140F67C431D94AB5715BEA81A0C98D39CE4BCF78D6B9EBC895D34FE89D94091D5848615EF15F5E86F11D96F6C969E203DDFA58356420A49CB444B595B901A933CFE0767B594F18A07B7F91DECDBA446B88990F78F2FF91F2FE7CD43FD2E46D18EADA1F7BB6602C617F6EF3A4B284F2FD9BA10A36042DE8FA87A2CA36597FEC81157A1485E44041DF02830111CB880BBE6ED494814886F965CDC3135F5CCF1383728BF65B806F9692C0B10D6C4C09C75A6CA3B4013CB16AB2C105F6BE23AEA9000EAB2178985F972C98057E1C86E44E7218688EA4AE0F3636DCCA745C9DCD4E6AFFB67CCBC13D6131"); } if(name == "dsa/botan/3072") { return load_DL_group_info("0xE4B50880759663585E142460CA2D9DFF132F8AE4C840DDA3A2666889124FE5638B84E8A29B7AF3FA1209BE6BFC4B5072ED3B2B7387BAF3F857F478A80228EF3600B76B3DCFB61D20D34465B2506D2CAF87DF6E7DC0CE91BD2D167A46F6ADCC31C531E4F9C7ABBDB92ADDF35B0A806C66292A5F5E17E964DD099903733AC428AB35D80EA6F685BFBA8BE4068E5418AE5ECAD9E8FF073DE2B63E4E7EAD35C8A9B70B5BD47CFB88D373B66F37931939B0AB71BD5595809086DA0155337D185A0E4FB36A519B1B6202B8591E6002449CF1CD3A66384F6D2073B1CD73BECA93BAF1E1A6117D0238F222AE1ED7FED185A890E7F67FAB8FEB9753CC134A5183DFE87AE2595F7B5C2D9FBB42249FDD59513E1D3396B3EB2FD86684F285A8448FE757A029881C40760B94EF919BDF9740C38389599EC51A6E9BB519A8E068491E9CE0A2FCFE3CB60D66CF0DFAD20A8EC684048684A61444575BD1724D7352B44A760077B3BD6BD385CE5B0A7250CC0BF768DA82923806EB9CFBB138843731B618208C759B", "0xB3EBD364EC69EF8CF3BAF643B75734B16339B2E49E5CDE1B59C1E9FB40EE0C5B", "0x2BED21EEF83964A230AE89BBA71D9F7C39C52FC8229B4E3BC7E5944D329DA10F010EAC9E7BAF6C009FC4EB2960723E2B56DF4663E4C3AC800E9258DE2F7649D206782893F865EFCA498D2EEF30074EA5E8A7AB262712A4D94A2F3B0B9A92EE400FB38A3CC59A5DC7E436D5C004B22E35028381B51C93407EB32D4AE0FD42CB45E12D0ECEE8A26238EDE2082A7B1522113C66CEF8D745C6CF3CB945F84D2F4DE16D44A71DE198270E13F03553C88B8D323AD0B948A1BF2103A949979B6ED16FB5F3C953D95B7C8E88CA67DCF5A636FB9CA39D924215F7A884ED6C7EE3C96D8D9715427974B7C4351282E13D3773F7D28B452F10892A13C7587328DEA4827B6B369B2A8DC172ADC583F51F2A6598C5483E5BC467B02F91D059C402D18E2C2680F776AA06F49280A2C72C17CC42D5B6E740C5C4B1AB3C51C2ED092BE2A2D8B053AE5773D1425ED2B08F06E2DD50592DF1A478C15591CDFD11564FF88FF38B721D42392FDA473212DCFD8D2D88A976A00AFFE6FFFB430A359E64CA2B351CA2412394"); } return std::shared_ptr(); } } /* * DLIES * (C) 1999-2007 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key, RandomNumberGenerator& rng, KDF* kdf, MessageAuthenticationCode* mac, size_t mac_key_length) : DLIES_Encryptor(own_priv_key, rng, kdf, nullptr, 0, mac, mac_key_length) { } DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key, RandomNumberGenerator& rng, KDF* kdf, Cipher_Mode* cipher, size_t cipher_key_len, MessageAuthenticationCode* mac, size_t mac_key_length) : m_other_pub_key(), m_own_pub_key(own_priv_key.public_value()), m_ka(own_priv_key, rng, "Raw"), m_kdf(kdf), m_cipher(cipher), m_cipher_key_len(cipher_key_len), m_mac(mac), m_mac_keylen(mac_key_length), m_iv() { BOTAN_ASSERT_NONNULL(kdf); BOTAN_ASSERT_NONNULL(mac); } std::vector DLIES_Encryptor::enc(const uint8_t in[], size_t length, RandomNumberGenerator&) const { if(m_other_pub_key.empty()) { throw Invalid_State("DLIES: The other key was never set"); } // calculate secret value const SymmetricKey secret_value = m_ka.derive_key(0, m_other_pub_key); // derive secret key from secret value const size_t required_key_length = m_cipher ? m_cipher_key_len + m_mac_keylen : length + m_mac_keylen; const secure_vector secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of()); if(secret_keys.size() != required_key_length) { throw Encoding_Error("DLIES: KDF did not provide sufficient output"); } secure_vector ciphertext(in, in + length); const size_t cipher_key_len = m_cipher ? m_cipher_key_len : length; if(m_cipher) { SymmetricKey enc_key(secret_keys.data(), cipher_key_len); m_cipher->set_key(enc_key); if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) throw Invalid_Argument("DLIES with " + m_cipher->name() + " requires an IV be set"); m_cipher->start(m_iv.bits_of()); m_cipher->finish(ciphertext); } else { xor_buf(ciphertext, secret_keys, cipher_key_len); } // calculate MAC m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen); secure_vector tag = m_mac->process(ciphertext); // out = (ephemeral) public key + ciphertext + tag secure_vector out(m_own_pub_key.size() + ciphertext.size() + tag.size()); buffer_insert(out, 0, m_own_pub_key); buffer_insert(out, 0 + m_own_pub_key.size(), ciphertext); buffer_insert(out, 0 + m_own_pub_key.size() + ciphertext.size(), tag); return unlock(out); } /** * Return the max size, in bytes, of a message * We assume DLIES is only used for key transport and limit the maximum size * to 512 bits */ size_t DLIES_Encryptor::maximum_input_size() const { return 64; } size_t DLIES_Encryptor::ciphertext_length(size_t ptext_len) const { return m_own_pub_key.size() + m_mac->output_length() + m_cipher->output_length(ptext_len); } DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key, RandomNumberGenerator& rng, KDF* kdf, Cipher_Mode* cipher, size_t cipher_key_len, MessageAuthenticationCode* mac, size_t mac_key_length) : m_pub_key_size(own_priv_key.public_value().size()), m_ka(own_priv_key, rng, "Raw"), m_kdf(kdf), m_cipher(cipher), m_cipher_key_len(cipher_key_len), m_mac(mac), m_mac_keylen(mac_key_length), m_iv() { BOTAN_ASSERT_NONNULL(kdf); BOTAN_ASSERT_NONNULL(mac); } DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key, RandomNumberGenerator& rng, KDF* kdf, MessageAuthenticationCode* mac, size_t mac_key_length) : DLIES_Decryptor(own_priv_key, rng, kdf, nullptr, 0, mac, mac_key_length) {} size_t DLIES_Decryptor::plaintext_length(size_t ctext_len) const { if(ctext_len < m_pub_key_size + m_mac->output_length()) return 0; // will throw if attempted return ctext_len - (m_pub_key_size + m_mac->output_length()); } secure_vector DLIES_Decryptor::do_decrypt(uint8_t& valid_mask, const uint8_t msg[], size_t length) const { if(length < m_pub_key_size + m_mac->output_length()) { throw Decoding_Error("DLIES decryption: ciphertext is too short"); } // calculate secret value std::vector other_pub_key(msg, msg + m_pub_key_size); const SymmetricKey secret_value = m_ka.derive_key(0, other_pub_key); const size_t ciphertext_len = length - m_pub_key_size - m_mac->output_length(); size_t cipher_key_len = m_cipher ? m_cipher_key_len : ciphertext_len; // derive secret key from secret value const size_t required_key_length = cipher_key_len + m_mac_keylen; secure_vector secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of()); if(secret_keys.size() != required_key_length) { throw Encoding_Error("DLIES: KDF did not provide sufficient output"); } secure_vector ciphertext(msg + m_pub_key_size, msg + m_pub_key_size + ciphertext_len); // calculate MAC m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen); secure_vector calculated_tag = m_mac->process(ciphertext); // calculated tag == received tag ? secure_vector tag(msg + m_pub_key_size + ciphertext_len, msg + m_pub_key_size + ciphertext_len + m_mac->output_length()); valid_mask = ct_compare_u8(tag.data(), calculated_tag.data(), tag.size()); // decrypt if(m_cipher) { if(valid_mask) { SymmetricKey dec_key(secret_keys.data(), cipher_key_len); m_cipher->set_key(dec_key); try { // the decryption can fail: // e.g. Invalid_Authentication_Tag is thrown if GCM is used and the message does not have a valid tag if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) throw Invalid_Argument("DLIES with " + m_cipher->name() + " requires an IV be set"); m_cipher->start(m_iv.bits_of()); m_cipher->finish(ciphertext); } catch(...) { valid_mask = 0; } } else { return secure_vector(); } } else { xor_buf(ciphertext, secret_keys.data(), cipher_key_len); } return ciphertext; } } /* * DSA * (C) 1999-2010,2014,2016 Jack Lloyd * (C) 2016 René Korthaus * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_RFC6979_GENERATOR) #endif namespace Botan { /* * DSA_PublicKey Constructor */ DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) { m_group = grp; m_y = y1; } /* * Create a DSA private key */ DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, const BigInt& x_arg) { m_group = grp; if(x_arg == 0) m_x = BigInt::random_integer(rng, 2, group_q()); else m_x = x_arg; m_y = m_group.power_g_p(m_x, m_group.q_bits()); } DSA_PrivateKey::DSA_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits) : DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) { m_y = m_group.power_g_p(m_x, m_group.q_bits()); } /* * Check Private DSA Parameters */ bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!DL_Scheme_PrivateKey::check_key(rng, strong) || m_x >= group_q()) return false; if(!strong) return true; return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); } namespace { /** * Object that can create a DSA signature */ class DSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA { public: DSA_Signature_Operation(const DSA_PrivateKey& dsa, const std::string& emsa, RandomNumberGenerator& rng) : PK_Ops::Signature_with_EMSA(emsa), m_group(dsa.get_group()), m_x(dsa.get_x()) { #if defined(BOTAN_HAS_RFC6979_GENERATOR) m_rfc6979_hash = hash_for_emsa(emsa); #endif m_b = BigInt::random_integer(rng, 2, dsa.group_q()); m_b_inv = m_group.inverse_mod_q(m_b); } size_t signature_length() const override { return 2*m_group.q_bytes(); } size_t max_input_bits() const override { return m_group.q_bits(); } secure_vector raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; private: const DL_Group m_group; const BigInt& m_x; #if defined(BOTAN_HAS_RFC6979_GENERATOR) std::string m_rfc6979_hash; #endif BigInt m_b, m_b_inv; }; secure_vector DSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) { const BigInt& q = m_group.get_q(); BigInt m(msg, msg_len, m_group.q_bits()); while(m >= q) m -= q; #if defined(BOTAN_HAS_RFC6979_GENERATOR) BOTAN_UNUSED(rng); const BigInt k = generate_rfc6979_nonce(m_x, q, m, m_rfc6979_hash); #else const BigInt k = BigInt::random_integer(rng, 1, q); #endif const BigInt k_inv = m_group.inverse_mod_q(k); /* * It may not be strictly necessary for the reduction (g^k mod p) mod q to be * const time, since r is published as part of the signature, and deriving * anything useful about k from g^k mod p would seem to require computing a * discrete logarithm. * * However it only increases the cost of signatures by about 7-10%, and DSA is * only for legacy use anyway so we don't care about the performance so much. */ const BigInt r = ct_modulo(m_group.power_g_p(k, m_group.q_bits()), m_group.get_q()); /* * Blind the input message and compute x*r+m as (x*r*b + m*b)/b */ m_b = m_group.square_mod_q(m_b); m_b_inv = m_group.square_mod_q(m_b_inv); m = m_group.multiply_mod_q(m_b, m); const BigInt xr = m_group.multiply_mod_q(m_b, m_x, r); const BigInt s = m_group.multiply_mod_q(m_b_inv, k_inv, m_group.mod_q(xr+m)); // With overwhelming probability, a bug rather than actual zero r/s if(r.is_zero() || s.is_zero()) throw Internal_Error("Computed zero r/s during DSA signature"); return BigInt::encode_fixed_length_int_pair(r, s, q.bytes()); } /** * Object that can verify a DSA signature */ class DSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA { public: DSA_Verification_Operation(const DSA_PublicKey& dsa, const std::string& emsa) : PK_Ops::Verification_with_EMSA(emsa), m_group(dsa.get_group()), m_y(dsa.get_y()) { } size_t max_input_bits() const override { return m_group.q_bits(); } bool with_recovery() const override { return false; } bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override; private: const DL_Group m_group; const BigInt& m_y; }; bool DSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) { const BigInt& q = m_group.get_q(); const size_t q_bytes = q.bytes(); if(sig_len != 2*q_bytes || msg_len > q_bytes) return false; BigInt r(sig, q_bytes); BigInt s(sig + q_bytes, q_bytes); BigInt i(msg, msg_len, q.bits()); if(r <= 0 || r >= q || s <= 0 || s >= q) return false; s = inverse_mod(s, q); const BigInt sr = m_group.multiply_mod_q(s, r); const BigInt si = m_group.multiply_mod_q(s, i); s = m_group.multi_exponentiate(si, m_y, sr); // s is too big for Barrett, and verification doesn't need to be const-time return (s % m_group.get_q() == r); } } std::unique_ptr DSA_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new DSA_Verification_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr DSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new DSA_Signature_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } } /* * Dynamically Loaded Object * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_OS_HAS_POSIX1) #include #elif defined(BOTAN_TARGET_OS_HAS_WIN32) #define NOMINMAX 1 #define _WINSOCKAPI_ // stop windows.h including winsock.h #endif namespace Botan { namespace { void raise_runtime_loader_exception(const std::string& lib_name, const char* msg) { const std::string ex_msg = "Failed to load " + lib_name + ": " + (msg ? msg : "Unknown error"); throw System_Error(ex_msg, 0); } } Dynamically_Loaded_Library::Dynamically_Loaded_Library( const std::string& library) : m_lib_name(library), m_lib(nullptr) { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) m_lib = ::dlopen(m_lib_name.c_str(), RTLD_LAZY); if(!m_lib) raise_runtime_loader_exception(m_lib_name, ::dlerror()); #elif defined(BOTAN_TARGET_OS_HAS_WIN32) m_lib = ::LoadLibraryA(m_lib_name.c_str()); if(!m_lib) raise_runtime_loader_exception(m_lib_name, "LoadLibrary failed"); #endif if(!m_lib) raise_runtime_loader_exception(m_lib_name, "Dynamic load not supported"); } Dynamically_Loaded_Library::~Dynamically_Loaded_Library() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) ::dlclose(m_lib); #elif defined(BOTAN_TARGET_OS_HAS_WIN32) ::FreeLibrary((HMODULE)m_lib); #endif } void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) { void* addr = nullptr; #if defined(BOTAN_TARGET_OS_HAS_POSIX1) addr = ::dlsym(m_lib, symbol.c_str()); #elif defined(BOTAN_TARGET_OS_HAS_WIN32) addr = reinterpret_cast(::GetProcAddress((HMODULE)m_lib, symbol.c_str())); #endif if(!addr) throw Invalid_Argument("Failed to resolve symbol " + symbol + " in " + m_lib_name); return addr; } } /* * EAX Mode Encryption * (C) 1999-2007 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * EAX MAC-based PRF */ secure_vector eax_prf(uint8_t tag, size_t block_size, MessageAuthenticationCode& mac, const uint8_t in[], size_t length) { for(size_t i = 0; i != block_size - 1; ++i) { mac.update(0); } mac.update(tag); mac.update(in, length); return mac.final(); } } /* * EAX_Mode Constructor */ EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) : m_tag_size(tag_size), m_cipher(cipher), m_ctr(new CTR_BE(m_cipher->clone())), m_cmac(new CMAC(m_cipher->clone())) { if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size)); } void EAX_Mode::clear() { m_cipher->clear(); m_ctr->clear(); m_cmac->clear(); reset(); } void EAX_Mode::reset() { m_ad_mac.clear(); m_nonce_mac.clear(); // Clear out any data added to the CMAC calculation try { m_cmac->final(); } catch(Key_Not_Set&) {} } std::string EAX_Mode::name() const { return (m_cipher->name() + "/EAX"); } size_t EAX_Mode::update_granularity() const { /* * For EAX this actually can be as low as 1 but that causes problems * for applications which use update_granularity as the buffer size. */ return m_cipher->parallel_bytes(); } Key_Length_Specification EAX_Mode::key_spec() const { return m_cipher->key_spec(); } /* * Set the EAX key */ void EAX_Mode::key_schedule(const uint8_t key[], size_t length) { /* * These could share the key schedule, which is one nice part of EAX, * but it's much easier to ignore that here... */ m_ctr->set_key(key, length); m_cmac->set_key(key, length); } /* * Set the EAX associated data */ void EAX_Mode::set_associated_data(const uint8_t ad[], size_t length) { if(m_nonce_mac.empty() == false) throw Invalid_State("Cannot set AD for EAX while processing a message"); m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length); } void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len); m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size()); for(size_t i = 0; i != block_size() - 1; ++i) m_cmac->update(0); m_cmac->update(2); } size_t EAX_Encryption::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(m_nonce_mac.size() > 0); m_ctr->cipher(buf, buf, sz); m_cmac->update(buf, sz); return sz; } void EAX_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT_NOMSG(m_nonce_mac.empty() == false); update(buffer, offset); secure_vector data_mac = m_cmac->final(); xor_buf(data_mac, m_nonce_mac, data_mac.size()); if(m_ad_mac.empty()) { m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); } xor_buf(data_mac, m_ad_mac, data_mac.size()); buffer += std::make_pair(data_mac.data(), tag_size()); } size_t EAX_Decryption::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(m_nonce_mac.size() > 0); m_cmac->update(buf, sz); m_ctr->cipher(buf, buf, sz); return sz; } void EAX_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); const size_t remaining = sz - tag_size(); if(remaining) { m_cmac->update(buf, remaining); m_ctr->cipher(buf, buf, remaining); } const uint8_t* included_tag = &buf[remaining]; secure_vector mac = m_cmac->final(); mac ^= m_nonce_mac; if(m_ad_mac.empty()) { m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); } mac ^= m_ad_mac; if(!constant_time_compare(mac.data(), included_tag, tag_size())) throw Invalid_Authentication_Tag("EAX tag check failed"); buffer.resize(offset + remaining); m_nonce_mac.clear(); } } /* * Elliptic curves over GF(p) Montgomery Representation * (C) 2014,2015,2018 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { class CurveGFp_Montgomery final : public CurveGFp_Repr { public: CurveGFp_Montgomery(const BigInt& p, const BigInt& a, const BigInt& b) : m_p(p), m_a(a), m_b(b), m_p_words(m_p.sig_words()), m_p_dash(monty_inverse(m_p.word_at(0))) { Modular_Reducer mod_p(m_p); m_r.set_bit(m_p_words * BOTAN_MP_WORD_BITS); m_r = mod_p.reduce(m_r); m_r2 = mod_p.square(m_r); m_r3 = mod_p.multiply(m_r, m_r2); m_a_r = mod_p.multiply(m_r, m_a); m_b_r = mod_p.multiply(m_r, m_b); m_a_is_zero = m_a.is_zero(); m_a_is_minus_3 = (m_a + 3 == m_p); } bool a_is_zero() const override { return m_a_is_zero; } bool a_is_minus_3() const override { return m_a_is_minus_3; } const BigInt& get_a() const override { return m_a; } const BigInt& get_b() const override { return m_b; } const BigInt& get_p() const override { return m_p; } const BigInt& get_a_rep() const override { return m_a_r; } const BigInt& get_b_rep() const override { return m_b_r; } const BigInt& get_1_rep() const override { return m_r; } bool is_one(const BigInt& x) const override { return x == m_r; } size_t get_p_words() const override { return m_p_words; } size_t get_ws_size() const override { return 2*m_p_words + 4; } BigInt invert_element(const BigInt& x, secure_vector& ws) const override; void to_curve_rep(BigInt& x, secure_vector& ws) const override; void from_curve_rep(BigInt& x, secure_vector& ws) const override; void curve_mul_words(BigInt& z, const word x_words[], const size_t x_size, const BigInt& y, secure_vector& ws) const override; void curve_sqr_words(BigInt& z, const word x_words[], size_t x_size, secure_vector& ws) const override; private: BigInt m_p; BigInt m_a, m_b; BigInt m_a_r, m_b_r; size_t m_p_words; // cache of m_p.sig_words() // Montgomery parameters BigInt m_r, m_r2, m_r3; word m_p_dash; bool m_a_is_zero; bool m_a_is_minus_3; }; BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector& ws) const { // Should we use Montgomery inverse instead? const BigInt inv = inverse_mod(x, m_p); BigInt res; curve_mul(res, inv, m_r3, ws); return res; } void CurveGFp_Montgomery::to_curve_rep(BigInt& x, secure_vector& ws) const { const BigInt tx = x; curve_mul(x, tx, m_r2, ws); } void CurveGFp_Montgomery::from_curve_rep(BigInt& z, secure_vector& ws) const { if(ws.size() < get_ws_size()) ws.resize(get_ws_size()); const size_t output_size = 2*m_p_words + 2; if(z.size() < output_size) z.grow_to(output_size); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); } void CurveGFp_Montgomery::curve_mul_words(BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector& ws) const { BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); if(ws.size() < get_ws_size()) ws.resize(get_ws_size()); const size_t output_size = 2*m_p_words + 2; if(z.size() < output_size) z.grow_to(output_size); bigint_mul(z.mutable_data(), z.size(), x_w, x_size, std::min(m_p_words, x_size), y.data(), y.size(), std::min(m_p_words, y.size()), ws.data(), ws.size()); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); } void CurveGFp_Montgomery::curve_sqr_words(BigInt& z, const word x[], size_t x_size, secure_vector& ws) const { if(ws.size() < get_ws_size()) ws.resize(get_ws_size()); const size_t output_size = 2*m_p_words + 2; if(z.size() < output_size) z.grow_to(output_size); bigint_sqr(z.mutable_data(), z.size(), x, x_size, std::min(m_p_words, x_size), ws.data(), ws.size()); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); } class CurveGFp_NIST : public CurveGFp_Repr { public: CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) : m_1(1), m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS) { // All Solinas prime curves are assumed a == -3 } bool a_is_zero() const override { return false; } bool a_is_minus_3() const override { return true; } const BigInt& get_a() const override { return m_a; } const BigInt& get_b() const override { return m_b; } const BigInt& get_1_rep() const override { return m_1; } size_t get_p_words() const override { return m_p_words; } size_t get_ws_size() const override { return 2*m_p_words + 4; } const BigInt& get_a_rep() const override { return m_a; } const BigInt& get_b_rep() const override { return m_b; } bool is_one(const BigInt& x) const override { return x == 1; } void to_curve_rep(BigInt& x, secure_vector& ws) const override { redc_mod_p(x, ws); } void from_curve_rep(BigInt& x, secure_vector& ws) const override { redc_mod_p(x, ws); } virtual void redc_mod_p(BigInt& z, secure_vector& ws) const = 0; BigInt invert_element(const BigInt& x, secure_vector& ws) const override; void curve_mul_words(BigInt& z, const word x_words[], const size_t x_size, const BigInt& y, secure_vector& ws) const override; void curve_mul_tmp(BigInt& x, const BigInt& y, BigInt& tmp, secure_vector& ws) const { curve_mul(tmp, x, y, ws); x.swap(tmp); } void curve_sqr_tmp(BigInt& x, BigInt& tmp, secure_vector& ws) const { curve_sqr(tmp, x, ws); x.swap(tmp); } void curve_sqr_words(BigInt& z, const word x_words[], size_t x_size, secure_vector& ws) const override; private: // Curve parameters BigInt m_1; BigInt m_a, m_b; size_t m_p_words; // cache of m_p.sig_words() }; BigInt CurveGFp_NIST::invert_element(const BigInt& x, secure_vector& ws) const { BOTAN_UNUSED(ws); return inverse_mod(x, get_p()); } void CurveGFp_NIST::curve_mul_words(BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector& ws) const { BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); if(ws.size() < get_ws_size()) ws.resize(get_ws_size()); const size_t output_size = 2*m_p_words + 2; if(z.size() < output_size) z.grow_to(output_size); bigint_mul(z.mutable_data(), z.size(), x_w, x_size, std::min(m_p_words, x_size), y.data(), y.size(), std::min(m_p_words, y.size()), ws.data(), ws.size()); this->redc_mod_p(z, ws); } void CurveGFp_NIST::curve_sqr_words(BigInt& z, const word x[], size_t x_size, secure_vector& ws) const { if(ws.size() < get_ws_size()) ws.resize(get_ws_size()); const size_t output_size = 2*m_p_words + 2; if(z.size() < output_size) z.grow_to(output_size); bigint_sqr(z.mutable_data(), output_size, x, x_size, std::min(m_p_words, x_size), ws.data(), ws.size()); this->redc_mod_p(z, ws); } /** * The NIST P-192 curve */ class CurveGFp_P192 final : public CurveGFp_NIST { public: CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {} const BigInt& get_p() const override { return prime_p192(); } private: void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p192(x, ws); } }; /** * The NIST P-224 curve */ class CurveGFp_P224 final : public CurveGFp_NIST { public: CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {} const BigInt& get_p() const override { return prime_p224(); } private: void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p224(x, ws); } }; /** * The NIST P-256 curve */ class CurveGFp_P256 final : public CurveGFp_NIST { public: CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {} const BigInt& get_p() const override { return prime_p256(); } private: void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p256(x, ws); } BigInt invert_element(const BigInt& x, secure_vector& ws) const override; }; BigInt CurveGFp_P256::invert_element(const BigInt& x, secure_vector& ws) const { BigInt r, p2, p4, p8, p16, p32, tmp; curve_sqr(r, x, ws); curve_mul(p2, r, x, ws); curve_sqr(r, p2, ws); curve_sqr_tmp(r, tmp, ws); curve_mul(p4, r, p2, ws); curve_sqr(r, p4, ws); for(size_t i = 0; i != 3; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul(p8, r, p4, ws); curve_sqr(r, p8, ws); for(size_t i = 0; i != 7; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul(p16, r, p8, ws); curve_sqr(r, p16, ws); for(size_t i = 0; i != 15; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul(p32, r, p16, ws); curve_sqr(r, p32, ws); for(size_t i = 0; i != 31; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); for(size_t i = 0; i != 32*4; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, p32, tmp, ws); for(size_t i = 0; i != 32; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, p32, tmp, ws); for(size_t i = 0; i != 16; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, p16, tmp, ws); for(size_t i = 0; i != 8; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, p8, tmp, ws); for(size_t i = 0; i != 4; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, p4, tmp, ws); for(size_t i = 0; i != 2; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, p2, tmp, ws); for(size_t i = 0; i != 2; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); return r; } /** * The NIST P-384 curve */ class CurveGFp_P384 final : public CurveGFp_NIST { public: CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {} const BigInt& get_p() const override { return prime_p384(); } private: void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p384(x, ws); } BigInt invert_element(const BigInt& x, secure_vector& ws) const override; }; BigInt CurveGFp_P384::invert_element(const BigInt& x, secure_vector& ws) const { // From https://briansmith.org/ecc-inversion-addition-chains-01 BigInt r, x2, x3, x15, x30, tmp, rl; r = x; curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); x2 = r; curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); x3 = r; for(size_t i = 0; i != 3; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x3, tmp, ws); rl = r; for(size_t i = 0; i != 6; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); for(size_t i = 0; i != 3; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x3, tmp, ws); x15 = r; for(size_t i = 0; i != 15; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x15, tmp, ws); x30 = r; for(size_t i = 0; i != 30; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x30, tmp, ws); rl = r; for(size_t i = 0; i != 60; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); rl = r; for(size_t i = 0; i != 120; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); for(size_t i = 0; i != 15; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x15, tmp, ws); for(size_t i = 0; i != 31; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x30, tmp, ws); for(size_t i = 0; i != 2; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x2, tmp, ws); for(size_t i = 0; i != 94; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x30, tmp, ws); for(size_t i = 0; i != 2; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); return r; } /** * The NIST P-521 curve */ class CurveGFp_P521 final : public CurveGFp_NIST { public: CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {} const BigInt& get_p() const override { return prime_p521(); } private: void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p521(x, ws); } BigInt invert_element(const BigInt& x, secure_vector& ws) const override; }; BigInt CurveGFp_P521::invert_element(const BigInt& x, secure_vector& ws) const { // Addition chain from https://eprint.iacr.org/2014/852.pdf section BigInt r; BigInt rl; BigInt a7; BigInt tmp; curve_sqr(r, x, ws); curve_mul_tmp(r, x, tmp, ws); curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); rl = r; for(size_t i = 0; i != 3; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); a7 = r; // need this value later curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); rl = r; for(size_t i = 0; i != 8; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); rl = r; for(size_t i = 0; i != 16; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); rl = r; for(size_t i = 0; i != 32; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); rl = r; for(size_t i = 0; i != 64; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); rl = r; for(size_t i = 0; i != 128; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); rl = r; for(size_t i = 0; i != 256; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, rl, tmp, ws); for(size_t i = 0; i != 7; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, a7, tmp, ws); for(size_t i = 0; i != 2; ++i) curve_sqr_tmp(r, tmp, ws); curve_mul_tmp(r, x, tmp, ws); return r; } } std::shared_ptr CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b) { if(p == prime_p192()) return std::shared_ptr(new CurveGFp_P192(a, b)); if(p == prime_p224()) return std::shared_ptr(new CurveGFp_P224(a, b)); if(p == prime_p256()) return std::shared_ptr(new CurveGFp_P256(a, b)); if(p == prime_p384()) return std::shared_ptr(new CurveGFp_P384(a, b)); if(p == prime_p521()) return std::shared_ptr(new CurveGFp_P521(a, b)); return std::shared_ptr(new CurveGFp_Montgomery(p, a, b)); } } /* * ECC Domain Parameters * * (C) 2007 Falko Strenzke, FlexSecure GmbH * (C) 2008,2018 Jack Lloyd * (C) 2018 Tobias Niemann * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { class EC_Group_Data final { public: EC_Group_Data(const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& g_x, const BigInt& g_y, const BigInt& order, const BigInt& cofactor, const OID& oid, EC_Group_Source source) : m_curve(p, a, b), m_base_point(m_curve, g_x, g_y), m_g_x(g_x), m_g_y(g_y), m_order(order), m_cofactor(cofactor), m_mod_order(order), m_base_mult(m_base_point, m_mod_order), m_oid(oid), m_p_bits(p.bits()), m_order_bits(order.bits()), m_a_is_minus_3(a == p - 3), m_a_is_zero(a.is_zero()), m_source(source) { } bool match(const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& g_x, const BigInt& g_y, const BigInt& order, const BigInt& cofactor) const { return (this->p() == p && this->a() == a && this->b() == b && this->order() == order && this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y); } void set_oid(const OID& oid) { BOTAN_STATE_CHECK(m_oid.empty()); m_oid = oid; } const OID& oid() const { return m_oid; } const BigInt& p() const { return m_curve.get_p(); } const BigInt& a() const { return m_curve.get_a(); } const BigInt& b() const { return m_curve.get_b(); } const BigInt& order() const { return m_order; } const BigInt& cofactor() const { return m_cofactor; } const BigInt& g_x() const { return m_g_x; } const BigInt& g_y() const { return m_g_y; } size_t p_bits() const { return m_p_bits; } size_t p_bytes() const { return (m_p_bits + 7) / 8; } size_t order_bits() const { return m_order_bits; } size_t order_bytes() const { return (m_order_bits + 7) / 8; } const CurveGFp& curve() const { return m_curve; } const PointGFp& base_point() const { return m_base_point; } bool a_is_minus_3() const { return m_a_is_minus_3; } bool a_is_zero() const { return m_a_is_zero; } BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); } BigInt square_mod_order(const BigInt& x) const { return m_mod_order.square(x); } BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const { return m_mod_order.multiply(x, y); } BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const { return m_mod_order.multiply(m_mod_order.multiply(x, y), z); } BigInt inverse_mod_order(const BigInt& x) const { return inverse_mod(x, m_order); } PointGFp blinded_base_point_multiply(const BigInt& k, RandomNumberGenerator& rng, std::vector& ws) const { return m_base_mult.mul(k, rng, m_order, ws); } EC_Group_Source source() const { return m_source; } private: CurveGFp m_curve; PointGFp m_base_point; BigInt m_g_x; BigInt m_g_y; BigInt m_order; BigInt m_cofactor; Modular_Reducer m_mod_order; PointGFp_Base_Point_Precompute m_base_mult; OID m_oid; size_t m_p_bits; size_t m_order_bits; bool m_a_is_minus_3; bool m_a_is_zero; EC_Group_Source m_source; }; class EC_Group_Data_Map final { public: EC_Group_Data_Map() {} size_t clear() { lock_guard_type lock(m_mutex); size_t count = m_registered_curves.size(); m_registered_curves.clear(); return count; } std::shared_ptr lookup(const OID& oid) { lock_guard_type lock(m_mutex); for(auto i : m_registered_curves) { if(i->oid() == oid) return i; } // Not found, check hardcoded data std::shared_ptr data = EC_Group::EC_group_info(oid); if(data) { m_registered_curves.push_back(data); return data; } // Nope, unknown curve return std::shared_ptr(); } std::shared_ptr lookup_or_create(const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& g_x, const BigInt& g_y, const BigInt& order, const BigInt& cofactor, const OID& oid, EC_Group_Source source) { lock_guard_type lock(m_mutex); for(auto i : m_registered_curves) { if(!oid.empty()) { if(i->oid() == oid) { if(!i->match(p, a, b, g_x, g_y, order, cofactor)) throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() + " but another curve is already registered using that OID"); return i; } else if(i->oid().has_value()) continue; // distinct OIDs so not a match } if(i->match(p, a, b, g_x, g_y, order, cofactor)) { /* * If the same curve was previously created without an OID * but has been registered again using an OID, save that OID. */ if(oid.empty() == false) { if(i->oid().empty() == true) { i->set_oid(oid); } else { throw Invalid_Argument("Cannot register ECC group with OID " + oid.to_string() + " already registered using " + i->oid().to_string()); } } return i; } } // Not found - if OID is set try looking up that way if(oid.has_value()) { // Not located in existing store - try hardcoded data set std::shared_ptr data = EC_Group::EC_group_info(oid); if(data) { m_registered_curves.push_back(data); return data; } } // Not found or no OID, add data and return std::shared_ptr d = std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, source); m_registered_curves.push_back(d); return d; } private: mutex_type m_mutex; std::vector> m_registered_curves; }; //static EC_Group_Data_Map& EC_Group::ec_group_data() { /* * This exists purely to ensure the allocator is constructed before g_ec_data, * which ensures that its destructor runs after ~g_ec_data is complete. */ static Allocator_Initializer g_init_allocator; static EC_Group_Data_Map g_ec_data; return g_ec_data; } //static size_t EC_Group::clear_registered_curve_data() { return ec_group_data().clear(); } //static std::shared_ptr EC_Group::load_EC_group_info(const char* p_str, const char* a_str, const char* b_str, const char* g_x_str, const char* g_y_str, const char* order_str, const OID& oid) { const BigInt p(p_str); const BigInt a(a_str); const BigInt b(b_str); const BigInt g_x(g_x_str); const BigInt g_y(g_y_str); const BigInt order(order_str); const BigInt cofactor(1); // implicit return std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin); } //static std::shared_ptr EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len, EC_Group_Source source) { BER_Decoder ber(bits, len); BER_Object obj = ber.get_next_object(); if(obj.type() == NULL_TAG) { throw Decoding_Error("Cannot handle ImplicitCA ECC parameters"); } else if(obj.type() == OBJECT_ID) { OID dom_par_oid; BER_Decoder(bits, len).decode(dom_par_oid); return ec_group_data().lookup(dom_par_oid); } else if(obj.type() == SEQUENCE) { BigInt p, a, b, order, cofactor; std::vector base_pt; std::vector seed; BER_Decoder(bits, len) .start_cons(SEQUENCE) .decode_and_check(1, "Unknown ECC param version code") .start_cons(SEQUENCE) .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported") .decode(p) .end_cons() .start_cons(SEQUENCE) .decode_octet_string_bigint(a) .decode_octet_string_bigint(b) .decode_optional_string(seed, BIT_STRING, BIT_STRING) .end_cons() .decode(base_pt, OCTET_STRING) .decode(order) .decode(cofactor) .end_cons() .verify_end(); if(p.bits() < 64 || p.is_negative() || !is_bailie_psw_probable_prime(p)) throw Decoding_Error("Invalid ECC p parameter"); if(a.is_negative() || a >= p) throw Decoding_Error("Invalid ECC a parameter"); if(b <= 0 || b >= p) throw Decoding_Error("Invalid ECC b parameter"); if(order <= 0 || !is_bailie_psw_probable_prime(order)) throw Decoding_Error("Invalid ECC order parameter"); if(cofactor <= 0 || cofactor >= 16) throw Decoding_Error("Invalid ECC cofactor parameter"); std::pair base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b); return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source); } else { throw Decoding_Error("Unexpected tag while decoding ECC domain params"); } } EC_Group::EC_Group() { } EC_Group::~EC_Group() { // shared_ptr possibly freed here } EC_Group::EC_Group(const OID& domain_oid) { this->m_data = ec_group_data().lookup(domain_oid); if(!this->m_data) throw Invalid_Argument("Unknown EC_Group " + domain_oid.to_string()); } EC_Group::EC_Group(const std::string& str) { if(str == "") return; // no initialization / uninitialized try { const OID oid = OID::from_string(str); if(oid.has_value()) m_data = ec_group_data().lookup(oid); } catch(...) { } if(m_data == nullptr) { if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") { // OK try it as PEM ... secure_vector ber = PEM_Code::decode_check_label(str, "EC PARAMETERS"); this->m_data = BER_decode_EC_group(ber.data(), ber.size(), EC_Group_Source::ExternalSource); } } if(m_data == nullptr) throw Invalid_Argument("Unknown ECC group '" + str + "'"); } //static EC_Group EC_Group::EC_Group_from_PEM(const std::string& pem) { const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS"); return EC_Group(ber.data(), ber.size()); } //static std::string EC_Group::PEM_for_named_group(const std::string& name) { try { EC_Group group(name); return group.PEM_encode(); } catch(...) { return ""; } } EC_Group::EC_Group(const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order, const BigInt& cofactor, const OID& oid) { m_data = ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource); } EC_Group::EC_Group(const uint8_t ber[], size_t ber_len) { m_data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource); } const EC_Group_Data& EC_Group::data() const { if(m_data == nullptr) throw Invalid_State("EC_Group uninitialized"); return *m_data; } const CurveGFp& EC_Group::get_curve() const { return data().curve(); } bool EC_Group::a_is_minus_3() const { return data().a_is_minus_3(); } bool EC_Group::a_is_zero() const { return data().a_is_zero(); } size_t EC_Group::get_p_bits() const { return data().p_bits(); } size_t EC_Group::get_p_bytes() const { return data().p_bytes(); } size_t EC_Group::get_order_bits() const { return data().order_bits(); } size_t EC_Group::get_order_bytes() const { return data().order_bytes(); } const BigInt& EC_Group::get_p() const { return data().p(); } const BigInt& EC_Group::get_a() const { return data().a(); } const BigInt& EC_Group::get_b() const { return data().b(); } const PointGFp& EC_Group::get_base_point() const { return data().base_point(); } const BigInt& EC_Group::get_order() const { return data().order(); } const BigInt& EC_Group::get_g_x() const { return data().g_x(); } const BigInt& EC_Group::get_g_y() const { return data().g_y(); } const BigInt& EC_Group::get_cofactor() const { return data().cofactor(); } BigInt EC_Group::mod_order(const BigInt& k) const { return data().mod_order(k); } BigInt EC_Group::square_mod_order(const BigInt& x) const { return data().square_mod_order(x); } BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const { return data().multiply_mod_order(x, y); } BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const { return data().multiply_mod_order(x, y, z); } BigInt EC_Group::inverse_mod_order(const BigInt& x) const { return data().inverse_mod_order(x); } const OID& EC_Group::get_curve_oid() const { return data().oid(); } EC_Group_Source EC_Group::source() const { return data().source(); } size_t EC_Group::point_size(PointGFp::Compression_Type format) const { // Hybrid and standard format are (x,y), compressed is y, +1 format byte if(format == PointGFp::COMPRESSED) return (1 + get_p_bytes()); else return (1 + 2*get_p_bytes()); } PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const { return Botan::OS2ECP(bits, len, data().curve()); } PointGFp EC_Group::point(const BigInt& x, const BigInt& y) const { // TODO: randomize the representation? return PointGFp(data().curve(), x, y); } PointGFp EC_Group::point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const { PointGFp_Multi_Point_Precompute xy_mul(get_base_point(), pt); return xy_mul.multi_exp(x, y); } PointGFp EC_Group::blinded_base_point_multiply(const BigInt& k, RandomNumberGenerator& rng, std::vector& ws) const { return data().blinded_base_point_multiply(k, rng, ws); } BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k, RandomNumberGenerator& rng, std::vector& ws) const { const PointGFp pt = data().blinded_base_point_multiply(k, rng, ws); if(pt.is_zero()) return 0; return pt.get_affine_x(); } BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const { return BigInt::random_integer(rng, 1, get_order()); } PointGFp EC_Group::blinded_var_point_multiply(const PointGFp& point, const BigInt& k, RandomNumberGenerator& rng, std::vector& ws) const { PointGFp_Var_Point_Precompute mul(point, rng, ws); return mul.mul(k, rng, get_order(), ws); } PointGFp EC_Group::zero_point() const { return PointGFp(data().curve()); } std::vector EC_Group::DER_encode(EC_Group_Encoding form) const { std::vector output; DER_Encoder der(output); if(form == EC_DOMPAR_ENC_EXPLICIT) { const size_t ecpVers1 = 1; const OID curve_type("1.2.840.10045.1.1"); // prime field const size_t p_bytes = get_p_bytes(); der.start_cons(SEQUENCE) .encode(ecpVers1) .start_cons(SEQUENCE) .encode(curve_type) .encode(get_p()) .end_cons() .start_cons(SEQUENCE) .encode(BigInt::encode_1363(get_a(), p_bytes), OCTET_STRING) .encode(BigInt::encode_1363(get_b(), p_bytes), OCTET_STRING) .end_cons() .encode(get_base_point().encode(PointGFp::UNCOMPRESSED), OCTET_STRING) .encode(get_order()) .encode(get_cofactor()) .end_cons(); } else if(form == EC_DOMPAR_ENC_OID) { const OID oid = get_curve_oid(); if(oid.empty()) { throw Encoding_Error("Cannot encode EC_Group as OID because OID not set"); } der.encode(oid); } else if(form == EC_DOMPAR_ENC_IMPLICITCA) { der.encode_null(); } else { throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); } return output; } std::string EC_Group::PEM_encode() const { const std::vector der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); return PEM_Code::encode(der, "EC PARAMETERS"); } bool EC_Group::operator==(const EC_Group& other) const { if(m_data == other.m_data) return true; // same shared rep /* * No point comparing order/cofactor as they are uniquely determined * by the curve equation (p,a,b) and the base point. */ return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() && get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y()); } bool EC_Group::verify_public_element(const PointGFp& point) const { //check that public point is not at infinity if(point.is_zero()) return false; //check that public point is on the curve if(point.on_the_curve() == false) return false; //check that public point has order q if((point * get_order()).is_zero() == false) return false; if(get_cofactor() > 1) { if((point * get_cofactor()).is_zero()) return false; } return true; } bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const { const bool is_builtin = source() == EC_Group_Source::Builtin; if(is_builtin && !strong) return true; const BigInt& p = get_p(); const BigInt& a = get_a(); const BigInt& b = get_b(); const BigInt& order = get_order(); const PointGFp& base_point = get_base_point(); if(p <= 3 || order <= 0) return false; if(a < 0 || a >= p) return false; if(b <= 0 || b >= p) return false; const size_t test_prob = 128; const bool is_randomly_generated = is_builtin; //check if field modulus is prime if(!is_prime(p, rng, test_prob, is_randomly_generated)) { return false; } //check if order is prime if(!is_prime(order, rng, test_prob, is_randomly_generated)) { return false; } //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero const Modular_Reducer mod_p(p); const BigInt discriminant = mod_p.reduce( mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b))); if(discriminant == 0) { return false; } //check for valid cofactor if(get_cofactor() < 1) { return false; } //check if the base point is on the curve if(!base_point.on_the_curve()) { return false; } if((base_point * get_cofactor()).is_zero()) { return false; } //check if order of the base point is correct if(!(base_point * order).is_zero()) { return false; } return true; } } /* * List of ECC groups * (C) 2013,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { //static std::shared_ptr EC_Group::EC_group_info(const OID& oid) { // P-256 if(oid == OID{1,2,840,10045,3,1,7}) return load_EC_group_info("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", "0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", "0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", "0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", oid); // P-384 if(oid == OID{1,3,132,0,34}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", "0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", "0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", "0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", oid); // P-521 if(oid == OID{1,3,132,0,35}) return load_EC_group_info("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", "0x51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", "0xC6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", "0x11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", oid); // brainpool160r1 if(oid == OID{1,3,36,3,3,2,8,1,1,1}) return load_EC_group_info("0xE95E4A5F737059DC60DFC7AD95B3D8139515620F", "0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300", "0x1E589A8595423412134FAA2DBDEC95C8D8675E58", "0xBED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", "0x1667CB477A1A8EC338F94741669C976316DA6321", "0xE95E4A5F737059DC60DF5991D45029409E60FC09", oid); // brainpool192r1 if(oid == OID{1,3,36,3,3,2,8,1,1,3}) return load_EC_group_info("0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", "0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", "0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", "0xC0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6", "0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", "0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", oid); // brainpool224r1 if(oid == OID{1,3,36,3,3,2,8,1,1,5}) return load_EC_group_info("0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", "0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", "0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", "0xD9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D", "0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", "0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", oid); // brainpool256r1 if(oid == OID{1,3,36,3,3,2,8,1,1,7}) return load_EC_group_info("0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", "0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", "0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", "0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", "0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", "0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", oid); // brainpool320r1 if(oid == OID{1,3,36,3,3,2,8,1,1,9}) return load_EC_group_info("0xD35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", "0x3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", "0x520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", "0x43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", "0x14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", "0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", oid); // brainpool384r1 if(oid == OID{1,3,36,3,3,2,8,1,1,11}) return load_EC_group_info("0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", "0x7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", "0x4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", "0x1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", "0x8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", "0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", oid); // brainpool512r1 if(oid == OID{1,3,36,3,3,2,8,1,1,13}) return load_EC_group_info("0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", "0x7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", "0x3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", "0x81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", "0x7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", "0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", oid); // frp256v1 if(oid == OID{1,2,250,1,223,101,256,1}) return load_EC_group_info("0xF1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C03", "0xF1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C00", "0xEE353FCA5428A9300D4ABA754A44C00FDFEC0C9AE4B1A1803075ED967B7BB73F", "0xB6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF", "0x6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB", "0xF1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1", oid); // gost_256A if(oid == OID{1,2,643,2,2,35,1} || oid == OID{1,2,643,2,2,36,0} || oid == OID{1,2,643,7,1,2,1,1,1}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", "0xA6", "0x1", "0x8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", OID{1,2,643,7,1,2,1,1,1}); // gost_512A if(oid == OID{1,2,643,7,1,2,1,2,1}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4", "0xE8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760", "3", "0x7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275", oid); // secp160k1 if(oid == OID{1,3,132,0,9}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", "0x0", "0x7", "0x3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", "0x938CF935318FDCED6BC28286531733C3F03C4FEE", "0x100000000000000000001B8FA16DFAB9ACA16B6B3", oid); // secp160r1 if(oid == OID{1,3,132,0,8}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", "0x1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", "0x4A96B5688EF573284664698968C38BB913CBFC82", "0x23A628553168947D59DCC912042351377AC5FB32", "0x100000000000000000001F4C8F927AED3CA752257", oid); // secp160r2 if(oid == OID{1,3,132,0,30}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", "0xB4E134D3FB59EB8BAB57274904664D5AF50388BA", "0x52DCB034293A117E1F4FF11B30F7199D3144CE6D", "0xFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", "0x100000000000000000000351EE786A818F3A1A16B", oid); // secp192k1 if(oid == OID{1,3,132,0,31}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", "0x0", "0x3", "0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", "0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", "0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", oid); // secp192r1 if(oid == OID{1,2,840,10045,3,1,1}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", "0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", "0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", "0x7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", "0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", oid); // secp224k1 if(oid == OID{1,3,132,0,32}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", "0x0", "0x5", "0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", "0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", "0x10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", oid); // secp224r1 if(oid == OID{1,3,132,0,33}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", "0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", "0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", "0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", oid); // secp256k1 if(oid == OID{1,3,132,0,10}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", "0x0", "0x7", "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", oid); // sm2p256v1 if(oid == OID{1,2,156,10197,1,301}) return load_EC_group_info("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", "0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", "0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", "0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", oid); // x962_p192v2 if(oid == OID{1,2,840,10045,3,1,2}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", "0xCC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", "0xEEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", "0x6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", "0xFFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", oid); // x962_p192v3 if(oid == OID{1,2,840,10045,3,1,3}) return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", "0x22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", "0x7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", "0x38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", "0xFFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", oid); // x962_p239v1 if(oid == OID{1,2,840,10045,3,1,4}) return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", "0x6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", "0xFFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", "0x7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", oid); // x962_p239v2 if(oid == OID{1,2,840,10045,3,1,5}) return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", "0x617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", "0x38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", "0x5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", "0x7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", oid); // x962_p239v3 if(oid == OID{1,2,840,10045,3,1,6}) return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", "0x255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", "0x6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", "0x1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", oid); return std::shared_ptr(); } //static const std::set& EC_Group::known_named_groups() { static const std::set named_groups = { "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1", "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1", "brainpool160r1", "brainpool192r1", "brainpool224r1", "brainpool256r1", "brainpool320r1", "brainpool384r1", "brainpool512r1", "x962_p192v2", "x962_p192v3", "x962_p239v1", "x962_p239v2", "x962_p239v3", "gost_256A", "gost_512A", "frp256v1", "sm2p256v1" }; return named_groups; } } /* * Point arithmetic on elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke * 2008-2011,2012,2014,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { PointGFp::PointGFp(const CurveGFp& curve) : m_curve(curve), m_coord_x(0), m_coord_y(curve.get_1_rep()), m_coord_z(0) { // Assumes Montgomery rep of zero is zero } PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) : m_curve(curve), m_coord_x(x), m_coord_y(y), m_coord_z(m_curve.get_1_rep()) { if(x < 0 || x >= curve.get_p()) throw Invalid_Argument("Invalid PointGFp affine x"); if(y < 0 || y >= curve.get_p()) throw Invalid_Argument("Invalid PointGFp affine y"); secure_vector monty_ws(m_curve.get_ws_size()); m_curve.to_rep(m_coord_x, monty_ws); m_curve.to_rep(m_coord_y, monty_ws); } void PointGFp::randomize_repr(RandomNumberGenerator& rng) { secure_vector ws(m_curve.get_ws_size()); randomize_repr(rng, ws); } void PointGFp::randomize_repr(RandomNumberGenerator& rng, secure_vector& ws) { const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p()); /* * No reason to convert this to Montgomery representation first, * just pretend the random mask was chosen as Redc(mask) and the * random mask we generated above is in the Montgomery * representation. * //m_curve.to_rep(mask, ws); */ const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws); const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws); m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws); m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws); m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws); } namespace { inline void resize_ws(std::vector& ws_bn, size_t cap_size) { BOTAN_ASSERT(ws_bn.size() >= PointGFp::WORKSPACE_SIZE, "Expected size for PointGFp workspace"); for(size_t i = 0; i != ws_bn.size(); ++i) if(ws_bn[i].size() < cap_size) ws_bn[i].get_word_vector().resize(cap_size); } inline word all_zeros(const word x[], size_t len) { word z = 0; for(size_t i = 0; i != len; ++i) z |= x[i]; return CT::Mask::is_zero(z).value(); } } void PointGFp::add_affine(const word x_words[], size_t x_size, const word y_words[], size_t y_size, std::vector& ws_bn) { if(all_zeros(x_words, x_size) & all_zeros(y_words, y_size)) { return; } if(is_zero()) { m_coord_x.set_words(x_words, x_size); m_coord_y.set_words(y_words, y_size); m_coord_z = m_curve.get_1_rep(); return; } resize_ws(ws_bn, m_curve.get_ws_size()); secure_vector& ws = ws_bn[0].get_word_vector(); secure_vector& sub_ws = ws_bn[1].get_word_vector(); BigInt& T0 = ws_bn[2]; BigInt& T1 = ws_bn[3]; BigInt& T2 = ws_bn[4]; BigInt& T3 = ws_bn[5]; BigInt& T4 = ws_bn[6]; /* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 simplified with Z2 = 1 */ const BigInt& p = m_curve.get_p(); m_curve.sqr(T3, m_coord_z, ws); // z1^2 m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 m_curve.mul(T2, m_coord_z, T3, ws); // z1^3 m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3 T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2 T0.mod_sub(m_coord_y, p, sub_ws); if(T4.is_zero()) { if(T0.is_zero()) { mult2(ws_bn); return; } // setting to zero: m_coord_x.clear(); m_coord_y = m_curve.get_1_rep(); m_coord_z.clear(); return; } m_curve.sqr(T2, T4, ws); m_curve.mul(T3, m_coord_x, T2, ws); m_curve.mul(T1, T2, T4, ws); m_curve.sqr(m_coord_x, T0, ws); m_coord_x.mod_sub(T1, p, sub_ws); m_coord_x.mod_sub(T3, p, sub_ws); m_coord_x.mod_sub(T3, p, sub_ws); T3.mod_sub(m_coord_x, p, sub_ws); m_curve.mul(T2, T0, T3, ws); m_curve.mul(T0, m_coord_y, T1, ws); T2.mod_sub(T0, p, sub_ws); m_coord_y.swap(T2); m_curve.mul(T0, m_coord_z, T4, ws); m_coord_z.swap(T0); } void PointGFp::add(const word x_words[], size_t x_size, const word y_words[], size_t y_size, const word z_words[], size_t z_size, std::vector& ws_bn) { if(all_zeros(x_words, x_size) & all_zeros(z_words, z_size)) return; if(is_zero()) { m_coord_x.set_words(x_words, x_size); m_coord_y.set_words(y_words, y_size); m_coord_z.set_words(z_words, z_size); return; } resize_ws(ws_bn, m_curve.get_ws_size()); secure_vector& ws = ws_bn[0].get_word_vector(); secure_vector& sub_ws = ws_bn[1].get_word_vector(); BigInt& T0 = ws_bn[2]; BigInt& T1 = ws_bn[3]; BigInt& T2 = ws_bn[4]; BigInt& T3 = ws_bn[5]; BigInt& T4 = ws_bn[6]; BigInt& T5 = ws_bn[7]; /* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 */ const BigInt& p = m_curve.get_p(); m_curve.sqr(T0, z_words, z_size, ws); // z2^2 m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2 m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3 m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3 m_curve.sqr(T3, m_coord_z, ws); // z1^2 m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 m_curve.mul(T5, m_coord_z, T3, ws); // z1^3 m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3 T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2 T0.mod_sub(T2, p, sub_ws); if(T4.is_zero()) { if(T0.is_zero()) { mult2(ws_bn); return; } // setting to zero: m_coord_x.clear(); m_coord_y = m_curve.get_1_rep(); m_coord_z.clear(); return; } m_curve.sqr(T5, T4, ws); m_curve.mul(T3, T1, T5, ws); m_curve.mul(T1, T5, T4, ws); m_curve.sqr(m_coord_x, T0, ws); m_coord_x.mod_sub(T1, p, sub_ws); m_coord_x.mod_sub(T3, p, sub_ws); m_coord_x.mod_sub(T3, p, sub_ws); T3.mod_sub(m_coord_x, p, sub_ws); m_curve.mul(m_coord_y, T0, T3, ws); m_curve.mul(T3, T2, T1, ws); m_coord_y.mod_sub(T3, p, sub_ws); m_curve.mul(T3, z_words, z_size, m_coord_z, ws); m_curve.mul(m_coord_z, T3, T4, ws); } void PointGFp::mult2i(size_t iterations, std::vector& ws_bn) { if(iterations == 0) return; if(m_coord_y.is_zero()) { *this = PointGFp(m_curve); // setting myself to zero return; } /* TODO we can save 2 squarings per iteration by computing a*Z^4 using values cached from previous iteration */ for(size_t i = 0; i != iterations; ++i) mult2(ws_bn); } // *this *= 2 void PointGFp::mult2(std::vector& ws_bn) { if(is_zero()) return; if(m_coord_y.is_zero()) { *this = PointGFp(m_curve); // setting myself to zero return; } resize_ws(ws_bn, m_curve.get_ws_size()); secure_vector& ws = ws_bn[0].get_word_vector(); secure_vector& sub_ws = ws_bn[1].get_word_vector(); BigInt& T0 = ws_bn[2]; BigInt& T1 = ws_bn[3]; BigInt& T2 = ws_bn[4]; BigInt& T3 = ws_bn[5]; BigInt& T4 = ws_bn[6]; /* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc */ const BigInt& p = m_curve.get_p(); m_curve.sqr(T0, m_coord_y, ws); m_curve.mul(T1, m_coord_x, T0, ws); T1.mod_mul(4, p, sub_ws); if(m_curve.a_is_zero()) { // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2 m_curve.sqr(T4, m_coord_x, ws); // x^2 T4.mod_mul(3, p, sub_ws); // 3*x^2 } else if(m_curve.a_is_minus_3()) { /* if a == -3 then 3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2) */ m_curve.sqr(T3, m_coord_z, ws); // z^2 // (x-z^2) T2 = m_coord_x; T2.mod_sub(T3, p, sub_ws); // (x+z^2) T3.mod_add(m_coord_x, p, sub_ws); m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2) T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2) } else { m_curve.sqr(T3, m_coord_z, ws); // z^2 m_curve.sqr(T4, T3, ws); // z^4 m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4 m_curve.sqr(T4, m_coord_x, ws); // x^2 T4.mod_mul(3, p, sub_ws); T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4 } m_curve.sqr(T2, T4, ws); T2.mod_sub(T1, p, sub_ws); T2.mod_sub(T1, p, sub_ws); m_curve.sqr(T3, T0, ws); T3.mod_mul(8, p, sub_ws); T1.mod_sub(T2, p, sub_ws); m_curve.mul(T0, T4, T1, ws); T0.mod_sub(T3, p, sub_ws); m_coord_x.swap(T2); m_curve.mul(T2, m_coord_y, m_coord_z, ws); T2.mod_mul(2, p, sub_ws); m_coord_y.swap(T0); m_coord_z.swap(T2); } // arithmetic operators PointGFp& PointGFp::operator+=(const PointGFp& rhs) { std::vector ws(PointGFp::WORKSPACE_SIZE); add(rhs, ws); return *this; } PointGFp& PointGFp::operator-=(const PointGFp& rhs) { PointGFp minus_rhs = PointGFp(rhs).negate(); if(is_zero()) *this = minus_rhs; else *this += minus_rhs; return *this; } PointGFp& PointGFp::operator*=(const BigInt& scalar) { *this = scalar * *this; return *this; } PointGFp operator*(const BigInt& scalar, const PointGFp& point) { BOTAN_DEBUG_ASSERT(point.on_the_curve()); const size_t scalar_bits = scalar.bits(); std::vector ws(PointGFp::WORKSPACE_SIZE); PointGFp R[2] = { point.zero(), point }; for(size_t i = scalar_bits; i > 0; i--) { const size_t b = scalar.get_bit(i - 1); R[b ^ 1].add(R[b], ws); R[b].mult2(ws); } if(scalar.is_negative()) R[0].negate(); BOTAN_DEBUG_ASSERT(R[0].on_the_curve()); return R[0]; } //static void PointGFp::force_all_affine(std::vector& points, secure_vector& ws) { if(points.size() <= 1) { for(size_t i = 0; i != points.size(); ++i) points[i].force_affine(); return; } for(size_t i = 0; i != points.size(); ++i) { if(points[i].is_zero()) throw Invalid_State("Cannot convert zero ECC point to affine"); } /* For >= 2 points use Montgomery's trick See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) TODO is it really necessary to save all k points in c? */ const CurveGFp& curve = points[0].m_curve; const BigInt& rep_1 = curve.get_1_rep(); if(ws.size() < curve.get_ws_size()) ws.resize(curve.get_ws_size()); std::vector c(points.size()); c[0] = points[0].m_coord_z; for(size_t i = 1; i != points.size(); ++i) { curve.mul(c[i], c[i-1], points[i].m_coord_z, ws); } BigInt s_inv = curve.invert_element(c[c.size()-1], ws); BigInt z_inv, z2_inv, z3_inv; for(size_t i = points.size() - 1; i != 0; i--) { PointGFp& point = points[i]; curve.mul(z_inv, s_inv, c[i-1], ws); s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws); curve.sqr(z2_inv, z_inv, ws); curve.mul(z3_inv, z2_inv, z_inv, ws); point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws); point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws); point.m_coord_z = rep_1; } curve.sqr(z2_inv, s_inv, ws); curve.mul(z3_inv, z2_inv, s_inv, ws); points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws); points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws); points[0].m_coord_z = rep_1; } void PointGFp::force_affine() { if(is_zero()) throw Invalid_State("Cannot convert zero ECC point to affine"); secure_vector ws; const BigInt z_inv = m_curve.invert_element(m_coord_z, ws); const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws); const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws); m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws); m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws); m_coord_z = m_curve.get_1_rep(); } bool PointGFp::is_affine() const { return m_curve.is_one(m_coord_z); } BigInt PointGFp::get_affine_x() const { if(is_zero()) throw Illegal_Transformation("Cannot convert zero point to affine"); secure_vector monty_ws; if(is_affine()) return m_curve.from_rep_to_tmp(m_coord_x, monty_ws); BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); z2 = m_curve.invert_element(z2, monty_ws); BigInt r; m_curve.mul(r, m_coord_x, z2, monty_ws); m_curve.from_rep(r, monty_ws); return r; } BigInt PointGFp::get_affine_y() const { if(is_zero()) throw Illegal_Transformation("Cannot convert zero point to affine"); secure_vector monty_ws; if(is_affine()) return m_curve.from_rep_to_tmp(m_coord_y, monty_ws); const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); const BigInt z3_inv = m_curve.invert_element(z3, monty_ws); BigInt r; m_curve.mul(r, m_coord_y, z3_inv, monty_ws); m_curve.from_rep(r, monty_ws); return r; } bool PointGFp::on_the_curve() const { /* Is the point still on the curve?? (If everything is correct, the point is always on its curve; then the function will return true. If somehow the state is corrupted, which suggests a fault attack (or internal computational error), then return false. */ if(is_zero()) return true; secure_vector monty_ws; const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws); const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws); const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws); const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)? { if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws)) return false; } const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws); const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws); if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws)) return false; return true; } // swaps the states of *this and other, does not throw! void PointGFp::swap(PointGFp& other) { m_curve.swap(other.m_curve); m_coord_x.swap(other.m_coord_x); m_coord_y.swap(other.m_coord_y); m_coord_z.swap(other.m_coord_z); } bool PointGFp::operator==(const PointGFp& other) const { if(m_curve != other.m_curve) return false; // If this is zero, only equal if other is also zero if(is_zero()) return other.is_zero(); return (get_affine_x() == other.get_affine_x() && get_affine_y() == other.get_affine_y()); } // encoding and decoding std::vector PointGFp::encode(PointGFp::Compression_Type format) const { if(is_zero()) return std::vector(1); // single 0 byte const size_t p_bytes = m_curve.get_p().bytes(); const BigInt x = get_affine_x(); const BigInt y = get_affine_y(); std::vector result; if(format == PointGFp::UNCOMPRESSED) { result.resize(1 + 2*p_bytes); result[0] = 0x04; BigInt::encode_1363(&result[1], p_bytes, x); BigInt::encode_1363(&result[1+p_bytes], p_bytes, y); } else if(format == PointGFp::COMPRESSED) { result.resize(1 + p_bytes); result[0] = 0x02 | static_cast(y.get_bit(0)); BigInt::encode_1363(&result[1], p_bytes, x); } else if(format == PointGFp::HYBRID) { result.resize(1 + 2*p_bytes); result[0] = 0x06 | static_cast(y.get_bit(0)); BigInt::encode_1363(&result[1], p_bytes, x); BigInt::encode_1363(&result[1+p_bytes], p_bytes, y); } else throw Invalid_Argument("EC2OSP illegal point encoding"); return result; } namespace { BigInt decompress_point(bool yMod2, const BigInt& x, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) { BigInt xpow3 = x * x * x; BigInt g = curve_a * x; g += xpow3; g += curve_b; g = g % curve_p; BigInt z = ressol(g, curve_p); if(z < 0) throw Illegal_Point("error during EC point decompression"); if(z.get_bit(0) != yMod2) z = curve_p - z; return z; } } PointGFp OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) { // Should we really be doing this? if(data_len <= 1) return PointGFp(curve); // return zero std::pair xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b()); PointGFp point(curve, xy.first, xy.second); if(!point.on_the_curve()) throw Illegal_Point("OS2ECP: Decoded point was not on the curve"); return point; } std::pair OS2ECP(const uint8_t data[], size_t data_len, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) { if(data_len <= 1) throw Decoding_Error("OS2ECP invalid point"); const uint8_t pc = data[0]; BigInt x, y; if(pc == 2 || pc == 3) { //compressed form x = BigInt::decode(&data[1], data_len - 1); const bool y_mod_2 = ((pc & 0x01) == 1); y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b); } else if(pc == 4) { const size_t l = (data_len - 1) / 2; // uncompressed form x = BigInt::decode(&data[1], l); y = BigInt::decode(&data[l+1], l); } else if(pc == 6 || pc == 7) { const size_t l = (data_len - 1) / 2; // hybrid form x = BigInt::decode(&data[1], l); y = BigInt::decode(&data[l+1], l); const bool y_mod_2 = ((pc & 0x01) == 1); if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y) throw Illegal_Point("OS2ECP: Decoding error in hybrid format"); } else throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc)); return std::make_pair(x, y); } } /* * (C) 2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace { size_t blinding_size(const BigInt& group_order) { return (group_order.bits() + 1) / 2; } } PointGFp multi_exponentiate(const PointGFp& x, const BigInt& z1, const PointGFp& y, const BigInt& z2) { PointGFp_Multi_Point_Precompute xy_mul(x, y); return xy_mul.multi_exp(z1, z2); } Blinded_Point_Multiply::Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h) : m_ws(PointGFp::WORKSPACE_SIZE), m_order(order) { BOTAN_UNUSED(h); Null_RNG null_rng; m_point_mul.reset(new PointGFp_Var_Point_Precompute(base, null_rng, m_ws)); } Blinded_Point_Multiply::~Blinded_Point_Multiply() { /* for ~unique_ptr */ } PointGFp Blinded_Point_Multiply::blinded_multiply(const BigInt& scalar, RandomNumberGenerator& rng) { return m_point_mul->mul(scalar, rng, m_order, m_ws); } PointGFp_Base_Point_Precompute::PointGFp_Base_Point_Precompute(const PointGFp& base, const Modular_Reducer& mod_order) : m_base_point(base), m_mod_order(mod_order), m_p_words(base.get_curve().get_p().sig_words()) { std::vector ws(PointGFp::WORKSPACE_SIZE); const size_t p_bits = base.get_curve().get_p().bits(); /* * Some of the curves (eg secp160k1) have an order slightly larger than * the size of the prime modulus. In all cases they are at most 1 bit * longer. The +1 compensates for this. */ const size_t T_bits = round_up(p_bits + blinding_size(mod_order.get_modulus()) + 1, WINDOW_BITS) / WINDOW_BITS; std::vector T(WINDOW_SIZE*T_bits); PointGFp g = base; PointGFp g2, g4; for(size_t i = 0; i != T_bits; i++) { g2 = g; g2.mult2(ws); g4 = g2; g4.mult2(ws); T[7*i+0] = g; T[7*i+1] = std::move(g2); T[7*i+2] = T[7*i+1].plus(T[7*i+0], ws); // g2+g T[7*i+3] = g4; T[7*i+4] = T[7*i+3].plus(T[7*i+0], ws); // g4+g T[7*i+5] = T[7*i+3].plus(T[7*i+1], ws); // g4+g2 T[7*i+6] = T[7*i+3].plus(T[7*i+2], ws); // g4+g2+g g.swap(g4); g.mult2(ws); } PointGFp::force_all_affine(T, ws[0].get_word_vector()); m_W.resize(T.size() * 2 * m_p_words); word* p = &m_W[0]; for(size_t i = 0; i != T.size(); ++i) { T[i].get_x().encode_words(p, m_p_words); p += m_p_words; T[i].get_y().encode_words(p, m_p_words); p += m_p_words; } } PointGFp PointGFp_Base_Point_Precompute::mul(const BigInt& k, RandomNumberGenerator& rng, const BigInt& group_order, std::vector& ws) const { if(k.is_negative()) throw Invalid_Argument("PointGFp_Base_Point_Precompute scalar must be positive"); // Instead of reducing k mod group order should we alter the mask size?? BigInt scalar = m_mod_order.reduce(k); if(rng.is_seeded()) { // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) const BigInt mask(rng, blinding_size(group_order)); scalar += group_order * mask; } else { /* When we don't have an RNG we cannot do scalar blinding. Instead use the same trick as OpenSSL and add one or two copies of the order to normalize the length of the scalar at order.bits()+1. This at least ensures the loop bound does not leak information about the high bits of the scalar. */ scalar += group_order; if(scalar.bits() == group_order.bits()) scalar += group_order; BOTAN_DEBUG_ASSERT(scalar.bits() == group_order.bits() + 1); } const size_t windows = round_up(scalar.bits(), WINDOW_BITS) / WINDOW_BITS; const size_t elem_size = 2*m_p_words; BOTAN_ASSERT(windows <= m_W.size() / (3*elem_size), "Precomputed sufficient values for scalar mult"); PointGFp R = m_base_point.zero(); if(ws.size() < PointGFp::WORKSPACE_SIZE) ws.resize(PointGFp::WORKSPACE_SIZE); // the precomputed multiples are not secret so use std::vector std::vector Wt(elem_size); for(size_t i = 0; i != windows; ++i) { const size_t window = windows - i - 1; const size_t base_addr = (WINDOW_SIZE*window)*elem_size; const word w = scalar.get_substring(WINDOW_BITS*window, WINDOW_BITS); const auto w_is_1 = CT::Mask::is_equal(w, 1); const auto w_is_2 = CT::Mask::is_equal(w, 2); const auto w_is_3 = CT::Mask::is_equal(w, 3); const auto w_is_4 = CT::Mask::is_equal(w, 4); const auto w_is_5 = CT::Mask::is_equal(w, 5); const auto w_is_6 = CT::Mask::is_equal(w, 6); const auto w_is_7 = CT::Mask::is_equal(w, 7); for(size_t j = 0; j != elem_size; ++j) { const word w1 = w_is_1.if_set_return(m_W[base_addr + 0*elem_size + j]); const word w2 = w_is_2.if_set_return(m_W[base_addr + 1*elem_size + j]); const word w3 = w_is_3.if_set_return(m_W[base_addr + 2*elem_size + j]); const word w4 = w_is_4.if_set_return(m_W[base_addr + 3*elem_size + j]); const word w5 = w_is_5.if_set_return(m_W[base_addr + 4*elem_size + j]); const word w6 = w_is_6.if_set_return(m_W[base_addr + 5*elem_size + j]); const word w7 = w_is_7.if_set_return(m_W[base_addr + 6*elem_size + j]); Wt[j] = w1 | w2 | w3 | w4 | w5 | w6 | w7; } R.add_affine(&Wt[0], m_p_words, &Wt[m_p_words], m_p_words, ws); if(i == 0 && rng.is_seeded()) { /* * Since we start with the top bit of the exponent we know the * first window must have a non-zero element, and thus R is * now a point other than the point at infinity. */ BOTAN_DEBUG_ASSERT(w != 0); R.randomize_repr(rng, ws[0].get_word_vector()); } } BOTAN_DEBUG_ASSERT(R.on_the_curve()); return R; } PointGFp_Var_Point_Precompute::PointGFp_Var_Point_Precompute(const PointGFp& point, RandomNumberGenerator& rng, std::vector& ws) : m_curve(point.get_curve()), m_p_words(m_curve.get_p().sig_words()), m_window_bits(4) { if(ws.size() < PointGFp::WORKSPACE_SIZE) ws.resize(PointGFp::WORKSPACE_SIZE); std::vector U(static_cast(1) << m_window_bits); U[0] = point.zero(); U[1] = point; for(size_t i = 2; i < U.size(); i += 2) { U[i] = U[i/2].double_of(ws); U[i+1] = U[i].plus(point, ws); } // Hack to handle Blinded_Point_Multiply if(rng.is_seeded()) { BigInt& mask = ws[0]; BigInt& mask2 = ws[1]; BigInt& mask3 = ws[2]; BigInt& new_x = ws[3]; BigInt& new_y = ws[4]; BigInt& new_z = ws[5]; secure_vector& tmp = ws[6].get_word_vector(); const CurveGFp& curve = U[0].get_curve(); const size_t p_bits = curve.get_p().bits(); // Skipping zero point since it can't be randomized for(size_t i = 1; i != U.size(); ++i) { mask.randomize(rng, p_bits - 1, false); // Easy way of ensuring mask != 0 mask.set_bit(0); curve.sqr(mask2, mask, tmp); curve.mul(mask3, mask, mask2, tmp); curve.mul(new_x, U[i].get_x(), mask2, tmp); curve.mul(new_y, U[i].get_y(), mask3, tmp); curve.mul(new_z, U[i].get_z(), mask, tmp); U[i].swap_coords(new_x, new_y, new_z); } } m_T.resize(U.size() * 3 * m_p_words); word* p = &m_T[0]; for(size_t i = 0; i != U.size(); ++i) { U[i].get_x().encode_words(p , m_p_words); U[i].get_y().encode_words(p + m_p_words, m_p_words); U[i].get_z().encode_words(p + 2*m_p_words, m_p_words); p += 3*m_p_words; } } PointGFp PointGFp_Var_Point_Precompute::mul(const BigInt& k, RandomNumberGenerator& rng, const BigInt& group_order, std::vector& ws) const { if(k.is_negative()) throw Invalid_Argument("PointGFp_Var_Point_Precompute scalar must be positive"); if(ws.size() < PointGFp::WORKSPACE_SIZE) ws.resize(PointGFp::WORKSPACE_SIZE); // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) const BigInt mask(rng, blinding_size(group_order), false); const BigInt scalar = k + group_order * mask; const size_t elem_size = 3*m_p_words; const size_t window_elems = (1ULL << m_window_bits); size_t windows = round_up(scalar.bits(), m_window_bits) / m_window_bits; PointGFp R(m_curve); secure_vector e(elem_size); if(windows > 0) { windows--; const uint32_t w = scalar.get_substring(windows*m_window_bits, m_window_bits); clear_mem(e.data(), e.size()); for(size_t i = 1; i != window_elems; ++i) { const auto wmask = CT::Mask::is_equal(w, i); for(size_t j = 0; j != elem_size; ++j) { e[j] |= wmask.if_set_return(m_T[i * elem_size + j]); } } R.add(&e[0], m_p_words, &e[m_p_words], m_p_words, &e[2*m_p_words], m_p_words, ws); /* Randomize after adding the first nibble as before the addition R is zero, and we cannot effectively randomize the point representation of the zero point. */ R.randomize_repr(rng, ws[0].get_word_vector()); } while(windows) { R.mult2i(m_window_bits, ws); const uint32_t w = scalar.get_substring((windows-1)*m_window_bits, m_window_bits); clear_mem(e.data(), e.size()); for(size_t i = 1; i != window_elems; ++i) { const auto wmask = CT::Mask::is_equal(w, i); for(size_t j = 0; j != elem_size; ++j) { e[j] |= wmask.if_set_return(m_T[i * elem_size + j]); } } R.add(&e[0], m_p_words, &e[m_p_words], m_p_words, &e[2*m_p_words], m_p_words, ws); windows--; } BOTAN_DEBUG_ASSERT(R.on_the_curve()); return R; } PointGFp_Multi_Point_Precompute::PointGFp_Multi_Point_Precompute(const PointGFp& x, const PointGFp& y) { std::vector ws(PointGFp::WORKSPACE_SIZE); PointGFp x2 = x; x2.mult2(ws); const PointGFp x3(x2.plus(x, ws)); PointGFp y2 = y; y2.mult2(ws); const PointGFp y3(y2.plus(y, ws)); m_M.reserve(15); m_M.push_back(x); m_M.push_back(x2); m_M.push_back(x3); m_M.push_back(y); m_M.push_back(y.plus(x, ws)); m_M.push_back(y.plus(x2, ws)); m_M.push_back(y.plus(x3, ws)); m_M.push_back(y2); m_M.push_back(y2.plus(x, ws)); m_M.push_back(y2.plus(x2, ws)); m_M.push_back(y2.plus(x3, ws)); m_M.push_back(y3); m_M.push_back(y3.plus(x, ws)); m_M.push_back(y3.plus(x2, ws)); m_M.push_back(y3.plus(x3, ws)); bool no_infinity = true; for(auto& pt : m_M) { if(pt.is_zero()) no_infinity = false; } if(no_infinity) { PointGFp::force_all_affine(m_M, ws[0].get_word_vector()); } m_no_infinity = no_infinity; } PointGFp PointGFp_Multi_Point_Precompute::multi_exp(const BigInt& z1, const BigInt& z2) const { std::vector ws(PointGFp::WORKSPACE_SIZE); const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); PointGFp H = m_M[0].zero(); for(size_t i = 0; i != z_bits; i += 2) { if(i > 0) { H.mult2i(2, ws); } const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2); const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2); const uint32_t z12 = (4*z2_b) + z1_b; // This function is not intended to be const time if(z12) { if(m_no_infinity) H.add_affine(m_M[z12-1], ws); else H.add(m_M[z12-1], ws); } } if(z1.is_negative() != z2.is_negative()) H.negate(); return H; } } /* * ECC Key implemenation * (C) 2007 Manuel Hartl, FlexSecure GmbH * Falko Strenzke, FlexSecure GmbH * 2008-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t EC_PublicKey::key_length() const { return domain().get_p_bits(); } size_t EC_PublicKey::estimated_strength() const { return ecp_work_factor(key_length()); } EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, const PointGFp& pub_point) : m_domain_params(dom_par), m_public_key(pub_point) { if (!dom_par.get_curve_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; #if 0 if(domain().get_curve() != public_point().get_curve()) throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); #endif } EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, const std::vector& key_bits) : m_domain_params{EC_Group(alg_id.get_parameters())}, m_public_key{domain().OS2ECP(key_bits)} { if (!domain().get_curve_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; } bool EC_PublicKey::check_key(RandomNumberGenerator& rng, bool) const { return m_domain_params.verify_group(rng) && m_domain_params.verify_public_element(public_point()); } AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), DER_domain()); } std::vector EC_PublicKey::public_key_bits() const { return public_point().encode(point_encoding()); } void EC_PublicKey::set_point_encoding(PointGFp::Compression_Type enc) { if(enc != PointGFp::COMPRESSED && enc != PointGFp::UNCOMPRESSED && enc != PointGFp::HYBRID) throw Invalid_Argument("Invalid point encoding for EC_PublicKey"); m_point_encoding = enc; } void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) { if(form != EC_DOMPAR_ENC_EXPLICIT && form != EC_DOMPAR_ENC_IMPLICITCA && form != EC_DOMPAR_ENC_OID) throw Invalid_Argument("Invalid encoding form for EC-key object specified"); if((form == EC_DOMPAR_ENC_OID) && (m_domain_params.get_curve_oid().empty())) throw Invalid_Argument("Invalid encoding form OID specified for " "EC-key object whose corresponding domain " "parameters are without oid"); m_domain_encoding = form; } const BigInt& EC_PrivateKey::private_value() const { if(m_private_key == 0) throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); return m_private_key; } /** * EC_PrivateKey constructor */ EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, const EC_Group& ec_group, const BigInt& x, bool with_modular_inverse) { m_domain_params = ec_group; if (!ec_group.get_curve_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; if(x == 0) { m_private_key = ec_group.random_scalar(rng); } else { m_private_key = x; } std::vector ws; if(with_modular_inverse) { // ECKCDSA m_public_key = domain().blinded_base_point_multiply( m_domain_params.inverse_mod_order(m_private_key), rng, ws); } else { m_public_key = domain().blinded_base_point_multiply(m_private_key, rng, ws); } BOTAN_ASSERT(m_public_key.on_the_curve(), "Generated public key point was on the curve"); } secure_vector EC_PrivateKey::private_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) .encode(static_cast(1)) .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), OCTET_STRING) .start_cons(ASN1_Tag(1), PRIVATE) .encode(m_public_key.encode(PointGFp::Compression_Type::UNCOMPRESSED), BIT_STRING) .end_cons() .end_cons() .get_contents(); } EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits, bool with_modular_inverse) { m_domain_params = EC_Group(alg_id.get_parameters()); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; if (!domain().get_curve_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; OID key_parameters; secure_vector public_key_bits; BER_Decoder(key_bits) .start_cons(SEQUENCE) .decode_and_check(1, "Unknown version code for ECC key") .decode_octet_string_bigint(m_private_key) .decode_optional(key_parameters, ASN1_Tag(0), PRIVATE) .decode_optional_string(public_key_bits, BIT_STRING, 1, PRIVATE) .end_cons(); if(public_key_bits.empty()) { if(with_modular_inverse) { // ECKCDSA m_public_key = domain().get_base_point() * m_domain_params.inverse_mod_order(m_private_key); } else { m_public_key = domain().get_base_point() * m_private_key; } BOTAN_ASSERT(m_public_key.on_the_curve(), "Public point derived from loaded key was on the curve"); } else { m_public_key = domain().OS2ECP(public_key_bits); // OS2ECP verifies that the point is on the curve } } } /* * ECDH implemenation * (C) 2007 Manuel Hartl, FlexSecure GmbH * 2007 Falko Strenzke, FlexSecure GmbH * 2008-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_OPENSSL) #endif namespace Botan { namespace { /** * ECDH operation */ class ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF { public: ECDH_KA_Operation(const ECDH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : PK_Ops::Key_Agreement_with_KDF(kdf), m_group(key.domain()), m_rng(rng) { m_l_times_priv = m_group.inverse_mod_order(m_group.get_cofactor()) * key.private_value(); } size_t agreed_value_size() const override { return m_group.get_p_bytes(); } secure_vector raw_agree(const uint8_t w[], size_t w_len) override { PointGFp input_point = m_group.get_cofactor() * m_group.OS2ECP(w, w_len); input_point.randomize_repr(m_rng); const PointGFp S = m_group.blinded_var_point_multiply( input_point, m_l_times_priv, m_rng, m_ws); if(S.on_the_curve() == false) throw Internal_Error("ECDH agreed value was not on the curve"); return BigInt::encode_1363(S.get_affine_x(), m_group.get_p_bytes()); } private: const EC_Group m_group; BigInt m_l_times_priv; RandomNumberGenerator& m_rng; std::vector m_ws; }; } std::unique_ptr ECDH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { try { return make_openssl_ecdh_ka_op(*this, params); } catch(Lookup_Error&) { if(provider == "openssl") throw; } } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new ECDH_KA_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } } /* * ECDSA implemenation * (C) 2007 Manuel Hartl, FlexSecure GmbH * 2007 Falko Strenzke, FlexSecure GmbH * 2008-2010,2015,2016,2018 Jack Lloyd * 2016 René Korthaus * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_RFC6979_GENERATOR) #endif #if defined(BOTAN_HAS_OPENSSL) #endif namespace Botan { namespace { PointGFp recover_ecdsa_public_key(const EC_Group& group, const std::vector& msg, const BigInt& r, const BigInt& s, uint8_t v) { if(group.get_cofactor() != 1) throw Invalid_Argument("ECDSA public key recovery only supported for prime order groups"); if(v > 4) throw Invalid_Argument("Unexpected v param for ECDSA public key recovery"); const uint8_t y_odd = v % 2; const uint8_t add_order = v >> 1; const BigInt& group_order = group.get_order(); const size_t p_bytes = group.get_p_bytes(); try { const BigInt e(msg.data(), msg.size(), group.get_order_bits()); const BigInt r_inv = group.inverse_mod_order(r); BigInt x = r + add_order*group_order; std::vector X(p_bytes + 1); X[0] = 0x02 | y_odd; BigInt::encode_1363(&X[1], p_bytes, x); const PointGFp R = group.OS2ECP(X); if((R*group_order).is_zero() == false) throw Decoding_Error("Unable to recover ECDSA public key"); // Compute r_inv * (s*R - eG) PointGFp_Multi_Point_Precompute RG_mul(R, group.get_base_point()); const BigInt ne = group.mod_order(group_order - e); return r_inv * RG_mul.multi_exp(s, ne); } catch(...) { // continue on and throw } throw Decoding_Error("Failed to recover ECDSA public key from signature/msg pair"); } } ECDSA_PublicKey::ECDSA_PublicKey(const EC_Group& group, const std::vector& msg, const BigInt& r, const BigInt& s, uint8_t v) : EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {} uint8_t ECDSA_PublicKey::recovery_param(const std::vector& msg, const BigInt& r, const BigInt& s) const { for(uint8_t v = 0; v != 4; ++v) { try { PointGFp R = recover_ecdsa_public_key(this->domain(), msg, r, s, v); if(R == this->public_point()) { return v; } } catch(Decoding_Error&) { // try the next v } } throw Internal_Error("Could not determine ECDSA recovery parameter"); } bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!public_point().on_the_curve()) return false; if(!strong) return true; return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); } namespace { /** * ECDSA signature operation */ class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA { public: ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa, RandomNumberGenerator& rng) : PK_Ops::Signature_with_EMSA(emsa), m_group(ecdsa.domain()), m_x(ecdsa.private_value()) { #if defined(BOTAN_HAS_RFC6979_GENERATOR) m_rfc6979.reset(new RFC6979_Nonce_Generator(hash_for_emsa(emsa), m_group.get_order(), m_x)); #endif m_b = m_group.random_scalar(rng); m_b_inv = m_group.inverse_mod_order(m_b); } size_t signature_length() const override { return 2*m_group.get_order_bytes(); } size_t max_input_bits() const override { return m_group.get_order_bits(); } secure_vector raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; private: const EC_Group m_group; const BigInt& m_x; #if defined(BOTAN_HAS_RFC6979_GENERATOR) std::unique_ptr m_rfc6979; #endif std::vector m_ws; BigInt m_b, m_b_inv; }; secure_vector ECDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) { BigInt m(msg, msg_len, m_group.get_order_bits()); #if defined(BOTAN_HAS_RFC6979_GENERATOR) const BigInt k = m_rfc6979->nonce_for(m); #else const BigInt k = m_group.random_scalar(rng); #endif const BigInt r = m_group.mod_order( m_group.blinded_base_point_multiply_x(k, rng, m_ws)); const BigInt k_inv = m_group.inverse_mod_order(k); /* * Blind the input message and compute x*r+m as (x*r*b + m*b)/b */ m_b = m_group.square_mod_order(m_b); m_b_inv = m_group.square_mod_order(m_b_inv); m = m_group.multiply_mod_order(m_b, m_group.mod_order(m)); const BigInt xr_m = m_group.mod_order(m_group.multiply_mod_order(m_x, m_b, r) + m); const BigInt s = m_group.multiply_mod_order(k_inv, xr_m, m_b_inv); // With overwhelming probability, a bug rather than actual zero r/s if(r.is_zero() || s.is_zero()) throw Internal_Error("During ECDSA signature generated zero r/s"); return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); } /** * ECDSA verification operation */ class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA { public: ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa) : PK_Ops::Verification_with_EMSA(emsa), m_group(ecdsa.domain()), m_gy_mul(m_group.get_base_point(), ecdsa.public_point()) { } size_t max_input_bits() const override { return m_group.get_order_bits(); } bool with_recovery() const override { return false; } bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override; private: const EC_Group m_group; const PointGFp_Multi_Point_Precompute m_gy_mul; }; bool ECDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) { if(sig_len != m_group.get_order_bytes() * 2) return false; const BigInt e(msg, msg_len, m_group.get_order_bits()); const BigInt r(sig, sig_len / 2); const BigInt s(sig + sig_len / 2, sig_len / 2); if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) return false; const BigInt w = m_group.inverse_mod_order(s); const BigInt u1 = m_group.multiply_mod_order(m_group.mod_order(e), w); const BigInt u2 = m_group.multiply_mod_order(r, w); const PointGFp R = m_gy_mul.multi_exp(u1, u2); if(R.is_zero()) return false; const BigInt v = m_group.mod_order(R.get_affine_x()); return (v == r); } } std::unique_ptr ECDSA_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { try { return make_openssl_ecdsa_ver_op(*this, params); } catch(Lookup_Error& e) { if(provider == "openssl") throw; } } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new ECDSA_Verification_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { try { return make_openssl_ecdsa_sig_op(*this, params); } catch(Lookup_Error& e) { if(provider == "openssl") throw; } } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new ECDSA_Signature_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } } /* * ECGDSA (BSI-TR-03111, version 2.0) * (C) 2016 René Korthaus * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!public_point().on_the_curve()) return false; if(!strong) return true; return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); } namespace { /** * ECGDSA signature operation */ class ECGDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA { public: ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, const std::string& emsa) : PK_Ops::Signature_with_EMSA(emsa), m_group(ecgdsa.domain()), m_x(ecgdsa.private_value()) { } secure_vector raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; size_t signature_length() const override { return 2*m_group.get_order_bytes(); } size_t max_input_bits() const override { return m_group.get_order_bits(); } private: const EC_Group m_group; const BigInt& m_x; std::vector m_ws; }; secure_vector ECGDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) { const BigInt m(msg, msg_len, m_group.get_order_bits()); const BigInt k = m_group.random_scalar(rng); const BigInt r = m_group.mod_order( m_group.blinded_base_point_multiply_x(k, rng, m_ws)); const BigInt kr = m_group.multiply_mod_order(k, r); const BigInt s = m_group.multiply_mod_order(m_x, kr - m); // With overwhelming probability, a bug rather than actual zero r/s if(r.is_zero() || s.is_zero()) throw Internal_Error("During ECGDSA signature generated zero r/s"); return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); } /** * ECGDSA verification operation */ class ECGDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA { public: ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, const std::string& emsa) : PK_Ops::Verification_with_EMSA(emsa), m_group(ecgdsa.domain()), m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) { } size_t max_input_bits() const override { return m_group.get_order_bits(); } bool with_recovery() const override { return false; } bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override; private: const EC_Group m_group; const PointGFp_Multi_Point_Precompute m_gy_mul; }; bool ECGDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) { if(sig_len != m_group.get_order_bytes() * 2) return false; const BigInt e(msg, msg_len, m_group.get_order_bits()); const BigInt r(sig, sig_len / 2); const BigInt s(sig + sig_len / 2, sig_len / 2); if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) return false; const BigInt w = m_group.inverse_mod_order(r); const BigInt u1 = m_group.multiply_mod_order(e, w); const BigInt u2 = m_group.multiply_mod_order(s, w); const PointGFp R = m_gy_mul.multi_exp(u1, u2); if(R.is_zero()) return false; const BigInt v = m_group.mod_order(R.get_affine_x()); return (v == r); } } std::unique_ptr ECGDSA_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new ECGDSA_Verification_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr ECGDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new ECGDSA_Signature_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } } /* * ECIES * (C) 2016 Philipp Weber * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /** * Private key type for ECIES_ECDH_KA_Operation */ class ECIES_PrivateKey final : public EC_PrivateKey, public PK_Key_Agreement_Key { public: explicit ECIES_PrivateKey(const ECDH_PrivateKey& private_key) : EC_PublicKey(private_key), EC_PrivateKey(private_key), PK_Key_Agreement_Key(), m_key(private_key) { } std::vector public_value() const override { return m_key.public_value(); } std::string algo_name() const override { return "ECIES"; } std::unique_ptr create_key_agreement_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const override; private: ECDH_PrivateKey m_key; }; /** * Implements ECDH key agreement without using the cofactor mode */ class ECIES_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF { public: ECIES_ECDH_KA_Operation(const ECIES_PrivateKey& private_key, RandomNumberGenerator& rng) : PK_Ops::Key_Agreement_with_KDF("Raw"), m_key(private_key), m_rng(rng) { } size_t agreed_value_size() const override { return m_key.domain().get_p_bytes(); } secure_vector raw_agree(const uint8_t w[], size_t w_len) override { const EC_Group& group = m_key.domain(); PointGFp input_point = group.OS2ECP(w, w_len); input_point.randomize_repr(m_rng); const PointGFp S = group.blinded_var_point_multiply( input_point, m_key.private_value(), m_rng, m_ws); if(S.on_the_curve() == false) throw Internal_Error("ECDH agreed value was not on the curve"); return BigInt::encode_1363(S.get_affine_x(), group.get_p_bytes()); } private: ECIES_PrivateKey m_key; RandomNumberGenerator& m_rng; std::vector m_ws; }; std::unique_ptr ECIES_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, const std::string& /*params*/, const std::string& /*provider*/) const { return std::unique_ptr(new ECIES_ECDH_KA_Operation(*this, rng)); } /** * Creates a PK_Key_Agreement instance for the given key and ecies_params * Returns either ECIES_ECDH_KA_Operation or the default implementation for the given key, * depending on the key and ecies_params * @param private_key the private key used for the key agreement * @param ecies_params settings for ecies * @param for_encryption disable cofactor mode if the secret will be used for encryption * (according to ISO 18033 cofactor mode is only used during decryption) */ PK_Key_Agreement create_key_agreement(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params, bool for_encryption, RandomNumberGenerator& rng) { const ECDH_PrivateKey* ecdh_key = dynamic_cast(&private_key); if(ecdh_key == nullptr && (ecies_params.cofactor_mode() || ecies_params.old_cofactor_mode() || ecies_params.check_mode())) { // assume we have a private key from an external provider (e.g. pkcs#11): // there is no way to determine or control whether the provider uses cofactor mode or not. // ISO 18033 does not allow cofactor mode in combination with old cofactor mode or check mode // => disable cofactor mode, old cofactor mode and check mode for unknown keys/providers (as a precaution). throw Invalid_Argument("ECIES: cofactor, old cofactor and check mode are only supported for ECDH_PrivateKey"); } if(ecdh_key && (for_encryption || !ecies_params.cofactor_mode())) { // ECDH_KA_Operation uses cofactor mode: use own key agreement method if cofactor should not be used. return PK_Key_Agreement(ECIES_PrivateKey(*ecdh_key), rng, "Raw"); } return PK_Key_Agreement(private_key, rng, "Raw"); // use default implementation } } ECIES_KA_Operation::ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params, bool for_encryption, RandomNumberGenerator& rng) : m_ka(create_key_agreement(private_key, ecies_params, for_encryption, rng)), m_params(ecies_params) { } /** * ECIES secret derivation according to ISO 18033-2 */ SymmetricKey ECIES_KA_Operation::derive_secret(const std::vector& eph_public_key_bin, const PointGFp& other_public_key_point) const { if(other_public_key_point.is_zero()) { throw Invalid_Argument("ECIES: other public key point is zero"); } std::unique_ptr kdf = Botan::KDF::create_or_throw(m_params.kdf_spec()); PointGFp other_point = other_public_key_point; // ISO 18033: step b if(m_params.old_cofactor_mode()) { other_point *= m_params.domain().get_cofactor(); } secure_vector derivation_input; // ISO 18033: encryption step e / decryption step g if(!m_params.single_hash_mode()) { derivation_input += eph_public_key_bin; } // ISO 18033: encryption step f / decryption step h std::vector other_public_key_bin = other_point.encode(m_params.compression_type()); // Note: the argument `m_params.secret_length()` passed for `key_len` will only be used by providers because // "Raw" is passed to the `PK_Key_Agreement` if the implementation of botan is used. const SymmetricKey peh = m_ka.derive_key(m_params.domain().get_order().bytes(), other_public_key_bin.data(), other_public_key_bin.size()); derivation_input.insert(derivation_input.end(), peh.begin(), peh.end()); // ISO 18033: encryption step g / decryption step i return kdf->derive_key(m_params.secret_length(), derivation_input); } ECIES_KA_Params::ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length, PointGFp::Compression_Type compression_type, ECIES_Flags flags) : m_domain(domain), m_kdf_spec(kdf_spec), m_length(length), m_compression_mode(compression_type), m_flags(flags) { } ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec, size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len, PointGFp::Compression_Type compression_type, ECIES_Flags flags) : ECIES_KA_Params(domain, kdf_spec, dem_key_len + mac_key_len, compression_type, flags), m_dem_spec(dem_algo_spec), m_dem_keylen(dem_key_len), m_mac_spec(mac_spec), m_mac_keylen(mac_key_len) { // ISO 18033: "At most one of CofactorMode, OldCofactorMode, and CheckMode may be 1." if(size_t(cofactor_mode()) + size_t(old_cofactor_mode()) + size_t(check_mode()) > 1) { throw Invalid_Argument("ECIES: only one of cofactor_mode, old_cofactor_mode and check_mode can be set"); } } ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec, size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len) : ECIES_System_Params(domain, kdf_spec, dem_algo_spec, dem_key_len, mac_spec, mac_key_len, PointGFp::UNCOMPRESSED, ECIES_Flags::NONE) { } std::unique_ptr ECIES_System_Params::create_mac() const { return Botan::MessageAuthenticationCode::create_or_throw(m_mac_spec); } std::unique_ptr ECIES_System_Params::create_cipher(Botan::Cipher_Dir direction) const { return Cipher_Mode::create_or_throw(m_dem_spec, direction); } /* * ECIES_Encryptor Constructor */ ECIES_Encryptor::ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params, RandomNumberGenerator& rng) : m_ka(private_key, ecies_params, true, rng), m_params(ecies_params), m_eph_public_key_bin(private_key.public_value()), // returns the uncompressed public key, see conversion below m_iv(), m_other_point(), m_label() { if(ecies_params.compression_type() != PointGFp::UNCOMPRESSED) { // ISO 18033: step d // convert only if necessary; m_eph_public_key_bin has been initialized with the uncompressed format m_eph_public_key_bin = m_params.domain().OS2ECP(m_eph_public_key_bin).encode(ecies_params.compression_type()); } m_mac = m_params.create_mac(); m_cipher = m_params.create_cipher(ENCRYPTION); } /* * ECIES_Encryptor Constructor */ ECIES_Encryptor::ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params) : ECIES_Encryptor(ECDH_PrivateKey(rng, ecies_params.domain()), ecies_params, rng) { } size_t ECIES_Encryptor::maximum_input_size() const { /* ECIES should just be used for key transport so this (arbitrary) limit seems sufficient */ return 64; } size_t ECIES_Encryptor::ciphertext_length(size_t ptext_len) const { return m_eph_public_key_bin.size() + m_mac->output_length() + m_cipher->output_length(ptext_len); } /* * ECIES Encryption according to ISO 18033-2 */ std::vector ECIES_Encryptor::enc(const uint8_t data[], size_t length, RandomNumberGenerator&) const { if(m_other_point.is_zero()) { throw Invalid_State("ECIES: the other key is zero"); } const SymmetricKey secret_key = m_ka.derive_secret(m_eph_public_key_bin, m_other_point); // encryption m_cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen())); if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) throw Invalid_Argument("ECIES with " + m_cipher->name() + " requires an IV be set"); m_cipher->start(m_iv.bits_of()); secure_vector encrypted_data(data, data + length); m_cipher->finish(encrypted_data); // concat elements std::vector out(m_eph_public_key_bin.size() + encrypted_data.size() + m_mac->output_length()); buffer_insert(out, 0, m_eph_public_key_bin); buffer_insert(out, m_eph_public_key_bin.size(), encrypted_data); // mac m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen()); m_mac->update(encrypted_data); if(!m_label.empty()) { m_mac->update(m_label); } m_mac->final(out.data() + m_eph_public_key_bin.size() + encrypted_data.size()); return out; } ECIES_Decryptor::ECIES_Decryptor(const PK_Key_Agreement_Key& key, const ECIES_System_Params& ecies_params, RandomNumberGenerator& rng) : m_ka(key, ecies_params, false, rng), m_params(ecies_params), m_iv(), m_label() { // ISO 18033: "If v > 1 and CheckMode = 0, then we must have gcd(u, v) = 1." (v = index, u= order) if(!ecies_params.check_mode()) { const Botan::BigInt& cofactor = m_params.domain().get_cofactor(); if(cofactor > 1 && Botan::gcd(cofactor, m_params.domain().get_order()) != 1) { throw Invalid_Argument("ECIES: gcd of cofactor and order must be 1 if check_mode is 0"); } } m_mac = m_params.create_mac(); m_cipher = m_params.create_cipher(DECRYPTION); } size_t ECIES_Decryptor::plaintext_length(size_t ctext_len) const { const size_t point_size = m_params.domain().point_size(m_params.compression_type()); const size_t overhead = point_size + m_mac->output_length(); if(ctext_len < overhead) return 0; return m_cipher->output_length(ctext_len - overhead); } /** * ECIES Decryption according to ISO 18033-2 */ secure_vector ECIES_Decryptor::do_decrypt(uint8_t& valid_mask, const uint8_t in[], size_t in_len) const { const size_t point_size = m_params.domain().point_size(m_params.compression_type()); if(in_len < point_size + m_mac->output_length()) { throw Decoding_Error("ECIES decryption: ciphertext is too short"); } // extract data const std::vector other_public_key_bin(in, in + point_size); // the received (ephemeral) public key const std::vector encrypted_data(in + point_size, in + in_len - m_mac->output_length()); const std::vector mac_data(in + in_len - m_mac->output_length(), in + in_len); // ISO 18033: step a PointGFp other_public_key = m_params.domain().OS2ECP(other_public_key_bin); // ISO 18033: step b if(m_params.check_mode() && !other_public_key.on_the_curve()) { throw Decoding_Error("ECIES decryption: received public key is not on the curve"); } // ISO 18033: step e (and step f because get_affine_x (called by ECDH_KA_Operation::raw_agree) // throws Illegal_Transformation if the point is zero) const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key); // validate mac m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen()); m_mac->update(encrypted_data); if(!m_label.empty()) { m_mac->update(m_label); } const secure_vector calculated_mac = m_mac->final(); valid_mask = ct_compare_u8(mac_data.data(), calculated_mac.data(), mac_data.size()); if(valid_mask) { // decrypt data m_cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen())); if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) throw Invalid_Argument("ECIES with " + m_cipher->name() + " requires an IV be set"); m_cipher->start(m_iv.bits_of()); try { // the decryption can fail: // e.g. Invalid_Authentication_Tag is thrown if GCM is used and the message does not have a valid tag secure_vector decrypted_data(encrypted_data.begin(), encrypted_data.end()); m_cipher->finish(decrypted_data); return decrypted_data; } catch(...) { valid_mask = 0; } } return secure_vector(); } } /* * ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009) * (C) 2016 René Korthaus, Sirrix AG * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!public_point().on_the_curve()) { return false; } if(!strong) { return true; } return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); } namespace { /** * ECKCDSA signature operation */ class ECKCDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA { public: ECKCDSA_Signature_Operation(const ECKCDSA_PrivateKey& eckcdsa, const std::string& emsa) : PK_Ops::Signature_with_EMSA(emsa), m_group(eckcdsa.domain()), m_x(eckcdsa.private_value()), m_prefix() { const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); m_prefix.resize(public_point_x.bytes() + public_point_y.bytes()); public_point_x.binary_encode(m_prefix.data()); public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]); m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits } secure_vector raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; size_t signature_length() const override { return 2*m_group.get_order_bytes(); } size_t max_input_bits() const override { return m_group.get_order_bits(); } bool has_prefix() override { return true; } secure_vector message_prefix() const override { return m_prefix; } private: const EC_Group m_group; const BigInt& m_x; secure_vector m_prefix; std::vector m_ws; }; secure_vector ECKCDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t, RandomNumberGenerator& rng) { const BigInt k = m_group.random_scalar(rng); const BigInt k_times_P_x = m_group.blinded_base_point_multiply_x(k, rng, m_ws); secure_vector to_be_hashed(k_times_P_x.bytes()); k_times_P_x.binary_encode(to_be_hashed.data()); std::unique_ptr emsa = this->clone_emsa(); emsa->update(to_be_hashed.data(), to_be_hashed.size()); secure_vector c = emsa->raw_data(); c = emsa->encoding_of(c, max_input_bits(), rng); const BigInt r(c.data(), c.size()); xor_buf(c, msg, c.size()); BigInt w(c.data(), c.size()); w = m_group.mod_order(w); const BigInt s = m_group.multiply_mod_order(m_x, k - w); if(s.is_zero()) throw Internal_Error("During ECKCDSA signature generation created zero s"); secure_vector output = BigInt::encode_1363(r, c.size()); output += BigInt::encode_1363(s, m_group.get_order_bytes()); return output; } /** * ECKCDSA verification operation */ class ECKCDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA { public: ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa, const std::string& emsa) : PK_Ops::Verification_with_EMSA(emsa), m_group(eckcdsa.domain()), m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()), m_prefix() { const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); m_prefix.resize(public_point_x.bytes() + public_point_y.bytes()); public_point_x.binary_encode(&m_prefix[0]); public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]); m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits } bool has_prefix() override { return true; } secure_vector message_prefix() const override { return m_prefix; } size_t max_input_bits() const override { return m_group.get_order_bits(); } bool with_recovery() const override { return false; } bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override; private: const EC_Group m_group; const PointGFp_Multi_Point_Precompute m_gy_mul; secure_vector m_prefix; }; bool ECKCDSA_Verification_Operation::verify(const uint8_t msg[], size_t, const uint8_t sig[], size_t sig_len) { const std::unique_ptr hash = HashFunction::create(hash_for_signature()); //calculate size of r const size_t order_bytes = m_group.get_order_bytes(); const size_t size_r = std::min(hash -> output_length(), order_bytes); if(sig_len != size_r + order_bytes) { return false; } secure_vector r(sig, sig + size_r); // check that 0 < s < q const BigInt s(sig + size_r, order_bytes); if(s <= 0 || s >= m_group.get_order()) { return false; } secure_vector r_xor_e(r); xor_buf(r_xor_e, msg, r.size()); BigInt w(r_xor_e.data(), r_xor_e.size()); w = m_group.mod_order(w); const PointGFp q = m_gy_mul.multi_exp(w, s); const BigInt q_x = q.get_affine_x(); secure_vector c(q_x.bytes()); q_x.binary_encode(c.data()); std::unique_ptr emsa = this->clone_emsa(); emsa->update(c.data(), c.size()); secure_vector v = emsa->raw_data(); Null_RNG rng; v = emsa->encoding_of(v, max_input_bits(), rng); return (v == r); } } std::unique_ptr ECKCDSA_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new ECKCDSA_Verification_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr ECKCDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new ECKCDSA_Signature_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } } /* * Ed25519 * (C) 2017 Ribose Inc * * Based on the public domain code from SUPERCOP ref10 by * Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void ed25519_gen_keypair(uint8_t* pk, uint8_t* sk, const uint8_t seed[32]) { uint8_t az[64]; SHA_512 sha; sha.update(seed, 32); sha.final(az); az[0] &= 248; az[31] &= 63; az[31] |= 64; ge_scalarmult_base(pk, az); // todo copy_mem copy_mem(sk, seed, 32); copy_mem(sk + 32, pk, 32); } void ed25519_sign(uint8_t sig[64], const uint8_t m[], size_t mlen, const uint8_t sk[64], const uint8_t domain_sep[], size_t domain_sep_len) { uint8_t az[64]; uint8_t nonce[64]; uint8_t hram[64]; SHA_512 sha; sha.update(sk, 32); sha.final(az); az[0] &= 248; az[31] &= 63; az[31] |= 64; sha.update(domain_sep, domain_sep_len); sha.update(az + 32, 32); sha.update(m, mlen); sha.final(nonce); sc_reduce(nonce); ge_scalarmult_base(sig, nonce); sha.update(domain_sep, domain_sep_len); sha.update(sig, 32); sha.update(sk + 32, 32); sha.update(m, mlen); sha.final(hram); sc_reduce(hram); sc_muladd(sig + 32, hram, az, nonce); } bool ed25519_verify(const uint8_t* m, size_t mlen, const uint8_t sig[64], const uint8_t* pk, const uint8_t domain_sep[], size_t domain_sep_len) { uint8_t h[64]; uint8_t rcheck[32]; ge_p3 A; SHA_512 sha; if(sig[63] & 224) { return false; } if(ge_frombytes_negate_vartime(&A, pk) != 0) { return false; } sha.update(domain_sep, domain_sep_len); sha.update(sig, 32); sha.update(pk, 32); sha.update(m, mlen); sha.final(h); sc_reduce(h); ge_double_scalarmult_vartime(rcheck, h, &A, sig + 32); return constant_time_compare(rcheck, sig, 32); } } /* * Ed25519 field element * (C) 2017 Ribose Inc * * Based on the public domain code from SUPERCOP ref10 by * Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { //static FE_25519 FE_25519::invert(const FE_25519& z) { fe t0; fe t1; fe t2; fe t3; fe_sq(t0, z); fe_sq_iter(t1, t0, 2); fe_mul(t1, z, t1); fe_mul(t0, t0, t1); fe_sq(t2, t0); fe_mul(t1, t1, t2); fe_sq_iter(t2, t1, 5); fe_mul(t1, t2, t1); fe_sq_iter(t2, t1, 10); fe_mul(t2, t2, t1); fe_sq_iter(t3, t2, 20); fe_mul(t2, t3, t2); fe_sq_iter(t2, t2, 10); fe_mul(t1, t2, t1); fe_sq_iter(t2, t1, 50); fe_mul(t2, t2, t1); fe_sq_iter(t3, t2, 100); fe_mul(t2, t3, t2); fe_sq_iter(t2, t2, 50); fe_mul(t1, t2, t1); fe_sq_iter(t1, t1, 5); fe_mul(t0, t1, t0); return t0; } FE_25519 FE_25519::pow_22523(const fe& z) { fe t0; fe t1; fe t2; fe_sq(t0, z); fe_sq_iter(t1, t0, 2); fe_mul(t1, z, t1); fe_mul(t0, t0, t1); fe_sq(t0, t0); fe_mul(t0, t1, t0); fe_sq_iter(t1, t0, 5); fe_mul(t0, t1, t0); fe_sq_iter(t1, t0, 10); fe_mul(t1, t1, t0); fe_sq_iter(t2, t1, 20); fe_mul(t1, t2, t1); fe_sq_iter(t1, t1, 10); fe_mul(t0, t1, t0); fe_sq_iter(t1, t0, 50); fe_mul(t1, t1, t0); fe_sq_iter(t2, t1, 100); fe_mul(t1, t2, t1); fe_sq_iter(t1, t1, 50); fe_mul(t0, t1, t0); fe_sq_iter(t0, t0, 2); fe_mul(t0, t0, z); return t0; } /* h = f * g Can overlap h with f or g. Preconditions: |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. Postconditions: |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. */ /* Notes on implementation strategy: Using schoolbook multiplication. Karatsuba would save a little in some cost models. Most multiplications by 2 and 19 are 32-bit precomputations; cheaper than 64-bit postcomputations. There is one remaining multiplication by 19 in the carry chain; one *19 precomputation can be merged into this, but the resulting data flow is considerably less clean. There are 12 carries below. 10 of them are 2-way parallelizable and vectorizable. Can get away with 11 carries, but then data flow is much deeper. With tighter constraints on inputs can squeeze carries into int32. */ //static FE_25519 FE_25519::mul(const FE_25519& f, const FE_25519& g) { const int32_t f0 = f[0]; const int32_t f1 = f[1]; const int32_t f2 = f[2]; const int32_t f3 = f[3]; const int32_t f4 = f[4]; const int32_t f5 = f[5]; const int32_t f6 = f[6]; const int32_t f7 = f[7]; const int32_t f8 = f[8]; const int32_t f9 = f[9]; const int32_t g0 = g[0]; const int32_t g1 = g[1]; const int32_t g2 = g[2]; const int32_t g3 = g[3]; const int32_t g4 = g[4]; const int32_t g5 = g[5]; const int32_t g6 = g[6]; const int32_t g7 = g[7]; const int32_t g8 = g[8]; const int32_t g9 = g[9]; const int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ const int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ const int32_t g3_19 = 19 * g3; const int32_t g4_19 = 19 * g4; const int32_t g5_19 = 19 * g5; const int32_t g6_19 = 19 * g6; const int32_t g7_19 = 19 * g7; const int32_t g8_19 = 19 * g8; const int32_t g9_19 = 19 * g9; const int32_t f1_2 = 2 * f1; const int32_t f3_2 = 2 * f3; const int32_t f5_2 = 2 * f5; const int32_t f7_2 = 2 * f7; const int32_t f9_2 = 2 * f9; const int64_t f0g0 = f0 * static_cast(g0); const int64_t f0g1 = f0 * static_cast(g1); const int64_t f0g2 = f0 * static_cast(g2); const int64_t f0g3 = f0 * static_cast(g3); const int64_t f0g4 = f0 * static_cast(g4); const int64_t f0g5 = f0 * static_cast(g5); const int64_t f0g6 = f0 * static_cast(g6); const int64_t f0g7 = f0 * static_cast(g7); const int64_t f0g8 = f0 * static_cast(g8); const int64_t f0g9 = f0 * static_cast(g9); const int64_t f1g0 = f1 * static_cast(g0); const int64_t f1g1_2 = f1_2 * static_cast(g1); const int64_t f1g2 = f1 * static_cast(g2); const int64_t f1g3_2 = f1_2 * static_cast(g3); const int64_t f1g4 = f1 * static_cast(g4); const int64_t f1g5_2 = f1_2 * static_cast(g5); const int64_t f1g6 = f1 * static_cast(g6); const int64_t f1g7_2 = f1_2 * static_cast(g7); const int64_t f1g8 = f1 * static_cast(g8); const int64_t f1g9_38 = f1_2 * static_cast(g9_19); const int64_t f2g0 = f2 * static_cast(g0); const int64_t f2g1 = f2 * static_cast(g1); const int64_t f2g2 = f2 * static_cast(g2); const int64_t f2g3 = f2 * static_cast(g3); const int64_t f2g4 = f2 * static_cast(g4); const int64_t f2g5 = f2 * static_cast(g5); const int64_t f2g6 = f2 * static_cast(g6); const int64_t f2g7 = f2 * static_cast(g7); const int64_t f2g8_19 = f2 * static_cast(g8_19); const int64_t f2g9_19 = f2 * static_cast(g9_19); const int64_t f3g0 = f3 * static_cast(g0); const int64_t f3g1_2 = f3_2 * static_cast(g1); const int64_t f3g2 = f3 * static_cast(g2); const int64_t f3g3_2 = f3_2 * static_cast(g3); const int64_t f3g4 = f3 * static_cast(g4); const int64_t f3g5_2 = f3_2 * static_cast(g5); const int64_t f3g6 = f3 * static_cast(g6); const int64_t f3g7_38 = f3_2 * static_cast(g7_19); const int64_t f3g8_19 = f3 * static_cast(g8_19); const int64_t f3g9_38 = f3_2 * static_cast(g9_19); const int64_t f4g0 = f4 * static_cast(g0); const int64_t f4g1 = f4 * static_cast(g1); const int64_t f4g2 = f4 * static_cast(g2); const int64_t f4g3 = f4 * static_cast(g3); const int64_t f4g4 = f4 * static_cast(g4); const int64_t f4g5 = f4 * static_cast(g5); const int64_t f4g6_19 = f4 * static_cast(g6_19); const int64_t f4g7_19 = f4 * static_cast(g7_19); const int64_t f4g8_19 = f4 * static_cast(g8_19); const int64_t f4g9_19 = f4 * static_cast(g9_19); const int64_t f5g0 = f5 * static_cast(g0); const int64_t f5g1_2 = f5_2 * static_cast(g1); const int64_t f5g2 = f5 * static_cast(g2); const int64_t f5g3_2 = f5_2 * static_cast(g3); const int64_t f5g4 = f5 * static_cast(g4); const int64_t f5g5_38 = f5_2 * static_cast(g5_19); const int64_t f5g6_19 = f5 * static_cast(g6_19); const int64_t f5g7_38 = f5_2 * static_cast(g7_19); const int64_t f5g8_19 = f5 * static_cast(g8_19); const int64_t f5g9_38 = f5_2 * static_cast(g9_19); const int64_t f6g0 = f6 * static_cast(g0); const int64_t f6g1 = f6 * static_cast(g1); const int64_t f6g2 = f6 * static_cast(g2); const int64_t f6g3 = f6 * static_cast(g3); const int64_t f6g4_19 = f6 * static_cast(g4_19); const int64_t f6g5_19 = f6 * static_cast(g5_19); const int64_t f6g6_19 = f6 * static_cast(g6_19); const int64_t f6g7_19 = f6 * static_cast(g7_19); const int64_t f6g8_19 = f6 * static_cast(g8_19); const int64_t f6g9_19 = f6 * static_cast(g9_19); const int64_t f7g0 = f7 * static_cast(g0); const int64_t f7g1_2 = f7_2 * static_cast(g1); const int64_t f7g2 = f7 * static_cast(g2); const int64_t f7g3_38 = f7_2 * static_cast(g3_19); const int64_t f7g4_19 = f7 * static_cast(g4_19); const int64_t f7g5_38 = f7_2 * static_cast(g5_19); const int64_t f7g6_19 = f7 * static_cast(g6_19); const int64_t f7g7_38 = f7_2 * static_cast(g7_19); const int64_t f7g8_19 = f7 * static_cast(g8_19); const int64_t f7g9_38 = f7_2 * static_cast(g9_19); const int64_t f8g0 = f8 * static_cast(g0); const int64_t f8g1 = f8 * static_cast(g1); const int64_t f8g2_19 = f8 * static_cast(g2_19); const int64_t f8g3_19 = f8 * static_cast(g3_19); const int64_t f8g4_19 = f8 * static_cast(g4_19); const int64_t f8g5_19 = f8 * static_cast(g5_19); const int64_t f8g6_19 = f8 * static_cast(g6_19); const int64_t f8g7_19 = f8 * static_cast(g7_19); const int64_t f8g8_19 = f8 * static_cast(g8_19); const int64_t f8g9_19 = f8 * static_cast(g9_19); const int64_t f9g0 = f9 * static_cast(g0); const int64_t f9g1_38 = f9_2 * static_cast(g1_19); const int64_t f9g2_19 = f9 * static_cast(g2_19); const int64_t f9g3_38 = f9_2 * static_cast(g3_19); const int64_t f9g4_19 = f9 * static_cast(g4_19); const int64_t f9g5_38 = f9_2 * static_cast(g5_19); const int64_t f9g6_19 = f9 * static_cast(g6_19); const int64_t f9g7_38 = f9_2 * static_cast(g7_19); const int64_t f9g8_19 = f9 * static_cast(g8_19); const int64_t f9g9_38 = f9_2 * static_cast(g9_19); int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; int64_t h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; int64_t h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; int64_t h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; int64_t h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; int64_t h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; int64_t h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; int64_t h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; int64_t h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; int64_t h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; /* |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 */ carry<26>(h0, h1); carry<26>(h4, h5); /* |h0| <= 2^25 */ /* |h4| <= 2^25 */ /* |h1| <= 1.71*2^59 */ /* |h5| <= 1.71*2^59 */ carry<25>(h1, h2); carry<25>(h5, h6); /* |h1| <= 2^24; from now on fits into int32 */ /* |h5| <= 2^24; from now on fits into int32 */ /* |h2| <= 1.41*2^60 */ /* |h6| <= 1.41*2^60 */ carry<26>(h2, h3); carry<26>(h6, h7); /* |h2| <= 2^25; from now on fits into int32 unchanged */ /* |h6| <= 2^25; from now on fits into int32 unchanged */ /* |h3| <= 1.71*2^59 */ /* |h7| <= 1.71*2^59 */ carry<25>(h3, h4); carry<25>(h7, h8); /* |h3| <= 2^24; from now on fits into int32 unchanged */ /* |h7| <= 2^24; from now on fits into int32 unchanged */ /* |h4| <= 1.72*2^34 */ /* |h8| <= 1.41*2^60 */ carry<26>(h4, h5); carry<26>(h8, h9); /* |h4| <= 2^25; from now on fits into int32 unchanged */ /* |h8| <= 2^25; from now on fits into int32 unchanged */ /* |h5| <= 1.01*2^24 */ /* |h9| <= 1.71*2^59 */ carry<25, 19>(h9, h0); /* |h9| <= 2^24; from now on fits into int32 unchanged */ /* |h0| <= 1.1*2^39 */ carry<26>(h0, h1); /* |h0| <= 2^25; from now on fits into int32 unchanged */ /* |h1| <= 1.01*2^24 */ return FE_25519(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9); } /* h = f * f Can overlap h with f. Preconditions: |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. Postconditions: |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. */ /* See fe_mul.c for discussion of implementation strategy. */ //static FE_25519 FE_25519::sqr_iter(const FE_25519& f, size_t iter) { int32_t f0 = f[0]; int32_t f1 = f[1]; int32_t f2 = f[2]; int32_t f3 = f[3]; int32_t f4 = f[4]; int32_t f5 = f[5]; int32_t f6 = f[6]; int32_t f7 = f[7]; int32_t f8 = f[8]; int32_t f9 = f[9]; for(size_t i = 0; i != iter; ++i) { const int32_t f0_2 = 2 * f0; const int32_t f1_2 = 2 * f1; const int32_t f2_2 = 2 * f2; const int32_t f3_2 = 2 * f3; const int32_t f4_2 = 2 * f4; const int32_t f5_2 = 2 * f5; const int32_t f6_2 = 2 * f6; const int32_t f7_2 = 2 * f7; const int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ const int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ const int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ const int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ const int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ const int64_t f0f0 = f0 * static_cast(f0); const int64_t f0f1_2 = f0_2 * static_cast(f1); const int64_t f0f2_2 = f0_2 * static_cast(f2); const int64_t f0f3_2 = f0_2 * static_cast(f3); const int64_t f0f4_2 = f0_2 * static_cast(f4); const int64_t f0f5_2 = f0_2 * static_cast(f5); const int64_t f0f6_2 = f0_2 * static_cast(f6); const int64_t f0f7_2 = f0_2 * static_cast(f7); const int64_t f0f8_2 = f0_2 * static_cast(f8); const int64_t f0f9_2 = f0_2 * static_cast(f9); const int64_t f1f1_2 = f1_2 * static_cast(f1); const int64_t f1f2_2 = f1_2 * static_cast(f2); const int64_t f1f3_4 = f1_2 * static_cast(f3_2); const int64_t f1f4_2 = f1_2 * static_cast(f4); const int64_t f1f5_4 = f1_2 * static_cast(f5_2); const int64_t f1f6_2 = f1_2 * static_cast(f6); const int64_t f1f7_4 = f1_2 * static_cast(f7_2); const int64_t f1f8_2 = f1_2 * static_cast(f8); const int64_t f1f9_76 = f1_2 * static_cast(f9_38); const int64_t f2f2 = f2 * static_cast(f2); const int64_t f2f3_2 = f2_2 * static_cast(f3); const int64_t f2f4_2 = f2_2 * static_cast(f4); const int64_t f2f5_2 = f2_2 * static_cast(f5); const int64_t f2f6_2 = f2_2 * static_cast(f6); const int64_t f2f7_2 = f2_2 * static_cast(f7); const int64_t f2f8_38 = f2_2 * static_cast(f8_19); const int64_t f2f9_38 = f2 * static_cast(f9_38); const int64_t f3f3_2 = f3_2 * static_cast(f3); const int64_t f3f4_2 = f3_2 * static_cast(f4); const int64_t f3f5_4 = f3_2 * static_cast(f5_2); const int64_t f3f6_2 = f3_2 * static_cast(f6); const int64_t f3f7_76 = f3_2 * static_cast(f7_38); const int64_t f3f8_38 = f3_2 * static_cast(f8_19); const int64_t f3f9_76 = f3_2 * static_cast(f9_38); const int64_t f4f4 = f4 * static_cast(f4); const int64_t f4f5_2 = f4_2 * static_cast(f5); const int64_t f4f6_38 = f4_2 * static_cast(f6_19); const int64_t f4f7_38 = f4 * static_cast(f7_38); const int64_t f4f8_38 = f4_2 * static_cast(f8_19); const int64_t f4f9_38 = f4 * static_cast(f9_38); const int64_t f5f5_38 = f5 * static_cast(f5_38); const int64_t f5f6_38 = f5_2 * static_cast(f6_19); const int64_t f5f7_76 = f5_2 * static_cast(f7_38); const int64_t f5f8_38 = f5_2 * static_cast(f8_19); const int64_t f5f9_76 = f5_2 * static_cast(f9_38); const int64_t f6f6_19 = f6 * static_cast(f6_19); const int64_t f6f7_38 = f6 * static_cast(f7_38); const int64_t f6f8_38 = f6_2 * static_cast(f8_19); const int64_t f6f9_38 = f6 * static_cast(f9_38); const int64_t f7f7_38 = f7 * static_cast(f7_38); const int64_t f7f8_38 = f7_2 * static_cast(f8_19); const int64_t f7f9_76 = f7_2 * static_cast(f9_38); const int64_t f8f8_19 = f8 * static_cast(f8_19); const int64_t f8f9_38 = f8 * static_cast(f9_38); const int64_t f9f9_38 = f9 * static_cast(f9_38); int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; carry<26>(h0, h1); carry<26>(h4, h5); carry<25>(h1, h2); carry<25>(h5, h6); carry<26>(h2, h3); carry<26>(h6, h7); carry<25>(h3, h4); carry<25>(h7, h8); carry<26>(h4, h5); carry<26>(h8, h9); carry<25,19>(h9, h0); carry<26>(h0, h1); f0 = static_cast(h0); f1 = static_cast(h1); f2 = static_cast(h2); f3 = static_cast(h3); f4 = static_cast(h4); f5 = static_cast(h5); f6 = static_cast(h6); f7 = static_cast(h7); f8 = static_cast(h8); f9 = static_cast(h9); } return FE_25519(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } /* h = 2 * f * f Can overlap h with f. Preconditions: |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. Postconditions: |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. */ /* See fe_mul.c for discussion of implementation strategy. */ //static FE_25519 FE_25519::sqr2(const FE_25519& f) { const int32_t f0 = f[0]; const int32_t f1 = f[1]; const int32_t f2 = f[2]; const int32_t f3 = f[3]; const int32_t f4 = f[4]; const int32_t f5 = f[5]; const int32_t f6 = f[6]; const int32_t f7 = f[7]; const int32_t f8 = f[8]; const int32_t f9 = f[9]; const int32_t f0_2 = 2 * f0; const int32_t f1_2 = 2 * f1; const int32_t f2_2 = 2 * f2; const int32_t f3_2 = 2 * f3; const int32_t f4_2 = 2 * f4; const int32_t f5_2 = 2 * f5; const int32_t f6_2 = 2 * f6; const int32_t f7_2 = 2 * f7; const int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ const int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ const int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ const int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ const int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ const int64_t f0f0 = f0 * static_cast(f0); const int64_t f0f1_2 = f0_2 * static_cast(f1); const int64_t f0f2_2 = f0_2 * static_cast(f2); const int64_t f0f3_2 = f0_2 * static_cast(f3); const int64_t f0f4_2 = f0_2 * static_cast(f4); const int64_t f0f5_2 = f0_2 * static_cast(f5); const int64_t f0f6_2 = f0_2 * static_cast(f6); const int64_t f0f7_2 = f0_2 * static_cast(f7); const int64_t f0f8_2 = f0_2 * static_cast(f8); const int64_t f0f9_2 = f0_2 * static_cast(f9); const int64_t f1f1_2 = f1_2 * static_cast(f1); const int64_t f1f2_2 = f1_2 * static_cast(f2); const int64_t f1f3_4 = f1_2 * static_cast(f3_2); const int64_t f1f4_2 = f1_2 * static_cast(f4); const int64_t f1f5_4 = f1_2 * static_cast(f5_2); const int64_t f1f6_2 = f1_2 * static_cast(f6); const int64_t f1f7_4 = f1_2 * static_cast(f7_2); const int64_t f1f8_2 = f1_2 * static_cast(f8); const int64_t f1f9_76 = f1_2 * static_cast(f9_38); const int64_t f2f2 = f2 * static_cast(f2); const int64_t f2f3_2 = f2_2 * static_cast(f3); const int64_t f2f4_2 = f2_2 * static_cast(f4); const int64_t f2f5_2 = f2_2 * static_cast(f5); const int64_t f2f6_2 = f2_2 * static_cast(f6); const int64_t f2f7_2 = f2_2 * static_cast(f7); const int64_t f2f8_38 = f2_2 * static_cast(f8_19); const int64_t f2f9_38 = f2 * static_cast(f9_38); const int64_t f3f3_2 = f3_2 * static_cast(f3); const int64_t f3f4_2 = f3_2 * static_cast(f4); const int64_t f3f5_4 = f3_2 * static_cast(f5_2); const int64_t f3f6_2 = f3_2 * static_cast(f6); const int64_t f3f7_76 = f3_2 * static_cast(f7_38); const int64_t f3f8_38 = f3_2 * static_cast(f8_19); const int64_t f3f9_76 = f3_2 * static_cast(f9_38); const int64_t f4f4 = f4 * static_cast(f4); const int64_t f4f5_2 = f4_2 * static_cast(f5); const int64_t f4f6_38 = f4_2 * static_cast(f6_19); const int64_t f4f7_38 = f4 * static_cast(f7_38); const int64_t f4f8_38 = f4_2 * static_cast(f8_19); const int64_t f4f9_38 = f4 * static_cast(f9_38); const int64_t f5f5_38 = f5 * static_cast(f5_38); const int64_t f5f6_38 = f5_2 * static_cast(f6_19); const int64_t f5f7_76 = f5_2 * static_cast(f7_38); const int64_t f5f8_38 = f5_2 * static_cast(f8_19); const int64_t f5f9_76 = f5_2 * static_cast(f9_38); const int64_t f6f6_19 = f6 * static_cast(f6_19); const int64_t f6f7_38 = f6 * static_cast(f7_38); const int64_t f6f8_38 = f6_2 * static_cast(f8_19); const int64_t f6f9_38 = f6 * static_cast(f9_38); const int64_t f7f7_38 = f7 * static_cast(f7_38); const int64_t f7f8_38 = f7_2 * static_cast(f8_19); const int64_t f7f9_76 = f7_2 * static_cast(f9_38); const int64_t f8f8_19 = f8 * static_cast(f8_19); const int64_t f8f9_38 = f8 * static_cast(f9_38); const int64_t f9f9_38 = f9 * static_cast(f9_38); int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; h0 += h0; h1 += h1; h2 += h2; h3 += h3; h4 += h4; h5 += h5; h6 += h6; h7 += h7; h8 += h8; h9 += h9; carry<26>(h0, h1); carry<26>(h4, h5); carry<25>(h1, h2); carry<25>(h5, h6); carry<26>(h2, h3); carry<26>(h6, h7); carry<25>(h3, h4); carry<25>(h7, h8); carry<26>(h4, h5); carry<26>(h8, h9); carry<25,19>(h9, h0); carry<26>(h0, h1); return FE_25519(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9); } /* Ignores top bit of h. */ void FE_25519::from_bytes(const uint8_t s[32]) { int64_t h0 = load_4(s); int64_t h1 = load_3(s + 4) << 6; int64_t h2 = load_3(s + 7) << 5; int64_t h3 = load_3(s + 10) << 3; int64_t h4 = load_3(s + 13) << 2; int64_t h5 = load_4(s + 16); int64_t h6 = load_3(s + 20) << 7; int64_t h7 = load_3(s + 23) << 5; int64_t h8 = load_3(s + 26) << 4; int64_t h9 = (load_3(s + 29) & 0x7fffff) << 2; carry<25,19>(h9, h0); carry<25>(h1, h2); carry<25>(h3, h4); carry<25>(h5, h6); carry<25>(h7, h8); carry<26>(h0, h1); carry<26>(h2, h3); carry<26>(h4, h5); carry<26>(h6, h7); carry<26>(h8, h9); m_fe[0] = static_cast(h0); m_fe[1] = static_cast(h1); m_fe[2] = static_cast(h2); m_fe[3] = static_cast(h3); m_fe[4] = static_cast(h4); m_fe[5] = static_cast(h5); m_fe[6] = static_cast(h6); m_fe[7] = static_cast(h7); m_fe[8] = static_cast(h8); m_fe[9] = static_cast(h9); } /* Preconditions: |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. Write p=2^255-19; q=floor(h/p). Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). Proof: Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). Then 0(1) << 24))) >> 25; q = (h0 + q) >> 26; q = (h1 + q) >> 25; q = (h2 + q) >> 26; q = (h3 + q) >> 25; q = (h4 + q) >> 26; q = (h5 + q) >> 25; q = (h6 + q) >> 26; q = (h7 + q) >> 25; q = (h8 + q) >> 26; q = (h9 + q) >> 25; /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ h0 += 19 * q; /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ carry0<26>(h0, h1); carry0<25>(h1, h2); carry0<26>(h2, h3); carry0<25>(h3, h4); carry0<26>(h4, h5); carry0<25>(h5, h6); carry0<26>(h6, h7); carry0<25>(h7, h8); carry0<26>(h8, h9); int32_t carry9 = h9 >> 25; h9 -= carry9 * X25; /* h10 = carry9 */ /* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. Have h0+...+2^230 h9 between 0 and 2^255-1; evidently 2^255 h10-2^255 q = 0. Goal: Output h0+...+2^230 h9. */ s[0] = static_cast(h0 >> 0); s[1] = static_cast(h0 >> 8); s[2] = static_cast(h0 >> 16); s[3] = static_cast((h0 >> 24) | (h1 << 2)); s[4] = static_cast(h1 >> 6); s[5] = static_cast(h1 >> 14); s[6] = static_cast((h1 >> 22) | (h2 << 3)); s[7] = static_cast(h2 >> 5); s[8] = static_cast(h2 >> 13); s[9] = static_cast((h2 >> 21) | (h3 << 5)); s[10] = static_cast(h3 >> 3); s[11] = static_cast(h3 >> 11); s[12] = static_cast((h3 >> 19) | (h4 << 6)); s[13] = static_cast(h4 >> 2); s[14] = static_cast(h4 >> 10); s[15] = static_cast(h4 >> 18); s[16] = static_cast(h5 >> 0); s[17] = static_cast(h5 >> 8); s[18] = static_cast(h5 >> 16); s[19] = static_cast((h5 >> 24) | (h6 << 1)); s[20] = static_cast(h6 >> 7); s[21] = static_cast(h6 >> 15); s[22] = static_cast((h6 >> 23) | (h7 << 3)); s[23] = static_cast(h7 >> 5); s[24] = static_cast(h7 >> 13); s[25] = static_cast((h7 >> 21) | (h8 << 4)); s[26] = static_cast(h8 >> 4); s[27] = static_cast(h8 >> 12); s[28] = static_cast((h8 >> 20) | (h9 << 6)); s[29] = static_cast(h9 >> 2); s[30] = static_cast(h9 >> 10); s[31] = static_cast(h9 >> 18); } } /* * Ed25519 * (C) 2017 Ribose Inc * * Based on the public domain code from SUPERCOP ref10 by * Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { AlgorithmIdentifier Ed25519_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); } bool Ed25519_PublicKey::check_key(RandomNumberGenerator&, bool) const { return true; // no tests possible? // TODO could check cofactor } Ed25519_PublicKey::Ed25519_PublicKey(const uint8_t pub_key[], size_t pub_len) { if(pub_len != 32) throw Decoding_Error("Invalid length for Ed25519 key"); m_public.assign(pub_key, pub_key + pub_len); } Ed25519_PublicKey::Ed25519_PublicKey(const AlgorithmIdentifier&, const std::vector& key_bits) { m_public = key_bits; if(m_public.size() != 32) throw Decoding_Error("Invalid size for Ed25519 public key"); } std::vector Ed25519_PublicKey::public_key_bits() const { return m_public; } Ed25519_PrivateKey::Ed25519_PrivateKey(const secure_vector& secret_key) { if(secret_key.size() == 64) { m_private = secret_key; m_public.assign(m_private.begin() + 32, m_private.end()); } else if(secret_key.size() == 32) { m_public.resize(32); m_private.resize(64); ed25519_gen_keypair(m_public.data(), m_private.data(), secret_key.data()); } else throw Decoding_Error("Invalid size for Ed25519 private key"); } Ed25519_PrivateKey::Ed25519_PrivateKey(RandomNumberGenerator& rng) { const secure_vector seed = rng.random_vec(32); m_public.resize(32); m_private.resize(64); ed25519_gen_keypair(m_public.data(), m_private.data(), seed.data()); } Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier&, const secure_vector& key_bits) { secure_vector bits; BER_Decoder(key_bits).decode(bits, OCTET_STRING).discard_remaining(); if(bits.size() != 32) throw Decoding_Error("Invalid size for Ed25519 private key"); m_public.resize(32); m_private.resize(64); ed25519_gen_keypair(m_public.data(), m_private.data(), bits.data()); } secure_vector Ed25519_PrivateKey::private_key_bits() const { secure_vector bits(&m_private[0], &m_private[32]); return DER_Encoder().encode(bits, OCTET_STRING).get_contents(); } bool Ed25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const { return true; // ??? } namespace { /** * Ed25519 verifying operation */ class Ed25519_Pure_Verify_Operation final : public PK_Ops::Verification { public: Ed25519_Pure_Verify_Operation(const Ed25519_PublicKey& key) : m_key(key) { } void update(const uint8_t msg[], size_t msg_len) override { m_msg.insert(m_msg.end(), msg, msg + msg_len); } bool is_valid_signature(const uint8_t sig[], size_t sig_len) override { if(sig_len != 64) return false; const std::vector& pub_key = m_key.get_public_key(); BOTAN_ASSERT_EQUAL(pub_key.size(), 32, "Expected size"); const bool ok = ed25519_verify(m_msg.data(), m_msg.size(), sig, pub_key.data(), nullptr, 0); m_msg.clear(); return ok; } private: std::vector m_msg; const Ed25519_PublicKey& m_key; }; /** * Ed25519 verifying operation with pre-hash */ class Ed25519_Hashed_Verify_Operation final : public PK_Ops::Verification { public: Ed25519_Hashed_Verify_Operation(const Ed25519_PublicKey& key, const std::string& hash, bool rfc8032) : m_key(key) { m_hash = HashFunction::create_or_throw(hash); if(rfc8032) { m_domain_sep = { 0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E, 0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F, 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00 }; } } void update(const uint8_t msg[], size_t msg_len) override { m_hash->update(msg, msg_len); } bool is_valid_signature(const uint8_t sig[], size_t sig_len) override { if(sig_len != 64) return false; std::vector msg_hash(m_hash->output_length()); m_hash->final(msg_hash.data()); const std::vector& pub_key = m_key.get_public_key(); BOTAN_ASSERT_EQUAL(pub_key.size(), 32, "Expected size"); return ed25519_verify(msg_hash.data(), msg_hash.size(), sig, pub_key.data(), m_domain_sep.data(), m_domain_sep.size()); } private: std::unique_ptr m_hash; const Ed25519_PublicKey& m_key; std::vector m_domain_sep; }; /** * Ed25519 signing operation ('pure' - signs message directly) */ class Ed25519_Pure_Sign_Operation final : public PK_Ops::Signature { public: Ed25519_Pure_Sign_Operation(const Ed25519_PrivateKey& key) : m_key(key) { } void update(const uint8_t msg[], size_t msg_len) override { m_msg.insert(m_msg.end(), msg, msg + msg_len); } secure_vector sign(RandomNumberGenerator&) override { secure_vector sig(64); ed25519_sign(sig.data(), m_msg.data(), m_msg.size(), m_key.get_private_key().data(), nullptr, 0); m_msg.clear(); return sig; } size_t signature_length() const override { return 64; } private: std::vector m_msg; const Ed25519_PrivateKey& m_key; }; /** * Ed25519 signing operation with pre-hash */ class Ed25519_Hashed_Sign_Operation final : public PK_Ops::Signature { public: Ed25519_Hashed_Sign_Operation(const Ed25519_PrivateKey& key, const std::string& hash, bool rfc8032) : m_key(key) { m_hash = HashFunction::create_or_throw(hash); if(rfc8032) { m_domain_sep = std::vector{ 0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E, 0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F, 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00 }; } } size_t signature_length() const override { return 64; } void update(const uint8_t msg[], size_t msg_len) override { m_hash->update(msg, msg_len); } secure_vector sign(RandomNumberGenerator&) override { secure_vector sig(64); std::vector msg_hash(m_hash->output_length()); m_hash->final(msg_hash.data()); ed25519_sign(sig.data(), msg_hash.data(), msg_hash.size(), m_key.get_private_key().data(), m_domain_sep.data(), m_domain_sep.size()); return sig; } private: std::unique_ptr m_hash; const Ed25519_PrivateKey& m_key; std::vector m_domain_sep; }; } std::unique_ptr Ed25519_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) { if(params == "" || params == "Identity" || params == "Pure") return std::unique_ptr(new Ed25519_Pure_Verify_Operation(*this)); else if(params == "Ed25519ph") return std::unique_ptr(new Ed25519_Hashed_Verify_Operation(*this, "SHA-512", true)); else return std::unique_ptr(new Ed25519_Hashed_Verify_Operation(*this, params, false)); } throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr Ed25519_PrivateKey::create_signature_op(RandomNumberGenerator&, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) { if(params == "" || params == "Identity" || params == "Pure") return std::unique_ptr(new Ed25519_Pure_Sign_Operation(*this)); else if(params == "Ed25519ph") return std::unique_ptr(new Ed25519_Hashed_Sign_Operation(*this, "SHA-512", true)); else return std::unique_ptr(new Ed25519_Hashed_Sign_Operation(*this, params, false)); } throw Provider_Not_Found(algo_name(), provider); } } /* * Ed25519 group operations * (C) 2017 Ribose Inc * * Based on the public domain code from SUPERCOP ref10 by * Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace { /* Representations: ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T ge_precomp (Duif): (y+x,y-x,2dxy) */ typedef struct { fe X; fe Y; fe Z; } ge_p2; typedef struct { fe X; fe Y; fe Z; fe T; } ge_p1p1; typedef struct { fe yplusx; fe yminusx; fe xy2d; } ge_precomp; typedef struct { fe YplusX; fe YminusX; fe Z; fe T2d; } ge_cached; /* r = p + q */ void ge_add(ge_p1p1* r, const ge_p3* p, const ge_cached* q) { fe t0; /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X, p->Y, p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y, p->Y, p->X); /* qhasm: A = YpX1*YpX2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YplusX); */ fe_mul(r->Z, r->X, q->YplusX); /* qhasm: B = YmX1*YmX2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YminusX); */ fe_mul(r->Y, r->Y, q->YminusX); /* qhasm: C = T2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ fe_mul(r->T, q->T2d, p->T); /* qhasm: ZZ = Z1*Z2 */ /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ fe_mul(r->X, p->Z, q->Z); /* qhasm: D = 2*ZZ */ /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ fe_add(t0, r->X, r->X); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X, r->Z, r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y, r->Z, r->Y); /* qhasm: Z3 = D+C */ /* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ fe_add(r->Z, t0, r->T); /* qhasm: T3 = D-C */ /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ fe_sub(r->T, t0, r->T); } /* r = p + q */ void ge_madd(ge_p1p1* r, const ge_p3* p, const ge_precomp* q) { fe t0; /* qhasm: YpX1 = Y1+X1 */ fe_add(r->X, p->Y, p->X); /* qhasm: YmX1 = Y1-X1 */ fe_sub(r->Y, p->Y, p->X); /* qhasm: A = YpX1*ypx2 */ fe_mul(r->Z, r->X, q->yplusx); /* qhasm: B = YmX1*ymx2 */ fe_mul(r->Y, r->Y, q->yminusx); /* qhasm: C = xy2d2*T1 */ fe_mul(r->T, q->xy2d, p->T); /* qhasm: D = 2*Z1 */ fe_add(t0, p->Z, p->Z); /* qhasm: X3 = A-B */ fe_sub(r->X, r->Z, r->Y); /* qhasm: Y3 = A+B */ fe_add(r->Y, r->Z, r->Y); /* qhasm: Z3 = D+C */ fe_add(r->Z, t0, r->T); /* qhasm: T3 = D-C */ fe_sub(r->T, t0, r->T); } /* r = p - q */ void ge_msub(ge_p1p1* r, const ge_p3* p, const ge_precomp* q) { fe t0; /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X, p->Y, p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y, p->Y, p->X); /* qhasm: A = YpX1*ymx2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yminusx); */ fe_mul(r->Z, r->X, q->yminusx); /* qhasm: B = YmX1*ypx2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yplusx); */ fe_mul(r->Y, r->Y, q->yplusx); /* qhasm: C = xy2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ fe_mul(r->T, q->xy2d, p->T); /* qhasm: D = 2*Z1 */ /* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ fe_add(t0, p->Z, p->Z); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X, r->Z, r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y, r->Z, r->Y); /* qhasm: Z3 = D-C */ /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ fe_sub(r->Z, t0, r->T); /* qhasm: T3 = D+C */ /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ fe_add(r->T, t0, r->T); } /* r = p */ void ge_p1p1_to_p2(ge_p2* r, const ge_p1p1* p) { fe_mul(r->X, p->X, p->T); fe_mul(r->Y, p->Y, p->Z); fe_mul(r->Z, p->Z, p->T); } /* r = p */ void ge_p1p1_to_p3(ge_p3* r, const ge_p1p1* p) { fe_mul(r->X, p->X, p->T); fe_mul(r->Y, p->Y, p->Z); fe_mul(r->Z, p->Z, p->T); fe_mul(r->T, p->X, p->Y); } /* r = 2 * p */ void ge_p2_dbl(ge_p1p1* r, const ge_p2* p) { fe t0; /* qhasm: XX=X1^2 */ /* asm 1: fe_sq(>XX=fe#1,XX=r->X,X); */ fe_sq(r->X, p->X); /* qhasm: YY=Y1^2 */ /* asm 1: fe_sq(>YY=fe#3,YY=r->Z,Y); */ fe_sq(r->Z, p->Y); /* qhasm: B=2*Z1^2 */ /* asm 1: fe_sq2(>B=fe#4,B=r->T,Z); */ fe_sq2(r->T, p->Z); /* qhasm: A=X1+Y1 */ /* asm 1: fe_add(>A=fe#2,A=r->Y,X,Y); */ fe_add(r->Y, p->X, p->Y); /* qhasm: AA=A^2 */ /* asm 1: fe_sq(>AA=fe#5,AA=t0,Y); */ fe_sq(t0, r->Y); /* qhasm: Y3=YY+XX */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,X); */ fe_add(r->Y, r->Z, r->X); /* qhasm: Z3=YY-XX */ /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,Z,X); */ fe_sub(r->Z, r->Z, r->X); /* qhasm: X3=AA-Y3 */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Y); */ fe_sub(r->X, t0, r->Y); /* qhasm: T3=B-Z3 */ /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T,Z); */ fe_sub(r->T, r->T, r->Z); } void ge_p3_0(ge_p3* h) { fe_0(h->X); fe_1(h->Y); fe_1(h->Z); fe_0(h->T); } /* r = 2 * p */ void ge_p3_dbl(ge_p1p1* r, const ge_p3* p) { ge_p2 q; // Convert to p2 rep q.X = p->X; q.Y = p->Y; q.Z = p->Z; ge_p2_dbl(r, &q); } /* r = p */ void ge_p3_to_cached(ge_cached* r, const ge_p3* p) { static const fe d2 = { -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 } ; fe_add(r->YplusX, p->Y, p->X); fe_sub(r->YminusX, p->Y, p->X); fe_copy(r->Z, p->Z); fe_mul(r->T2d, p->T, d2); } /* r = p - q */ void ge_sub(ge_p1p1* r, const ge_p3* p, const ge_cached* q) { fe t0; /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X, p->Y, p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y, p->Y, p->X); /* qhasm: A = YpX1*YmX2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YminusX); */ fe_mul(r->Z, r->X, q->YminusX); /* qhasm: B = YmX1*YpX2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YplusX); */ fe_mul(r->Y, r->Y, q->YplusX); /* qhasm: C = T2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ fe_mul(r->T, q->T2d, p->T); /* qhasm: ZZ = Z1*Z2 */ /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ fe_mul(r->X, p->Z, q->Z); /* qhasm: D = 2*ZZ */ /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ fe_add(t0, r->X, r->X); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X, r->Z, r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y, r->Z, r->Y); /* qhasm: Z3 = D-C */ /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ fe_sub(r->Z, t0, r->T); /* qhasm: T3 = D+C */ /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ fe_add(r->T, t0, r->T); } void slide(int8_t* r, const uint8_t* a) { for(size_t i = 0; i < 256; ++i) { r[i] = 1 & (a[i >> 3] >> (i & 7)); } for(size_t i = 0; i < 256; ++i) { if(r[i]) { for(size_t b = 1; b <= 6 && i + b < 256; ++b) { if(r[i + b]) { if(r[i] + (r[i + b] << b) <= 15) { r[i] += r[i + b] << b; r[i + b] = 0; } else if(r[i] - (r[i + b] << b) >= -15) { r[i] -= r[i + b] << b; for(size_t k = i + b; k < 256; ++k) { if(!r[k]) { r[k] = 1; break; } r[k] = 0; } } else { break; } } } } } } void ge_tobytes(uint8_t* s, const ge_p2* h) { fe recip; fe x; fe y; fe_invert(recip, h->Z); fe_mul(x, h->X, recip); fe_mul(y, h->Y, recip); fe_tobytes(s, y); s[31] ^= fe_isnegative(x) << 7; } void ge_p2_0(ge_p2* h) { fe_0(h->X); fe_1(h->Y); fe_1(h->Z); } } int ge_frombytes_negate_vartime(ge_p3* h, const uint8_t* s) { static const fe d = { -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 } ; static const fe sqrtm1 = { -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 } ; fe u; fe v; fe v3; fe vxx; fe check; fe_frombytes(h->Y, s); fe_1(h->Z); fe_sq(u, h->Y); fe_mul(v, u, d); fe_sub(u, u, h->Z); /* u = y^2-1 */ fe_add(v, v, h->Z); /* v = dy^2+1 */ fe_sq(v3, v); fe_mul(v3, v3, v); /* v3 = v^3 */ fe_sq(h->X, v3); fe_mul(h->X, h->X, v); fe_mul(h->X, h->X, u); /* x = uv^7 */ fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ fe_mul(h->X, h->X, v3); fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ fe_sq(vxx, h->X); fe_mul(vxx, vxx, v); fe_sub(check, vxx, u); /* vx^2-u */ if(fe_isnonzero(check)) { fe_add(check, vxx, u); /* vx^2+u */ if(fe_isnonzero(check)) { return -1; } fe_mul(h->X, h->X, sqrtm1); } if(fe_isnegative(h->X) == (s[31] >> 7)) { fe_neg(h->X, h->X); } fe_mul(h->T, h->X, h->Y); return 0; } /* r = a * A + b * B where a = a[0]+256*a[1]+...+256^31 a[31]. and b = b[0]+256*b[1]+...+256^31 b[31]. B is the Ed25519 base point (x,4/5) with x positive. */ void ge_double_scalarmult_vartime( uint8_t out[32], const uint8_t* a, const ge_p3* A, const uint8_t* b) { static const ge_precomp Bi[8] = { { { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 }, }, { { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 }, }, { { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 }, }, { { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 }, }, { { -22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877 }, { -6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951 }, { 4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784 }, }, { { -25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436 }, { 25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918 }, { 23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877 }, }, { { -33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800 }, { -25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305 }, { -13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300 }, }, { { -3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876 }, { -24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619 }, { -3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683 }, }, } ; int8_t aslide[256]; int8_t bslide[256]; ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ ge_p1p1 t; ge_p3 u; ge_p3 A2; ge_p2 r; int i; slide(aslide, a); slide(bslide, b); ge_p3_to_cached(&Ai[0], A); ge_p3_dbl(&t, A); ge_p1p1_to_p3(&A2, &t); ge_add(&t, &A2, &Ai[0]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[1], &u); ge_add(&t, &A2, &Ai[1]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[2], &u); ge_add(&t, &A2, &Ai[2]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[3], &u); ge_add(&t, &A2, &Ai[3]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[4], &u); ge_add(&t, &A2, &Ai[4]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[5], &u); ge_add(&t, &A2, &Ai[5]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[6], &u); ge_add(&t, &A2, &Ai[6]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&Ai[7], &u); ge_p2_0(&r); for(i = 255; i >= 0; --i) { if(aslide[i] || bslide[i]) { break; } } for(; i >= 0; --i) { ge_p2_dbl(&t, &r); if(aslide[i] > 0) { ge_p1p1_to_p3(&u, &t); ge_add(&t, &u, &Ai[aslide[i] >> 1]); } else if(aslide[i] < 0) { ge_p1p1_to_p3(&u, &t); ge_sub(&t, &u, &Ai[(-aslide[i]) >> 1]); } if(bslide[i] > 0) { ge_p1p1_to_p3(&u, &t); ge_madd(&t, &u, &Bi[bslide[i] >> 1]); } else if(bslide[i] < 0) { ge_p1p1_to_p3(&u, &t); ge_msub(&t, &u, &Bi[(-bslide[i]) >> 1]); } ge_p1p1_to_p2(&r, &t); } ge_tobytes(out, &r); } /* base[i][j] = (j+1)*256^i*B */ static const ge_precomp B_precomp[32][8] = { { { { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 }, }, { { -12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303 }, { -21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081 }, { 26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697 }, }, { { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 }, }, { { -17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540 }, { 23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397 }, { 7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325 }, }, { { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 }, }, { { -15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777 }, { -8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737 }, { -18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652 }, }, { { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 }, }, { { 14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726 }, { -7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955 }, { 27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425 }, }, }, { { { -13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171 }, { 27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510 }, { 17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660 }, }, { { -10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639 }, { 29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963 }, { 5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950 }, }, { { -27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568 }, { 12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335 }, { 25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628 }, }, { { -26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007 }, { -2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772 }, { -22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653 }, }, { { 2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567 }, { 13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686 }, { 21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372 }, }, { { -13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887 }, { -23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954 }, { -29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953 }, }, { { 24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833 }, { -16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532 }, { -22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876 }, }, { { 2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268 }, { 33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214 }, { 1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038 }, }, }, { { { 6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800 }, { 4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645 }, { -4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664 }, }, { { 1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933 }, { -25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182 }, { -17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222 }, }, { { -18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991 }, { 20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880 }, { 9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092 }, }, { { -16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295 }, { 19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788 }, { 8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553 }, }, { { -15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026 }, { 11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347 }, { -18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033 }, }, { { -23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395 }, { -27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278 }, { 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890 }, }, { { 32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995 }, { -30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596 }, { -11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891 }, }, { { 31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060 }, { 11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608 }, { -20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606 }, }, }, { { { 7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389 }, { -19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016 }, { -11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341 }, }, { { -22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505 }, { 14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553 }, { -28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655 }, }, { { 15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220 }, { 12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631 }, { -4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099 }, }, { { 26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556 }, { 14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749 }, { 236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930 }, }, { { 1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391 }, { 5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253 }, { 20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066 }, }, { { 24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958 }, { -11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082 }, { -28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383 }, }, { { -30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521 }, { -11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807 }, { 23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948 }, }, { { 9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134 }, { -32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455 }, { 27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629 }, }, }, { { { -8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069 }, { -32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746 }, { 24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919 }, }, { { 11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837 }, { 8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906 }, { -28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771 }, }, { { -25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817 }, { 10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098 }, { 10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409 }, }, { { -12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504 }, { -26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727 }, { 28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420 }, }, { { -32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003 }, { -1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605 }, { -30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384 }, }, { { -26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701 }, { -23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683 }, { 29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708 }, }, { { -3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563 }, { -19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260 }, { -5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387 }, }, { { -19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672 }, { 23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686 }, { -24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665 }, }, }, { { { 11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182 }, { -31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277 }, { 14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628 }, }, { { -4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474 }, { -26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539 }, { -25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822 }, }, { { -10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970 }, { 19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756 }, { -24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508 }, }, { { -26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683 }, { -10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655 }, { -20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158 }, }, { { -4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125 }, { -15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839 }, { -20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664 }, }, { { 27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294 }, { -18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899 }, { -11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070 }, }, { { 3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294 }, { -15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949 }, { -21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083 }, }, { { 31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420 }, { -5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940 }, { 29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396 }, }, }, { { { -12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567 }, { 20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127 }, { -16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294 }, }, { { -12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887 }, { 22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964 }, { 16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195 }, }, { { 9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244 }, { 24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999 }, { -1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762 }, }, { { -18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274 }, { -33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236 }, { -16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605 }, }, { { -13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761 }, { -22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884 }, { -6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482 }, }, { { -24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638 }, { -11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490 }, { -32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170 }, }, { { 5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736 }, { 10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124 }, { -17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392 }, }, { { 8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029 }, { 6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048 }, { 28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958 }, }, }, { { { 24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593 }, { 26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071 }, { -11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692 }, }, { { 11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687 }, { -160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441 }, { -20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001 }, }, { { -938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460 }, { -19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007 }, { -21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762 }, }, { { 15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005 }, { -9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674 }, { 4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035 }, }, { { 7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590 }, { -2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957 }, { -30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812 }, }, { { 33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740 }, { -18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122 }, { -27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158 }, }, { { 8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885 }, { 26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140 }, { 19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857 }, }, { { 801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155 }, { 19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260 }, { 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483 }, }, }, { { { -3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677 }, { 32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815 }, { 22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751 }, }, { { -16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203 }, { -11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208 }, { 1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230 }, }, { { 16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850 }, { -21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389 }, { -9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968 }, }, { { -11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689 }, { 14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880 }, { 5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304 }, }, { { 30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632 }, { -3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412 }, { 20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566 }, }, { { -20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038 }, { -26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232 }, { -1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943 }, }, { { 17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856 }, { 23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738 }, { 15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971 }, }, { { -27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718 }, { -13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697 }, { -11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883 }, }, }, { { { 5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912 }, { -26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358 }, { 3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849 }, }, { { 29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307 }, { -14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977 }, { -6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335 }, }, { { -29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644 }, { -22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616 }, { -27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735 }, }, { { -21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099 }, { 29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341 }, { -936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336 }, }, { { -23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646 }, { 31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425 }, { -17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388 }, }, { { -31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743 }, { -16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822 }, { -8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462 }, }, { { 18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985 }, { 9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702 }, { -22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797 }, }, { { 21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293 }, { 27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100 }, { 19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688 }, }, }, { { { 12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186 }, { 2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610 }, { -2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707 }, }, { { 7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220 }, { 915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025 }, { 32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044 }, }, { { 32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992 }, { -4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027 }, { 21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197 }, }, { { 8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901 }, { 31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952 }, { 19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878 }, }, { { -28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390 }, { 32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730 }, { 2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730 }, }, { { -19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180 }, { -30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272 }, { -15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715 }, }, { { -22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970 }, { -31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772 }, { -17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865 }, }, { { 15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750 }, { 20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373 }, { 32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348 }, }, }, { { { 9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144 }, { -22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195 }, { 5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086 }, }, { { -13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684 }, { -8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518 }, { -2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233 }, }, { { -5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793 }, { -2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794 }, { 580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435 }, }, { { 23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921 }, { 13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518 }, { 2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563 }, }, { { 14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278 }, { -27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024 }, { 4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030 }, }, { { 10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783 }, { 27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717 }, { 6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844 }, }, { { 14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333 }, { 16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048 }, { 22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760 }, }, { { -4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760 }, { -15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757 }, { -2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112 }, }, }, { { { -19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468 }, { 3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184 }, { 10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289 }, }, { { 15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066 }, { 24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882 }, { 13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226 }, }, { { 16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101 }, { 29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279 }, { -6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811 }, }, { { 27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709 }, { 20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714 }, { -2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121 }, }, { { 9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464 }, { 12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847 }, { 13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400 }, }, { { 4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414 }, { -15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158 }, { 17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045 }, }, { { -461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415 }, { -5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459 }, { -31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079 }, }, { { 21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412 }, { -20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743 }, { -14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836 }, }, }, { { { 12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022 }, { 18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429 }, { -6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065 }, }, { { 30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861 }, { 10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000 }, { -33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101 }, }, { { 32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815 }, { 29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642 }, { 10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966 }, }, { { 25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574 }, { -21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742 }, { -18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689 }, }, { { 12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020 }, { -10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772 }, { 3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982 }, }, { { -14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953 }, { -16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218 }, { -17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265 }, }, { { 29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073 }, { -3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325 }, { -11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798 }, }, { { -4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870 }, { -7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863 }, { -13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927 }, }, }, { { { -2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267 }, { -9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663 }, { 22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862 }, }, { { -25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673 }, { 15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943 }, { 15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020 }, }, { { -4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238 }, { 11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064 }, { 14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795 }, }, { { 15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052 }, { -10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904 }, { 29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531 }, }, { { -13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979 }, { -5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841 }, { 10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431 }, }, { { 10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324 }, { -31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940 }, { 10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320 }, }, { { -15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184 }, { 14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114 }, { 30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878 }, }, { { 12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784 }, { -2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091 }, { -16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585 }, }, }, { { { -8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208 }, { 10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864 }, { 17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661 }, }, { { 7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233 }, { 26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212 }, { -12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525 }, }, { { -24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068 }, { 9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397 }, { -8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988 }, }, { { 5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889 }, { 32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038 }, { 14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697 }, }, { { 20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875 }, { -25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905 }, { -25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656 }, }, { { 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818 }, { 27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714 }, { 10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203 }, }, { { 20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931 }, { -30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024 }, { -23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084 }, }, { { -1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204 }, { 20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817 }, { 27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667 }, }, }, { { { 11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504 }, { -12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768 }, { -19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255 }, }, { { 6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790 }, { 1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438 }, { -22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333 }, }, { { 17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971 }, { 31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905 }, { 29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409 }, }, { { 12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409 }, { 6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499 }, { -8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363 }, }, { { 28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664 }, { -11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324 }, { -21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940 }, }, { { 13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990 }, { -17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914 }, { -25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290 }, }, { { 24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257 }, { -6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433 }, { -16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236 }, }, { { -12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045 }, { 11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093 }, { -1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347 }, }, }, { { { -28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191 }, { -15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507 }, { -12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906 }, }, { { 3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018 }, { -16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109 }, { -23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926 }, }, { { -24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528 }, { 8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625 }, { -32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286 }, }, { { 2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033 }, { 27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866 }, { 21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896 }, }, { { 30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075 }, { 26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347 }, { -22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437 }, }, { { -5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165 }, { -18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588 }, { -32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193 }, }, { { -19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017 }, { -28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883 }, { 21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961 }, }, { { 8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043 }, { 29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663 }, { -20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362 }, }, }, { { { -33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860 }, { 2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466 }, { -24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063 }, }, { { -26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997 }, { -1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295 }, { -13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369 }, }, { { 9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385 }, { 18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109 }, { 2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906 }, }, { { 4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424 }, { -19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185 }, { 7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962 }, }, { { -7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325 }, { 10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593 }, { 696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404 }, }, { { -11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644 }, { 17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801 }, { 26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804 }, }, { { -31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884 }, { -586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577 }, { -9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849 }, }, { { 32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473 }, { -8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644 }, { -2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319 }, }, }, { { { -11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599 }, { -9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768 }, { -27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084 }, }, { { -27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328 }, { -15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369 }, { 20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920 }, }, { { 12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815 }, { -32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025 }, { -21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397 }, }, { { -20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448 }, { 6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981 }, { 30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165 }, }, { { 32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501 }, { 17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073 }, { -1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861 }, }, { { 14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845 }, { -1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211 }, { 18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870 }, }, { { 10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096 }, { 33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803 }, { -32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168 }, }, { { 30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965 }, { -14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505 }, { 18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598 }, }, }, { { { 5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782 }, { 5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900 }, { -31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479 }, }, { { -12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208 }, { 8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232 }, { 17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719 }, }, { { 16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271 }, { -4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326 }, { -8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132 }, }, { { 14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300 }, { 8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570 }, { 15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670 }, }, { { -2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994 }, { -12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913 }, { 31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317 }, }, { { -25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730 }, { 842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096 }, { -4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078 }, }, { { -15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411 }, { -19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905 }, { -9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654 }, }, { { -28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870 }, { -23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498 }, { 12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579 }, }, }, { { { 14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677 }, { 10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647 }, { -2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743 }, }, { { -25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468 }, { 21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375 }, { -25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155 }, }, { { 6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725 }, { -12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612 }, { -10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943 }, }, { { -30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944 }, { 30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928 }, { 9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406 }, }, { { 22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139 }, { -8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963 }, { -31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693 }, }, { { 1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734 }, { -448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680 }, { -24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410 }, }, { { -9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931 }, { -16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654 }, { 22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710 }, }, { { 29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180 }, { -26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684 }, { -10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895 }, }, }, { { { 22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501 }, { -11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413 }, { 6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880 }, }, { { -8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874 }, { 22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962 }, { -7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899 }, }, { { 21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152 }, { 9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063 }, { 7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080 }, }, { { -9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146 }, { -17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183 }, { -19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133 }, }, { { -32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421 }, { -3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622 }, { -4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197 }, }, { { 2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663 }, { 31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753 }, { 4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755 }, }, { { -9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862 }, { -26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118 }, { 26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171 }, }, { { 15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380 }, { 16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824 }, { 28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270 }, }, }, { { { -817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438 }, { -31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584 }, { -594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562 }, }, { { 30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471 }, { 18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610 }, { 19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269 }, }, { { -30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650 }, { 14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369 }, { 19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461 }, }, { { 30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462 }, { -5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793 }, { -2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218 }, }, { { -24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226 }, { 18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019 }, { -15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037 }, }, { { 31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171 }, { -17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132 }, { -28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841 }, }, { { 21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181 }, { -33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210 }, { -1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040 }, }, { { 3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935 }, { 24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105 }, { -28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814 }, }, }, { { { 793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852 }, { 5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581 }, { -4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646 }, }, { { 10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844 }, { 10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025 }, { 27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453 }, }, { { -23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068 }, { 4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192 }, { -17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921 }, }, { { -9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259 }, { -12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426 }, { -5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072 }, }, { { -17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305 }, { 13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832 }, { 28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943 }, }, { { -16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011 }, { 24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447 }, { 17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494 }, }, { { -28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245 }, { -20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859 }, { 28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915 }, }, { { 16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707 }, { 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848 }, { -11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224 }, }, }, { { { -25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391 }, { 15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215 }, { -23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101 }, }, { { 23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713 }, { 21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849 }, { -7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930 }, }, { { -29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940 }, { -21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031 }, { -17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404 }, }, { { -25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243 }, { -23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116 }, { -24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525 }, }, { { -23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509 }, { -10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883 }, { 15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865 }, }, { { -3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660 }, { 4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273 }, { -28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138 }, }, { { -25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560 }, { -10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135 }, { 2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941 }, }, { { -4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739 }, { 18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756 }, { -30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819 }, }, }, { { { -6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347 }, { -27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028 }, { 21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075 }, }, { { 16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799 }, { -2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609 }, { -25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817 }, }, { { -23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989 }, { -30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523 }, { 4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278 }, }, { { 31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045 }, { 19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377 }, { 24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480 }, }, { { 17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016 }, { 510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426 }, { 18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525 }, }, { { 13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396 }, { 9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080 }, { 12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892 }, }, { { 15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275 }, { 11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074 }, { 20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140 }, }, { { -16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717 }, { -1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101 }, { 24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127 }, }, }, { { { -12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632 }, { -26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415 }, { -31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160 }, }, { { 31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876 }, { 22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625 }, { -15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478 }, }, { { 27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164 }, { 26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595 }, { -7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248 }, }, { { -16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858 }, { 15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193 }, { 8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184 }, }, { { -18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942 }, { -1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635 }, { 21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948 }, }, { { 11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935 }, { -25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415 }, { -15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416 }, }, { { -7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018 }, { 4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778 }, { 366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659 }, }, { { -24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385 }, { 18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503 }, { 476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329 }, }, }, { { { 20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056 }, { -13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838 }, { 24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948 }, }, { { -3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691 }, { -15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118 }, { -23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517 }, }, { { -20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269 }, { -6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904 }, { -23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589 }, }, { { -28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193 }, { -7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910 }, { -30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930 }, }, { { -7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667 }, { 25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481 }, { -9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876 }, }, { { 22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640 }, { -8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278 }, { -21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112 }, }, { { 26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272 }, { 17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012 }, { -10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221 }, }, { { 30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046 }, { 13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345 }, { -19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310 }, }, }, { { { 19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937 }, { 31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636 }, { -9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008 }, }, { { -2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429 }, { -15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576 }, { 31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066 }, }, { { -9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490 }, { -12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104 }, { 33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053 }, }, { { 31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275 }, { -20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511 }, { 22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095 }, }, { { -28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439 }, { 23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939 }, { -23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424 }, }, { { 2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310 }, { 3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608 }, { -32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079 }, }, { { -23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101 }, { 21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418 }, { 18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576 }, }, { { 30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356 }, { 9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996 }, { -26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099 }, }, }, { { { -26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728 }, { -13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658 }, { -10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242 }, }, { { -21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001 }, { -4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766 }, { 18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373 }, }, { { 26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458 }, { -17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628 }, { -13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657 }, }, { { -23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062 }, { 25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616 }, { 31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014 }, }, { { 24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383 }, { -25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814 }, { -20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718 }, }, { { 30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417 }, { 2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222 }, { 33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444 }, }, { { -20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597 }, { 23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970 }, { 1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799 }, }, { { -5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647 }, { 13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511 }, { -29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032 }, }, }, { { { 9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834 }, { -23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461 }, { 29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062 }, }, { { -25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516 }, { -20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547 }, { -24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240 }, }, { { -17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038 }, { -33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741 }, { 16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103 }, }, { { -19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747 }, { -1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323 }, { 31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016 }, }, { { -14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373 }, { 15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228 }, { -2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141 }, }, { { 16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399 }, { 11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831 }, { -185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376 }, }, { { -32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313 }, { -18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958 }, { -6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577 }, }, { { -22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743 }, { 29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684 }, { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 }, }, }, } ; namespace { inline uint8_t equal(int8_t b, int8_t c) { uint8_t ub = b; uint8_t uc = c; uint8_t x = ub ^ uc; /* 0: yes; 1..255: no */ uint32_t y = x; /* 0: yes; 1..255: no */ y -= 1; /* 4294967295: yes; 0..254: no */ y >>= 31; /* 1: yes; 0: no */ return static_cast(y); } inline int32_t equal32(int8_t b, int8_t c) { return -static_cast(equal(b, c)); } inline uint8_t negative(int8_t b) { uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ x >>= 63; /* 1: yes; 0: no */ return static_cast(x); } inline void ge_precomp_0(ge_precomp* h) { fe_1(h->yplusx); fe_1(h->yminusx); fe_0(h->xy2d); } inline void select(ge_precomp* t, const ge_precomp* base, int8_t b) { const uint8_t bnegative = negative(b); const uint8_t babs = b - ((-static_cast(bnegative) & b) * 2); const int32_t neg_mask = equal32(bnegative, 1); const int32_t mask1 = equal32(babs, 1); const int32_t mask2 = equal32(babs, 2); const int32_t mask3 = equal32(babs, 3); const int32_t mask4 = equal32(babs, 4); const int32_t mask5 = equal32(babs, 5); const int32_t mask6 = equal32(babs, 6); const int32_t mask7 = equal32(babs, 7); const int32_t mask8 = equal32(babs, 8); ge_precomp_0(t); for(size_t i = 0; i != 10; ++i) { t->yplusx[i] = t->yplusx[i] ^ ((t->yplusx[i] ^ base[0].yplusx[i]) & mask1) ^ ((t->yplusx[i] ^ base[1].yplusx[i]) & mask2) ^ ((t->yplusx[i] ^ base[2].yplusx[i]) & mask3) ^ ((t->yplusx[i] ^ base[3].yplusx[i]) & mask4) ^ ((t->yplusx[i] ^ base[4].yplusx[i]) & mask5) ^ ((t->yplusx[i] ^ base[5].yplusx[i]) & mask6) ^ ((t->yplusx[i] ^ base[6].yplusx[i]) & mask7) ^ ((t->yplusx[i] ^ base[7].yplusx[i]) & mask8); t->yminusx[i] = t->yminusx[i] ^ ((t->yminusx[i] ^ base[0].yminusx[i]) & mask1) ^ ((t->yminusx[i] ^ base[1].yminusx[i]) & mask2) ^ ((t->yminusx[i] ^ base[2].yminusx[i]) & mask3) ^ ((t->yminusx[i] ^ base[3].yminusx[i]) & mask4) ^ ((t->yminusx[i] ^ base[4].yminusx[i]) & mask5) ^ ((t->yminusx[i] ^ base[5].yminusx[i]) & mask6) ^ ((t->yminusx[i] ^ base[6].yminusx[i]) & mask7) ^ ((t->yminusx[i] ^ base[7].yminusx[i]) & mask8); t->xy2d[i] = t->xy2d[i] ^ ((t->xy2d[i] ^ base[0].xy2d[i]) & mask1) ^ ((t->xy2d[i] ^ base[1].xy2d[i]) & mask2) ^ ((t->xy2d[i] ^ base[2].xy2d[i]) & mask3) ^ ((t->xy2d[i] ^ base[3].xy2d[i]) & mask4) ^ ((t->xy2d[i] ^ base[4].xy2d[i]) & mask5) ^ ((t->xy2d[i] ^ base[5].xy2d[i]) & mask6) ^ ((t->xy2d[i] ^ base[6].xy2d[i]) & mask7) ^ ((t->xy2d[i] ^ base[7].xy2d[i]) & mask8); } fe minus_xy2d; fe_neg(minus_xy2d, t->xy2d); // If negative have to swap yminusx and yplusx for(size_t i = 0; i != 10; ++i) { int32_t t_yplusx = t->yplusx[i] ^ ((t->yplusx[i] ^ t->yminusx[i]) & neg_mask); int32_t t_yminusx = t->yminusx[i] ^ ((t->yminusx[i] ^ t->yplusx[i]) & neg_mask); t->yplusx[i] = t_yplusx; t->yminusx[i] = t_yminusx; t->xy2d[i] = t->xy2d[i] ^ ((t->xy2d[i] ^ minus_xy2d[i]) & neg_mask); } } void ge_p3_tobytes(uint8_t* s, const ge_p3* h) { fe recip; fe x; fe y; fe_invert(recip, h->Z); fe_mul(x, h->X, recip); fe_mul(y, h->Y, recip); fe_tobytes(s, y); s[31] ^= fe_isnegative(x) << 7; } } /* h = a * B where a = a[0]+256*a[1]+...+256^31 a[31] B is the Ed25519 base point (x,4/5) with x positive. Preconditions: a[31] <= 127 */ void ge_scalarmult_base(uint8_t out[32], const uint8_t a[32]) { int8_t e[64]; int8_t carry; ge_p1p1 r; ge_p2 s; ge_p3 h; ge_precomp t; int i; for(i = 0; i < 32; ++i) { e[2 * i + 0] = (a[i] >> 0) & 15; e[2 * i + 1] = (a[i] >> 4) & 15; } /* each e[i] is between 0 and 15 */ /* e[63] is between 0 and 7 */ carry = 0; for(i = 0; i < 63; ++i) { e[i] += carry; carry = e[i] + 8; carry >>= 4; e[i] -= carry << 4; } e[63] += carry; /* each e[i] is between -8 and 8 */ ge_p3_0(&h); for(i = 1; i < 64; i += 2) { select(&t, B_precomp[i / 2], e[i]); ge_madd(&r, &h, &t); ge_p1p1_to_p3(&h, &r); } ge_p3_dbl(&r, &h); ge_p1p1_to_p2(&s, &r); ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); ge_p2_dbl(&r, &s); ge_p1p1_to_p3(&h, &r); for(i = 0; i < 64; i += 2) { select(&t, B_precomp[i / 2], e[i]); ge_madd(&r, &h, &t); ge_p1p1_to_p3(&h, &r); } ge_p3_tobytes(out, &h); } } /* * Ed25519 * (C) 2017 Ribose Inc * * Based on the public domain code from SUPERCOP ref10 by * Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* Input: a[0]+256*a[1]+...+256^31*a[31] = a b[0]+256*b[1]+...+256^31*b[31] = b c[0]+256*c[1]+...+256^31*c[31] = c Output: s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l where l = 2^252 + 27742317777372353535851937790883648493. */ void sc_muladd(uint8_t* s, const uint8_t* a, const uint8_t* b, const uint8_t* c) { const int32_t MASK = 0x1fffff; const int64_t a0 = MASK & load_3(a); const int64_t a1 = MASK & (load_4(a + 2) >> 5); const int64_t a2 = MASK & (load_3(a + 5) >> 2); const int64_t a3 = MASK & (load_4(a + 7) >> 7); const int64_t a4 = MASK & (load_4(a + 10) >> 4); const int64_t a5 = MASK & (load_3(a + 13) >> 1); const int64_t a6 = MASK & (load_4(a + 15) >> 6); const int64_t a7 = MASK & (load_3(a + 18) >> 3); const int64_t a8 = MASK & load_3(a + 21); const int64_t a9 = MASK & (load_4(a + 23) >> 5); const int64_t a10 = MASK & (load_3(a + 26) >> 2); const int64_t a11 = (load_4(a + 28) >> 7); const int64_t b0 = MASK & load_3(b); const int64_t b1 = MASK & (load_4(b + 2) >> 5); const int64_t b2 = MASK & (load_3(b + 5) >> 2); const int64_t b3 = MASK & (load_4(b + 7) >> 7); const int64_t b4 = MASK & (load_4(b + 10) >> 4); const int64_t b5 = MASK & (load_3(b + 13) >> 1); const int64_t b6 = MASK & (load_4(b + 15) >> 6); const int64_t b7 = MASK & (load_3(b + 18) >> 3); const int64_t b8 = MASK & load_3(b + 21); const int64_t b9 = MASK & (load_4(b + 23) >> 5); const int64_t b10 = MASK & (load_3(b + 26) >> 2); const int64_t b11 = (load_4(b + 28) >> 7); const int64_t c0 = MASK & load_3(c); const int64_t c1 = MASK & (load_4(c + 2) >> 5); const int64_t c2 = MASK & (load_3(c + 5) >> 2); const int64_t c3 = MASK & (load_4(c + 7) >> 7); const int64_t c4 = MASK & (load_4(c + 10) >> 4); const int64_t c5 = MASK & (load_3(c + 13) >> 1); const int64_t c6 = MASK & (load_4(c + 15) >> 6); const int64_t c7 = MASK & (load_3(c + 18) >> 3); const int64_t c8 = MASK & load_3(c + 21); const int64_t c9 = MASK & (load_4(c + 23) >> 5); const int64_t c10 = MASK & (load_3(c + 26) >> 2); const int64_t c11 = (load_4(c + 28) >> 7); int64_t s0 = c0 + a0*b0; int64_t s1 = c1 + a0*b1 + a1*b0; int64_t s2 = c2 + a0*b2 + a1*b1 + a2*b0; int64_t s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0; int64_t s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0; int64_t s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0; int64_t s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0; int64_t s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0; int64_t s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0; int64_t s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0; int64_t s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0; int64_t s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0; int64_t s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1; int64_t s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2; int64_t s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3; int64_t s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4; int64_t s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5; int64_t s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6; int64_t s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7; int64_t s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8; int64_t s20 = a9*b11 + a10*b10 + a11*b9; int64_t s21 = a10*b11 + a11*b10; int64_t s22 = a11*b11; int64_t s23 = 0; carry<21>(s0, s1); carry<21>(s2, s3); carry<21>(s4, s5); carry<21>(s6, s7); carry<21>(s8, s9); carry<21>(s10, s11); carry<21>(s12, s13); carry<21>(s14, s15); carry<21>(s16, s17); carry<21>(s18, s19); carry<21>(s20, s21); carry<21>(s22, s23); carry<21>(s1, s2); carry<21>(s3, s4); carry<21>(s5, s6); carry<21>(s7, s8); carry<21>(s9, s10); carry<21>(s11, s12); carry<21>(s13, s14); carry<21>(s15, s16); carry<21>(s17, s18); carry<21>(s19, s20); carry<21>(s21, s22); redc_mul(s11, s12, s13, s14, s15, s16, s23); redc_mul(s10, s11, s12, s13, s14, s15, s22); redc_mul( s9, s10, s11, s12, s13, s14, s21); redc_mul( s8, s9, s10, s11, s12, s13, s20); redc_mul( s7, s8, s9, s10, s11, s12, s19); redc_mul( s6, s7, s8, s9, s10, s11, s18); carry<21>(s6, s7); carry<21>(s8, s9); carry<21>(s10, s11); carry<21>(s12, s13); carry<21>(s14, s15); carry<21>(s16, s17); carry<21>(s7, s8); carry<21>(s9, s10); carry<21>(s11, s12); carry<21>(s13, s14); carry<21>(s15, s16); redc_mul(s5, s6, s7, s8, s9, s10, s17); redc_mul(s4, s5, s6, s7, s8, s9, s16); redc_mul(s3, s4, s5, s6, s7, s8, s15); redc_mul(s2, s3, s4, s5, s6, s7, s14); redc_mul(s1, s2, s3, s4, s5, s6, s13); redc_mul(s0, s1, s2, s3, s4, s5, s12); carry<21>(s0, s1); carry<21>(s2, s3); carry<21>(s4, s5); carry<21>(s6, s7); carry<21>(s8, s9); carry<21>(s10, s11); carry<21>(s1, s2); carry<21>(s3, s4); carry<21>(s5, s6); carry<21>(s7, s8); carry<21>(s9, s10); carry<21>(s11, s12); redc_mul(s0, s1, s2, s3, s4, s5, s12); carry0<21>(s0, s1); carry0<21>(s1, s2); carry0<21>(s2, s3); carry0<21>(s3, s4); carry0<21>(s4, s5); carry0<21>(s5, s6); carry0<21>(s6, s7); carry0<21>(s7, s8); carry0<21>(s8, s9); carry0<21>(s9, s10); carry0<21>(s10, s11); carry0<21>(s11, s12); redc_mul(s0, s1, s2, s3, s4, s5, s12); carry0<21>(s0, s1); carry0<21>(s1, s2); carry0<21>(s2, s3); carry0<21>(s3, s4); carry0<21>(s4, s5); carry0<21>(s5, s6); carry0<21>(s6, s7); carry0<21>(s7, s8); carry0<21>(s8, s9); carry0<21>(s9, s10); carry0<21>(s10, s11); s[0] = static_cast(s0 >> 0); s[1] = static_cast(s0 >> 8); s[2] = static_cast((s0 >> 16) | (s1 << 5)); s[3] = static_cast(s1 >> 3); s[4] = static_cast(s1 >> 11); s[5] = static_cast((s1 >> 19) | (s2 << 2)); s[6] = static_cast(s2 >> 6); s[7] = static_cast((s2 >> 14) | (s3 << 7)); s[8] = static_cast(s3 >> 1); s[9] = static_cast(s3 >> 9); s[10] = static_cast((s3 >> 17) | (s4 << 4)); s[11] = static_cast(s4 >> 4); s[12] = static_cast(s4 >> 12); s[13] = static_cast((s4 >> 20) | (s5 << 1)); s[14] = static_cast(s5 >> 7); s[15] = static_cast((s5 >> 15) | (s6 << 6)); s[16] = static_cast(s6 >> 2); s[17] = static_cast(s6 >> 10); s[18] = static_cast((s6 >> 18) | (s7 << 3)); s[19] = static_cast(s7 >> 5); s[20] = static_cast(s7 >> 13); s[21] = static_cast(s8 >> 0); s[22] = static_cast(s8 >> 8); s[23] = static_cast((s8 >> 16) | (s9 << 5)); s[24] = static_cast(s9 >> 3); s[25] = static_cast(s9 >> 11); s[26] = static_cast((s9 >> 19) | (s10 << 2)); s[27] = static_cast(s10 >> 6); s[28] = static_cast((s10 >> 14) | (s11 << 7)); s[29] = static_cast(s11 >> 1); s[30] = static_cast(s11 >> 9); s[31] = static_cast(s11 >> 17); } } /* * Ed25519 * (C) 2017 Ribose Inc * * Based on the public domain code from SUPERCOP ref10 by * Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* Input: s[0]+256*s[1]+...+256^63*s[63] = s Output: s[0]+256*s[1]+...+256^31*s[31] = s mod l where l = 2^252 + 27742317777372353535851937790883648493. Overwrites s in place. */ void sc_reduce(uint8_t* s) { const uint32_t MASK = 0x1fffff; int64_t s0 = MASK & load_3(s); int64_t s1 = MASK & (load_4(s + 2) >> 5); int64_t s2 = MASK & (load_3(s + 5) >> 2); int64_t s3 = MASK & (load_4(s + 7) >> 7); int64_t s4 = MASK & (load_4(s + 10) >> 4); int64_t s5 = MASK & (load_3(s + 13) >> 1); int64_t s6 = MASK & (load_4(s + 15) >> 6); int64_t s7 = MASK & (load_3(s + 18) >> 3); int64_t s8 = MASK & load_3(s + 21); int64_t s9 = MASK & (load_4(s + 23) >> 5); int64_t s10 = MASK & (load_3(s + 26) >> 2); int64_t s11 = MASK & (load_4(s + 28) >> 7); int64_t s12 = MASK & (load_4(s + 31) >> 4); int64_t s13 = MASK & (load_3(s + 34) >> 1); int64_t s14 = MASK & (load_4(s + 36) >> 6); int64_t s15 = MASK & (load_3(s + 39) >> 3); int64_t s16 = MASK & load_3(s + 42); int64_t s17 = MASK & (load_4(s + 44) >> 5); int64_t s18 = MASK & (load_3(s + 47) >> 2); int64_t s19 = MASK & (load_4(s + 49) >> 7); int64_t s20 = MASK & (load_4(s + 52) >> 4); int64_t s21 = MASK & (load_3(s + 55) >> 1); int64_t s22 = MASK & (load_4(s + 57) >> 6); int64_t s23 = (load_4(s + 60) >> 3); redc_mul(s11, s12, s13, s14, s15, s16, s23); redc_mul(s10, s11, s12, s13, s14, s15, s22); redc_mul( s9, s10, s11, s12, s13, s14, s21); redc_mul( s8, s9, s10, s11, s12, s13, s20); redc_mul( s7, s8, s9, s10, s11, s12, s19); redc_mul( s6, s7, s8, s9, s10, s11, s18); carry<21>(s6, s7); carry<21>(s8, s9); carry<21>(s10, s11); carry<21>(s12, s13); carry<21>(s14, s15); carry<21>(s16, s17); carry<21>(s7, s8); carry<21>(s9, s10); carry<21>(s11, s12); carry<21>(s13, s14); carry<21>(s15, s16); redc_mul(s5, s6, s7, s8, s9, s10, s17); redc_mul(s4, s5, s6, s7, s8, s9, s16); redc_mul(s3, s4, s5, s6, s7, s8, s15); redc_mul(s2, s3, s4, s5, s6, s7, s14); redc_mul(s1, s2, s3, s4, s5, s6, s13); redc_mul(s0, s1, s2, s3, s4, s5, s12); carry<21>(s0, s1); carry<21>(s2, s3); carry<21>(s4, s5); carry<21>(s6, s7); carry<21>(s8, s9); carry<21>(s10, s11); carry<21>(s1, s2); carry<21>(s3, s4); carry<21>(s5, s6); carry<21>(s7, s8); carry<21>(s9, s10); carry<21>(s11, s12); redc_mul(s0, s1, s2, s3, s4, s5, s12); carry0<21>(s0, s1); carry0<21>(s1, s2); carry0<21>(s2, s3); carry0<21>(s3, s4); carry0<21>(s4, s5); carry0<21>(s5, s6); carry0<21>(s6, s7); carry0<21>(s7, s8); carry0<21>(s8, s9); carry0<21>(s9, s10); carry0<21>(s10, s11); carry0<21>(s11, s12); redc_mul(s0, s1, s2, s3, s4, s5, s12); carry0<21>(s0, s1); carry0<21>(s1, s2); carry0<21>(s2, s3); carry0<21>(s3, s4); carry0<21>(s4, s5); carry0<21>(s5, s6); carry0<21>(s6, s7); carry0<21>(s7, s8); carry0<21>(s8, s9); carry0<21>(s9, s10); carry0<21>(s10, s11); carry0<21>(s11, s12); s[0] = static_cast(s0 >> 0); s[1] = static_cast(s0 >> 8); s[2] = static_cast((s0 >> 16) | (s1 << 5)); s[3] = static_cast(s1 >> 3); s[4] = static_cast(s1 >> 11); s[5] = static_cast((s1 >> 19) | (s2 << 2)); s[6] = static_cast(s2 >> 6); s[7] = static_cast((s2 >> 14) | (s3 << 7)); s[8] = static_cast(s3 >> 1); s[9] = static_cast(s3 >> 9); s[10] = static_cast((s3 >> 17) | (s4 << 4)); s[11] = static_cast(s4 >> 4); s[12] = static_cast(s4 >> 12); s[13] = static_cast((s4 >> 20) | (s5 << 1)); s[14] = static_cast(s5 >> 7); s[15] = static_cast((s5 >> 15) | (s6 << 6)); s[16] = static_cast(s6 >> 2); s[17] = static_cast(s6 >> 10); s[18] = static_cast((s6 >> 18) | (s7 << 3)); s[19] = static_cast(s7 >> 5); s[20] = static_cast(s7 >> 13); s[21] = static_cast(s8 >> 0); s[22] = static_cast(s8 >> 8); s[23] = static_cast((s8 >> 16) | (s9 << 5)); s[24] = static_cast(s9 >> 3); s[25] = static_cast(s9 >> 11); s[26] = static_cast((s9 >> 19) | (s10 << 2)); s[27] = static_cast(s10 >> 6); s[28] = static_cast((s10 >> 14) | (s11 << 7)); s[29] = static_cast(s11 >> 1); s[30] = static_cast(s11 >> 9); s[31] = static_cast(s11 >> 17); } } /* * ElGamal * (C) 1999-2007,2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * ElGamal_PublicKey Constructor */ ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& group, const BigInt& y) : DL_Scheme_PublicKey(group, y) { } /* * ElGamal_PrivateKey Constructor */ ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group, const BigInt& x) { m_x = x; m_group = group; if(m_x.is_zero()) { const size_t exp_bits = m_group.exponent_bits(); m_x.randomize(rng, exp_bits); m_y = m_group.power_g_p(m_x, exp_bits); } else { m_y = m_group.power_g_p(m_x, m_group.p_bits()); } } ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits) : DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) { m_y = m_group.power_g_p(m_x, m_group.p_bits()); } /* * Check Private ElGamal Parameters */ bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!DL_Scheme_PrivateKey::check_key(rng, strong)) return false; if(!strong) return true; return KeyPair::encryption_consistency_check(rng, *this, "OAEP(SHA-256)"); } namespace { /** * ElGamal encryption operation */ class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME { public: size_t ciphertext_length(size_t) const override { return 2*m_group.p_bytes(); } size_t max_raw_input_bits() const override { return m_group.p_bits() - 1; } ElGamal_Encryption_Operation(const ElGamal_PublicKey& key, const std::string& eme); secure_vector raw_encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; private: const DL_Group m_group; std::shared_ptr m_monty_y_p; }; ElGamal_Encryption_Operation::ElGamal_Encryption_Operation(const ElGamal_PublicKey& key, const std::string& eme) : PK_Ops::Encryption_with_EME(eme), m_group(key.get_group()) { const size_t powm_window = 4; m_monty_y_p = monty_precompute(key.get_group().monty_params_p(), key.get_y(), powm_window); } secure_vector ElGamal_Encryption_Operation::raw_encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) { BigInt m(msg, msg_len); if(m >= m_group.get_p()) throw Invalid_Argument("ElGamal encryption: Input is too large"); const size_t k_bits = m_group.exponent_bits(); const BigInt k(rng, k_bits); const BigInt a = m_group.power_g_p(k, k_bits); const BigInt b = m_group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits)); return BigInt::encode_fixed_length_int_pair(a, b, m_group.p_bytes()); } /** * ElGamal decryption operation */ class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME { public: ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, const std::string& eme, RandomNumberGenerator& rng); size_t plaintext_length(size_t) const override { return m_group.p_bytes(); } secure_vector raw_decrypt(const uint8_t msg[], size_t msg_len) override; private: BigInt powermod_x_p(const BigInt& v) const { const size_t powm_window = 4; auto powm_v_p = monty_precompute(m_monty_p, v, powm_window); return monty_execute(*powm_v_p, m_x, m_x_bits); } const DL_Group m_group; const BigInt& m_x; const size_t m_x_bits; std::shared_ptr m_monty_p; Blinder m_blinder; }; ElGamal_Decryption_Operation::ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, const std::string& eme, RandomNumberGenerator& rng) : PK_Ops::Decryption_with_EME(eme), m_group(key.get_group()), m_x(key.get_x()), m_x_bits(m_x.bits()), m_monty_p(key.get_group().monty_params_p()), m_blinder(m_group.get_p(), rng, [](const BigInt& k) { return k; }, [this](const BigInt& k) { return powermod_x_p(k); }) { } secure_vector ElGamal_Decryption_Operation::raw_decrypt(const uint8_t msg[], size_t msg_len) { const size_t p_bytes = m_group.p_bytes(); if(msg_len != 2 * p_bytes) throw Invalid_Argument("ElGamal decryption: Invalid message"); BigInt a(msg, p_bytes); const BigInt b(msg + p_bytes, p_bytes); if(a >= m_group.get_p() || b >= m_group.get_p()) throw Invalid_Argument("ElGamal decryption: Invalid message"); a = m_blinder.blind(a); const BigInt r = m_group.multiply_mod_p(m_group.inverse_mod_p(powermod_x_p(a)), b); return BigInt::encode_1363(m_blinder.unblind(r), p_bytes); } } std::unique_ptr ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new ElGamal_Encryption_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr ElGamal_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new ElGamal_Decryption_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } } /* * OAEP * (C) 1999-2010,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * OAEP Pad Operation */ secure_vector OAEP::pad(const uint8_t in[], size_t in_length, size_t key_length, RandomNumberGenerator& rng) const { key_length /= 8; if(in_length > maximum_input_size(key_length * 8)) { throw Invalid_Argument("OAEP: Input is too large"); } secure_vector out(key_length); rng.randomize(out.data(), m_Phash.size()); buffer_insert(out, m_Phash.size(), m_Phash.data(), m_Phash.size()); out[out.size() - in_length - 1] = 0x01; buffer_insert(out, out.size() - in_length, in, in_length); mgf1_mask(*m_mgf1_hash, out.data(), m_Phash.size(), &out[m_Phash.size()], out.size() - m_Phash.size()); mgf1_mask(*m_mgf1_hash, &out[m_Phash.size()], out.size() - m_Phash.size(), out.data(), m_Phash.size()); return out; } /* * OAEP Unpad Operation */ secure_vector OAEP::unpad(uint8_t& valid_mask, const uint8_t in[], size_t in_length) const { /* Must be careful about error messages here; if an attacker can distinguish them, it is easy to use the differences as an oracle to find the secret key, as described in "A Chosen Ciphertext Attack on RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 v2.0", James Manger, Crypto 2001 Also have to be careful about timing attacks! Pointed out by Falko Strenzke. According to the standard (Section 7.1.1), the encryptor always creates a message as follows: i. Concatenate a single octet with hexadecimal value 0x00, maskedSeed, and maskedDB to form an encoded message EM of length k octets as EM = 0x00 || maskedSeed || maskedDB. where k is the length of the modulus N. Therefore, the first byte can always be skipped safely. */ const uint8_t skip_first = CT::Mask::is_zero(in[0]).if_set_return(1); secure_vector input(in + skip_first, in + in_length); const size_t hlen = m_Phash.size(); mgf1_mask(*m_mgf1_hash, &input[hlen], input.size() - hlen, input.data(), hlen); mgf1_mask(*m_mgf1_hash, input.data(), hlen, &input[hlen], input.size() - hlen); return oaep_find_delim(valid_mask, input.data(), input.size(), m_Phash); } secure_vector oaep_find_delim(uint8_t& valid_mask, const uint8_t input[], size_t input_len, const secure_vector& Phash) { const size_t hlen = Phash.size(); // Too short to be valid, reject immediately if(input_len < 1 + 2*hlen) { return secure_vector(); } CT::poison(input, input_len); size_t delim_idx = 2 * hlen; CT::Mask waiting_for_delim = CT::Mask::set(); CT::Mask bad_input_m = CT::Mask::cleared(); for(size_t i = delim_idx; i < input_len; ++i) { const auto zero_m = CT::Mask::is_zero(input[i]); const auto one_m = CT::Mask::is_equal(input[i], 1); const auto add_m = waiting_for_delim & zero_m; bad_input_m |= waiting_for_delim & ~(zero_m | one_m); delim_idx += add_m.if_set_return(1); waiting_for_delim &= zero_m; } // If we never saw any non-zero byte, then it's not valid input bad_input_m |= waiting_for_delim; bad_input_m |= CT::Mask::is_zero(ct_compare_u8(&input[hlen], Phash.data(), hlen)); delim_idx += 1; valid_mask = (~bad_input_m).unpoisoned_value(); const secure_vector output = CT::copy_output(bad_input_m, input, input_len, delim_idx); CT::unpoison(input, input_len); return output; } /* * Return the max input size for a given key size */ size_t OAEP::maximum_input_size(size_t keybits) const { if(keybits / 8 > 2*m_Phash.size() + 1) return ((keybits / 8) - 2*m_Phash.size() - 1); else return 0; } /* * OAEP Constructor */ OAEP::OAEP(HashFunction* hash, const std::string& P) : m_mgf1_hash(hash) { m_Phash = m_mgf1_hash->process(P); } OAEP::OAEP(HashFunction* hash, HashFunction* mgf1_hash, const std::string& P) : m_mgf1_hash(mgf1_hash) { std::unique_ptr phash(hash); // takes ownership m_Phash = phash->process(P); } } /* * PKCS #1 v1.5 Type 2 (encryption) padding * (C) 1999-2007,2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * PKCS1 Pad Operation */ secure_vector EME_PKCS1v15::pad(const uint8_t in[], size_t inlen, size_t key_length, RandomNumberGenerator& rng) const { key_length /= 8; if(inlen > maximum_input_size(key_length * 8)) { throw Invalid_Argument("PKCS1: Input is too large"); } secure_vector out(key_length); out[0] = 0x02; rng.randomize(out.data() + 1, (key_length - inlen - 2)); for(size_t j = 1; j != key_length - inlen - 1; ++j) { if(out[j] == 0) { out[j] = rng.next_nonzero_byte(); } } buffer_insert(out, key_length - inlen, in, inlen); return out; } /* * PKCS1 Unpad Operation */ secure_vector EME_PKCS1v15::unpad(uint8_t& valid_mask, const uint8_t in[], size_t inlen) const { /* * RSA decryption pads the ciphertext up to the modulus size, so this only * occurs with very (!) small keys, or when fuzzing. * * 11 bytes == 00,02 + 8 bytes mandatory padding + 00 */ if(inlen < 11) { valid_mask = false; return secure_vector(); } CT::poison(in, inlen); CT::Mask bad_input_m = CT::Mask::cleared(); CT::Mask seen_zero_m = CT::Mask::cleared(); size_t delim_idx = 2; // initial 0002 bad_input_m |= ~CT::Mask::is_equal(in[0], 0); bad_input_m |= ~CT::Mask::is_equal(in[1], 2); for(size_t i = 2; i < inlen; ++i) { const auto is_zero_m = CT::Mask::is_zero(in[i]); delim_idx += seen_zero_m.if_not_set_return(1); seen_zero_m |= is_zero_m; } // no zero delim -> bad padding bad_input_m |= ~seen_zero_m; /* delim indicates < 8 bytes padding -> bad padding We require 11 here because we are counting also the 00 delim byte */ bad_input_m |= CT::Mask(CT::Mask::is_lt(delim_idx, 11)); valid_mask = (~bad_input_m).unpoisoned_value(); const secure_vector output = CT::copy_output(bad_input_m, in, inlen, delim_idx); CT::unpoison(in, inlen); return output; } /* * Return the max input size for a given key size */ size_t EME_PKCS1v15::maximum_input_size(size_t keybits) const { if(keybits / 8 > 10) return ((keybits / 8) - 10); else return 0; } } /* * (C) 2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { secure_vector EME_Raw::pad(const uint8_t in[], size_t in_length, size_t, RandomNumberGenerator&) const { return secure_vector(in, in + in_length); } secure_vector EME_Raw::unpad(uint8_t& valid_mask, const uint8_t in[], size_t in_length) const { valid_mask = 0xFF; return CT::strip_leading_zeros(in, in_length); } size_t EME_Raw::maximum_input_size(size_t keybits) const { return keybits / 8; } } /* * EMSA1 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { secure_vector emsa1_encoding(const secure_vector& msg, size_t output_bits) { if(8*msg.size() <= output_bits) return msg; size_t shift = 8*msg.size() - output_bits; size_t byte_shift = shift / 8, bit_shift = shift % 8; secure_vector digest(msg.size() - byte_shift); for(size_t j = 0; j != msg.size() - byte_shift; ++j) digest[j] = msg[j]; if(bit_shift) { uint8_t carry = 0; for(size_t j = 0; j != digest.size(); ++j) { uint8_t temp = digest[j]; digest[j] = (temp >> bit_shift) | carry; carry = (temp << (8 - bit_shift)); } } return digest; } } std::string EMSA1::name() const { return "EMSA1(" + m_hash->name() + ")"; } EMSA* EMSA1::clone() { return new EMSA1(m_hash->clone()); } void EMSA1::update(const uint8_t input[], size_t length) { m_hash->update(input, length); } secure_vector EMSA1::raw_data() { return m_hash->final(); } secure_vector EMSA1::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator&) { if(msg.size() != hash_output_length()) throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); return emsa1_encoding(msg, output_bits); } bool EMSA1::verify(const secure_vector& input, const secure_vector& raw, size_t key_bits) { if(raw.size() != m_hash->output_length()) return false; // Call emsa1_encoding to handle any required bit shifting const secure_vector our_coding = emsa1_encoding(raw, key_bits); if(our_coding.size() < input.size()) return false; const size_t offset = our_coding.size() - input.size(); // must be >= 0 per check above // If our encoding is longer, all the bytes in it must be zero for(size_t i = 0; i != offset; ++i) if(our_coding[i] != 0) return false; return constant_time_compare(input.data(), &our_coding[offset], input.size()); } AlgorithmIdentifier EMSA1::config_for_x509(const Private_Key& key, const std::string& cert_hash_name) const { if(cert_hash_name != m_hash->name()) throw Invalid_Argument("Hash function from opts and hash_fn argument" " need to be identical"); // check that the signature algorithm and the padding scheme fit if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA1")) { throw Invalid_Argument("Encoding scheme with canonical name EMSA1" " not supported for signature algorithm " + key.algo_name()); } const OID oid = OID::from_string(key.algo_name() + "/" + name()); const std::string algo_name = key.algo_name(); std::vector parameters; if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA" || algo_name == "GOST-34.10" || algo_name == "GOST-34.10-2012-256" || algo_name == "GOST-34.10-2012-512") { // for DSA, ECDSA, GOST parameters "SHALL" be empty } else { parameters = key.algorithm_identifier().get_parameters(); } return AlgorithmIdentifier(oid, parameters); } } /* * PKCS #1 v1.5 signature padding * (C) 1999-2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { secure_vector emsa3_encoding(const secure_vector& msg, size_t output_bits, const uint8_t hash_id[], size_t hash_id_length) { size_t output_length = output_bits / 8; if(output_length < hash_id_length + msg.size() + 10) throw Encoding_Error("emsa3_encoding: Output length is too small"); secure_vector T(output_length); const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2; T[0] = 0x01; set_mem(&T[1], P_LENGTH, 0xFF); T[P_LENGTH+1] = 0x00; if(hash_id_length > 0) { BOTAN_ASSERT_NONNULL(hash_id); buffer_insert(T, P_LENGTH+2, hash_id, hash_id_length); } buffer_insert(T, output_length-msg.size(), msg.data(), msg.size()); return T; } } void EMSA_PKCS1v15::update(const uint8_t input[], size_t length) { m_hash->update(input, length); } secure_vector EMSA_PKCS1v15::raw_data() { return m_hash->final(); } secure_vector EMSA_PKCS1v15::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator&) { if(msg.size() != m_hash->output_length()) throw Encoding_Error("EMSA_PKCS1v15::encoding_of: Bad input length"); return emsa3_encoding(msg, output_bits, m_hash_id.data(), m_hash_id.size()); } bool EMSA_PKCS1v15::verify(const secure_vector& coded, const secure_vector& raw, size_t key_bits) { if(raw.size() != m_hash->output_length()) return false; try { return (coded == emsa3_encoding(raw, key_bits, m_hash_id.data(), m_hash_id.size())); } catch(...) { return false; } } AlgorithmIdentifier EMSA_PKCS1v15::config_for_x509(const Private_Key& key, const std::string& cert_hash_name) const { if(cert_hash_name != m_hash->name()) throw Invalid_Argument("Hash function from opts and hash_fn argument" " need to be identical"); // check that the signature algorithm and the padding scheme fit if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA3")) { throw Invalid_Argument("Encoding scheme with canonical name EMSA3" " not supported for signature algorithm " + key.algo_name()); } // for RSA PKCSv1.5 parameters "SHALL" be NULL const OID oid = OID::from_string(key.algo_name() + "/" + name()); return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_NULL_PARAM); } EMSA_PKCS1v15::EMSA_PKCS1v15(HashFunction* hash) : m_hash(hash) { m_hash_id = pkcs_hash_id(m_hash->name()); } EMSA_PKCS1v15_Raw::EMSA_PKCS1v15_Raw(const std::string& hash_algo) { if(!hash_algo.empty()) { m_hash_id = pkcs_hash_id(hash_algo); std::unique_ptr hash(HashFunction::create_or_throw(hash_algo)); m_hash_name = hash->name(); m_hash_output_len = hash->output_length(); } else { m_hash_output_len = 0; } } void EMSA_PKCS1v15_Raw::update(const uint8_t input[], size_t length) { m_message += std::make_pair(input, length); } secure_vector EMSA_PKCS1v15_Raw::raw_data() { secure_vector ret; std::swap(ret, m_message); if(m_hash_output_len > 0 && ret.size() != m_hash_output_len) throw Encoding_Error("EMSA_PKCS1v15_Raw::encoding_of: Bad input length"); return ret; } secure_vector EMSA_PKCS1v15_Raw::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator&) { return emsa3_encoding(msg, output_bits, m_hash_id.data(), m_hash_id.size()); } bool EMSA_PKCS1v15_Raw::verify(const secure_vector& coded, const secure_vector& raw, size_t key_bits) { if(m_hash_output_len > 0 && raw.size() != m_hash_output_len) return false; try { return (coded == emsa3_encoding(raw, key_bits, m_hash_id.data(), m_hash_id.size())); } catch(...) { return false; } } } /* * PSSR * (C) 1999-2007,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * PSSR Encode Operation */ secure_vector pss_encode(HashFunction& hash, const secure_vector& msg, const secure_vector& salt, size_t output_bits) { const size_t HASH_SIZE = hash.output_length(); const size_t SALT_SIZE = salt.size(); if(msg.size() != HASH_SIZE) throw Encoding_Error("Cannot encode PSS string, input length invalid for hash"); if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9) throw Encoding_Error("Cannot encode PSS string, output length too small"); const size_t output_length = (output_bits + 7) / 8; for(size_t i = 0; i != 8; ++i) hash.update(0); hash.update(msg); hash.update(salt); secure_vector H = hash.final(); secure_vector EM(output_length); EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01; buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt); mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1); EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); buffer_insert(EM, output_length - 1 - HASH_SIZE, H); EM[output_length-1] = 0xBC; return EM; } bool pss_verify(HashFunction& hash, const secure_vector& pss_repr, const secure_vector& message_hash, size_t key_bits, size_t* out_salt_size) { const size_t HASH_SIZE = hash.output_length(); const size_t KEY_BYTES = (key_bits + 7) / 8; if(key_bits < 8*HASH_SIZE + 9) return false; if(message_hash.size() != HASH_SIZE) return false; if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1) return false; if(pss_repr[pss_repr.size()-1] != 0xBC) return false; secure_vector coded = pss_repr; if(coded.size() < KEY_BYTES) { secure_vector temp(KEY_BYTES); buffer_insert(temp, KEY_BYTES - coded.size(), coded); coded = temp; } const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; if(TOP_BITS > 8 - high_bit(coded[0])) return false; uint8_t* DB = coded.data(); const size_t DB_size = coded.size() - HASH_SIZE - 1; const uint8_t* H = &coded[DB_size]; const size_t H_size = HASH_SIZE; mgf1_mask(hash, H, H_size, DB, DB_size); DB[0] &= 0xFF >> TOP_BITS; size_t salt_offset = 0; for(size_t j = 0; j != DB_size; ++j) { if(DB[j] == 0x01) { salt_offset = j + 1; break; } if(DB[j]) return false; } if(salt_offset == 0) return false; const size_t salt_size = DB_size - salt_offset; for(size_t j = 0; j != 8; ++j) hash.update(0); hash.update(message_hash); hash.update(&DB[salt_offset], salt_size); const secure_vector H2 = hash.final(); const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE); if(out_salt_size && ok) *out_salt_size = salt_size; return ok; } } PSSR::PSSR(HashFunction* h) : m_hash(h), m_salt_size(m_hash->output_length()), m_required_salt_len(false) { } PSSR::PSSR(HashFunction* h, size_t salt_size) : m_hash(h), m_salt_size(salt_size), m_required_salt_len(true) { } /* * PSSR Update Operation */ void PSSR::update(const uint8_t input[], size_t length) { m_hash->update(input, length); } /* * Return the raw (unencoded) data */ secure_vector PSSR::raw_data() { return m_hash->final(); } secure_vector PSSR::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator& rng) { const secure_vector salt = rng.random_vec(m_salt_size); return pss_encode(*m_hash, msg, salt, output_bits); } /* * PSSR Decode/Verify Operation */ bool PSSR::verify(const secure_vector& coded, const secure_vector& raw, size_t key_bits) { size_t salt_size = 0; const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size); if(m_required_salt_len && salt_size != m_salt_size) return false; return ok; } EMSA* PSSR::clone() { return new PSSR(m_hash->clone(), m_salt_size); } std::string PSSR::name() const { return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")"; } AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key, const std::string& cert_hash_name) const { if(cert_hash_name != m_hash->name()) throw Invalid_Argument("Hash function from opts and hash_fn argument" " need to be identical"); // check that the signature algorithm and the padding scheme fit if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4")) { throw Invalid_Argument("Encoding scheme with canonical name EMSA4" " not supported for signature algorithm " + key.algo_name()); } const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM); const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode()); std::vector parameters; DER_Encoder(parameters) .start_cons(SEQUENCE) .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).encode(hash_id).end_cons() .start_cons(ASN1_Tag(1), CONTEXT_SPECIFIC).encode(mgf_id).end_cons() .start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_salt_size).end_cons() .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field .end_cons(); // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment return AlgorithmIdentifier("RSA/EMSA4", parameters); } PSSR_Raw::PSSR_Raw(HashFunction* h) : m_hash(h), m_salt_size(m_hash->output_length()), m_required_salt_len(false) { } PSSR_Raw::PSSR_Raw(HashFunction* h, size_t salt_size) : m_hash(h), m_salt_size(salt_size), m_required_salt_len(true) { } /* * PSSR_Raw Update Operation */ void PSSR_Raw::update(const uint8_t input[], size_t length) { m_msg.insert(m_msg.end(), input, input + length); } /* * Return the raw (unencoded) data */ secure_vector PSSR_Raw::raw_data() { secure_vector ret; std::swap(ret, m_msg); if(ret.size() != m_hash->output_length()) throw Encoding_Error("PSSR_Raw Bad input length, did not match hash"); return ret; } secure_vector PSSR_Raw::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator& rng) { secure_vector salt = rng.random_vec(m_salt_size); return pss_encode(*m_hash, msg, salt, output_bits); } /* * PSSR_Raw Decode/Verify Operation */ bool PSSR_Raw::verify(const secure_vector& coded, const secure_vector& raw, size_t key_bits) { size_t salt_size = 0; const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size); if(m_required_salt_len && salt_size != m_salt_size) return false; return ok; } EMSA* PSSR_Raw::clone() { return new PSSR_Raw(m_hash->clone(), m_salt_size); } std::string PSSR_Raw::name() const { return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")"; } } /* * EMSA-Raw * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string EMSA_Raw::name() const { if(m_expected_size > 0) return "Raw(" + std::to_string(m_expected_size) + ")"; return "Raw"; } /* * EMSA-Raw Encode Operation */ void EMSA_Raw::update(const uint8_t input[], size_t length) { m_message += std::make_pair(input, length); } /* * Return the raw (unencoded) data */ secure_vector EMSA_Raw::raw_data() { if(m_expected_size && m_message.size() != m_expected_size) throw Invalid_Argument("EMSA_Raw was configured to use a " + std::to_string(m_expected_size) + " byte hash but instead was used for a " + std::to_string(m_message.size()) + " hash"); secure_vector output; std::swap(m_message, output); return output; } /* * EMSA-Raw Encode Operation */ secure_vector EMSA_Raw::encoding_of(const secure_vector& msg, size_t, RandomNumberGenerator&) { if(m_expected_size && msg.size() != m_expected_size) throw Invalid_Argument("EMSA_Raw was configured to use a " + std::to_string(m_expected_size) + " byte hash but instead was used for a " + std::to_string(msg.size()) + " hash"); return msg; } /* * EMSA-Raw Verify Operation */ bool EMSA_Raw::verify(const secure_vector& coded, const secure_vector& raw, size_t) { if(m_expected_size && raw.size() != m_expected_size) return false; if(coded.size() == raw.size()) return (coded == raw); if(coded.size() > raw.size()) return false; // handle zero padding differences const size_t leading_zeros_expected = raw.size() - coded.size(); bool same_modulo_leading_zeros = true; for(size_t i = 0; i != leading_zeros_expected; ++i) if(raw[i]) same_modulo_leading_zeros = false; if(!constant_time_compare(coded.data(), raw.data() + leading_zeros_expected, coded.size())) same_modulo_leading_zeros = false; return same_modulo_leading_zeros; } } /* * EMSA_X931 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { secure_vector emsa2_encoding(const secure_vector& msg, size_t output_bits, const secure_vector& empty_hash, uint8_t hash_id) { const size_t HASH_SIZE = empty_hash.size(); size_t output_length = (output_bits + 1) / 8; if(msg.size() != HASH_SIZE) throw Encoding_Error("EMSA_X931::encoding_of: Bad input length"); if(output_length < HASH_SIZE + 4) throw Encoding_Error("EMSA_X931::encoding_of: Output length is too small"); const bool empty_input = (msg == empty_hash); secure_vector output(output_length); output[0] = (empty_input ? 0x4B : 0x6B); output[output_length - 3 - HASH_SIZE] = 0xBA; set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB); buffer_insert(output, output_length - (HASH_SIZE + 2), msg.data(), msg.size()); output[output_length-2] = hash_id; output[output_length-1] = 0xCC; return output; } } std::string EMSA_X931::name() const { return "EMSA2(" + m_hash->name() + ")"; } void EMSA_X931::update(const uint8_t input[], size_t length) { m_hash->update(input, length); } secure_vector EMSA_X931::raw_data() { return m_hash->final(); } /* * EMSA_X931 Encode Operation */ secure_vector EMSA_X931::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator&) { return emsa2_encoding(msg, output_bits, m_empty_hash, m_hash_id); } /* * EMSA_X931 Verify Operation */ bool EMSA_X931::verify(const secure_vector& coded, const secure_vector& raw, size_t key_bits) { try { return (coded == emsa2_encoding(raw, key_bits, m_empty_hash, m_hash_id)); } catch(...) { return false; } } /* * EMSA_X931 Constructor */ EMSA_X931::EMSA_X931(HashFunction* hash) : m_hash(hash) { m_empty_hash = m_hash->final(); m_hash_id = ieee1363_hash_id(hash->name()); if(!m_hash_id) throw Encoding_Error("EMSA_X931 no hash identifier for " + hash->name()); } } /* * Entropy Source Polling * (C) 2008-2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_SYSTEM_RNG) #endif #if defined(BOTAN_HAS_PROCESSOR_RNG) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_DARN) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) #endif #if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) #endif namespace Botan { namespace { #if defined(BOTAN_HAS_SYSTEM_RNG) class System_RNG_EntropySource final : public Entropy_Source { public: size_t poll(RandomNumberGenerator& rng) override { const size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS; rng.reseed_from_rng(system_rng(), poll_bits); return poll_bits; } std::string name() const override { return "system_rng"; } }; #endif #if defined(BOTAN_HAS_PROCESSOR_RNG) class Processor_RNG_EntropySource final : public Entropy_Source { public: size_t poll(RandomNumberGenerator& rng) override { /* * Intel's documentation for RDRAND at * https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide * claims that software can guarantee a reseed event by polling enough data: * "There is an upper bound of 511 samples per seed in the implementation * where samples are 128 bits in size and can provide two 64-bit random * numbers each." * * By requesting 65536 bits we are asking for 512 samples and thus are assured * that at some point in producing the output, at least one reseed of the * internal state will occur. * * The reseeding conditions of the POWER and ARM processor RNGs are not known * but probably work in a somewhat similar manner. The exact amount requested * may be tweaked if and when such conditions become publically known. */ const size_t poll_bits = 65536; rng.reseed_from_rng(m_hwrng, poll_bits); // Avoid trusting a black box, don't count this as contributing entropy: return 0; } std::string name() const override { return m_hwrng.name(); } private: Processor_RNG m_hwrng; }; #endif } std::unique_ptr Entropy_Source::create(const std::string& name) { #if defined(BOTAN_HAS_SYSTEM_RNG) if(name == "system_rng" || name == "win32_cryptoapi") { return std::unique_ptr(new System_RNG_EntropySource); } #endif #if defined(BOTAN_HAS_PROCESSOR_RNG) if(name == "hwrng" || name == "rdrand" || name == "p9_darn") { if(Processor_RNG::available()) { return std::unique_ptr(new Processor_RNG_EntropySource); } } #endif #if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED) if(name == "rdseed") { return std::unique_ptr(new Intel_Rdseed); } #endif #if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) if(name == "getentropy") { return std::unique_ptr(new Getentropy); } #endif #if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) if(name == "dev_random") { return std::unique_ptr(new Device_EntropySource(BOTAN_SYSTEM_RNG_POLL_DEVICES)); } #endif #if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) if(name == "proc_walk" && OS::running_in_privileged_state() == false) { const std::string root_dir = BOTAN_ENTROPY_PROC_FS_PATH; if(!root_dir.empty()) return std::unique_ptr(new ProcWalking_EntropySource(root_dir)); } #endif #if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) if(name == "system_stats") { return std::unique_ptr(new Win32_EntropySource); } #endif BOTAN_UNUSED(name); return std::unique_ptr(); } void Entropy_Sources::add_source(std::unique_ptr src) { if(src.get()) { m_srcs.push_back(std::move(src)); } } std::vector Entropy_Sources::enabled_sources() const { std::vector sources; for(size_t i = 0; i != m_srcs.size(); ++i) { sources.push_back(m_srcs[i]->name()); } return sources; } size_t Entropy_Sources::poll(RandomNumberGenerator& rng, size_t poll_bits, std::chrono::milliseconds timeout) { typedef std::chrono::system_clock clock; auto deadline = clock::now() + timeout; size_t bits_collected = 0; for(size_t i = 0; i != m_srcs.size(); ++i) { bits_collected += m_srcs[i]->poll(rng); if (bits_collected >= poll_bits || clock::now() > deadline) break; } return bits_collected; } size_t Entropy_Sources::poll_just(RandomNumberGenerator& rng, const std::string& the_src) { for(size_t i = 0; i != m_srcs.size(); ++i) { if(m_srcs[i]->name() == the_src) { return m_srcs[i]->poll(rng); } } return 0; } Entropy_Sources::Entropy_Sources(const std::vector& sources) { for(auto&& src_name : sources) { add_source(Entropy_Source::create(src_name)); } } Entropy_Sources& Entropy_Sources::global_sources() { static Entropy_Sources global_entropy_sources(BOTAN_ENTROPY_DEFAULT_SOURCES); return global_entropy_sources; } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include namespace Botan_FFI { int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) { std::string val; if(Botan::OS::read_env_variable(val, "BOTAN_FFI_PRINT_EXCEPTIONS") == true && val != "") { std::fprintf(stderr, "in %s exception '%s' returning %d\n", func_name, exn, rc); } return rc; } namespace { int ffi_map_error_type(Botan::ErrorType err) { switch(err) { case Botan::ErrorType::Unknown: return BOTAN_FFI_ERROR_UNKNOWN_ERROR; case Botan::ErrorType::SystemError: case Botan::ErrorType::IoError: case Botan::ErrorType::OpenSSLError: case Botan::ErrorType::Pkcs11Error: case Botan::ErrorType::CommonCryptoError: case Botan::ErrorType::TPMError: case Botan::ErrorType::ZlibError: case Botan::ErrorType::Bzip2Error: case Botan::ErrorType::LzmaError: case Botan::ErrorType::DatabaseError: return BOTAN_FFI_ERROR_SYSTEM_ERROR; case Botan::ErrorType::NotImplemented: return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; case Botan::ErrorType::OutOfMemory: return BOTAN_FFI_ERROR_OUT_OF_MEMORY; case Botan::ErrorType::InternalError: return BOTAN_FFI_ERROR_INTERNAL_ERROR; case Botan::ErrorType::InvalidObjectState: return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE; case Botan::ErrorType::KeyNotSet: return BOTAN_FFI_ERROR_KEY_NOT_SET; case Botan::ErrorType::InvalidArgument: case Botan::ErrorType::InvalidNonceLength: return BOTAN_FFI_ERROR_BAD_PARAMETER; case Botan::ErrorType::EncodingFailure: case Botan::ErrorType::DecodingFailure: return BOTAN_FFI_ERROR_INVALID_INPUT; case Botan::ErrorType::InvalidTag: return BOTAN_FFI_ERROR_BAD_MAC; case Botan::ErrorType::InvalidKeyLength: return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH; case Botan::ErrorType::LookupError: return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; case Botan::ErrorType::HttpError: return BOTAN_FFI_ERROR_HTTP_ERROR; case Botan::ErrorType::TLSError: return BOTAN_FFI_ERROR_TLS_ERROR; case Botan::ErrorType::RoughtimeError: return BOTAN_FFI_ERROR_ROUGHTIME_ERROR; } return BOTAN_FFI_ERROR_UNKNOWN_ERROR; } } int ffi_guard_thunk(const char* func_name, std::function thunk) { try { return thunk(); } catch(std::bad_alloc&) { return ffi_error_exception_thrown(func_name, "bad_alloc", BOTAN_FFI_ERROR_OUT_OF_MEMORY); } catch(Botan_FFI::FFI_Error& e) { return ffi_error_exception_thrown(func_name, e.what(), e.error_code()); } catch(Botan::Exception& e) { return ffi_error_exception_thrown(func_name, e.what(), ffi_map_error_type(e.error_type())); } catch(std::exception& e) { return ffi_error_exception_thrown(func_name, e.what()); } catch(...) { return ffi_error_exception_thrown(func_name, "unknown exception"); } return BOTAN_FFI_ERROR_UNKNOWN_ERROR; } } extern "C" { using namespace Botan_FFI; const char* botan_error_description(int err) { switch(err) { case BOTAN_FFI_SUCCESS: return "OK"; case BOTAN_FFI_INVALID_VERIFIER: return "Invalid verifier"; case BOTAN_FFI_ERROR_INVALID_INPUT: return "Invalid input"; case BOTAN_FFI_ERROR_BAD_MAC: return "Invalid authentication code"; case BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE: return "Insufficient buffer space"; case BOTAN_FFI_ERROR_EXCEPTION_THROWN: return "Exception thrown"; case BOTAN_FFI_ERROR_OUT_OF_MEMORY: return "Out of memory"; case BOTAN_FFI_ERROR_SYSTEM_ERROR: return "Error while calling system API"; case BOTAN_FFI_ERROR_INTERNAL_ERROR: return "Internal error"; case BOTAN_FFI_ERROR_BAD_FLAG: return "Bad flag"; case BOTAN_FFI_ERROR_NULL_POINTER: return "Null pointer argument"; case BOTAN_FFI_ERROR_BAD_PARAMETER: return "Bad parameter"; case BOTAN_FFI_ERROR_KEY_NOT_SET: return "Key not set on object"; case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH: return "Invalid key length"; case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE: return "Invalid object state"; case BOTAN_FFI_ERROR_NOT_IMPLEMENTED: return "Not implemented"; case BOTAN_FFI_ERROR_INVALID_OBJECT: return "Invalid object handle"; case BOTAN_FFI_ERROR_TLS_ERROR: return "TLS error"; case BOTAN_FFI_ERROR_HTTP_ERROR: return "HTTP error"; case BOTAN_FFI_ERROR_UNKNOWN_ERROR: return "Unknown error"; } return "Unknown error"; } /* * Versioning */ uint32_t botan_ffi_api_version() { return BOTAN_HAS_FFI; } int botan_ffi_supports_api(uint32_t api_version) { // This is the API introduced in 2.18 if(api_version == 20210220) return BOTAN_FFI_SUCCESS; // This is the API introduced in 2.13 if(api_version == 20191214) return BOTAN_FFI_SUCCESS; // This is the API introduced in 2.8 if(api_version == 20180713) return BOTAN_FFI_SUCCESS; // This is the API introduced in 2.3 if(api_version == 20170815) return BOTAN_FFI_SUCCESS; // This is the API introduced in 2.1 if(api_version == 20170327) return BOTAN_FFI_SUCCESS; // This is the API introduced in 2.0 if(api_version == 20150515) return BOTAN_FFI_SUCCESS; // Something else: return -1; } const char* botan_version_string() { return Botan::version_cstr(); } uint32_t botan_version_major() { return Botan::version_major(); } uint32_t botan_version_minor() { return Botan::version_minor(); } uint32_t botan_version_patch() { return Botan::version_patch(); } uint32_t botan_version_datestamp() { return Botan::version_datestamp(); } int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) { return Botan::constant_time_compare(x, y, len) ? 0 : -1; } int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) { return botan_constant_time_compare(x, y, len); } int botan_scrub_mem(void* mem, size_t bytes) { Botan::secure_scrub_memory(mem, bytes); return BOTAN_FFI_SUCCESS; } int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) { return ffi_guard_thunk(__func__, [=]() -> int { const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0; Botan::hex_encode(out, in, len, uppercase); return BOTAN_FFI_SUCCESS; }); } int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) { return ffi_guard_thunk(__func__, [=]() -> int { const std::vector bin = Botan::hex_decode(hex_str, in_len); return Botan_FFI::write_vec_output(out, out_len, bin); }); } int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) { return ffi_guard_thunk(__func__, [=]() -> int { const std::string base64 = Botan::base64_encode(in, len); return Botan_FFI::write_str_output(out, out_len, base64); }); } int botan_base64_decode(const char* base64_str, size_t in_len, uint8_t* out, size_t* out_len) { return ffi_guard_thunk(__func__, [=]() -> int { if(*out_len < Botan::base64_decode_max_output(in_len)) { *out_len = Botan::base64_decode_max_output(in_len); return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; } *out_len = Botan::base64_decode(out, std::string(base64_str, in_len)); return BOTAN_FFI_SUCCESS; }); } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ extern "C" { using namespace Botan_FFI; BOTAN_FFI_DECLARE_STRUCT(botan_block_cipher_struct, Botan::BlockCipher, 0x64C29716); int botan_block_cipher_init(botan_block_cipher_t* bc, const char* bc_name) { return ffi_guard_thunk(__func__, [=]() -> int { if(bc == nullptr || bc_name == nullptr || *bc_name == 0) return BOTAN_FFI_ERROR_NULL_POINTER; *bc = nullptr; std::unique_ptr cipher(Botan::BlockCipher::create(bc_name)); if(cipher == nullptr) return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; *bc = new botan_block_cipher_struct(cipher.release()); return BOTAN_FFI_SUCCESS; }); } /** * Destroy a block cipher object */ int botan_block_cipher_destroy(botan_block_cipher_t bc) { return BOTAN_FFI_CHECKED_DELETE(bc); } int botan_block_cipher_clear(botan_block_cipher_t bc) { return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.clear(); }); } /** * Set the key for a block cipher instance */ int botan_block_cipher_set_key(botan_block_cipher_t bc, const uint8_t key[], size_t len) { if(key == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.set_key(key, len); }); } /** * Return the positive block size of this block cipher, or negative to * indicate an error */ int botan_block_cipher_block_size(botan_block_cipher_t bc) { return BOTAN_FFI_RETURNING(Botan::BlockCipher, bc, b, { return static_cast(b.block_size()); }); } int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks) { if(in == nullptr || out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.encrypt_n(in, out, blocks); }); } int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks) { if(in == nullptr || out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.decrypt_n(in, out, blocks); }); } int botan_block_cipher_name(botan_block_cipher_t cipher, char* name, size_t* name_len) { if(name_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::BlockCipher, cipher, bc, { return write_str_output(name, name_len, bc.name()); }); } int botan_block_cipher_get_keyspec(botan_block_cipher_t cipher, size_t* out_minimum_keylength, size_t* out_maximum_keylength, size_t* out_keylength_modulo) { return BOTAN_FFI_DO(Botan::BlockCipher, cipher, bc, { if(out_minimum_keylength) *out_minimum_keylength = bc.minimum_keylength(); if(out_maximum_keylength) *out_maximum_keylength = bc.maximum_keylength(); if(out_keylength_modulo) *out_keylength_modulo = bc.key_spec().keylength_multiple(); }); } } /* * (C) 2015,2017,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_X509_CERTIFICATES) #endif extern "C" { using namespace Botan_FFI; #if defined(BOTAN_HAS_X509_CERTIFICATES) BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937); #endif int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) { if(!cert_obj || !cert_path) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr c(new Botan::X509_Certificate(cert_path)); *cert_obj = new botan_x509_cert_struct(c.release()); return BOTAN_FFI_SUCCESS; }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) { if(!cert_obj) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr c(new Botan::X509_Certificate(safe_get(cert))); *cert_obj = new botan_x509_cert_struct(c.release()); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(cert); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) { if(!cert_obj || !cert_bits) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_X509_CERTIFICATES) return ffi_guard_thunk(__func__, [=]() -> int { Botan::DataSource_Memory bits(cert_bits, cert_bits_len); std::unique_ptr c(new Botan::X509_Certificate(bits)); *cert_obj = new botan_x509_cert_struct(c.release()); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(cert_bits_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) { if(key == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *key = nullptr; #if defined(BOTAN_HAS_X509_CERTIFICATES) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr publicKey = safe_get(cert).load_subject_public_key(); *key = new botan_pubkey_struct(publicKey.release()); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(cert); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.issuer_info(key).at(index)); }); #else BOTAN_UNUSED(cert, key, index, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.subject_info(key).at(index)); }); #else BOTAN_UNUSED(cert, key, index, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.to_string()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_RETURNING(Botan::X509_Certificate, cert, c, { const Botan::Key_Constraints k = static_cast(key_usage); if(c.allowed_usage(k)) return BOTAN_FFI_SUCCESS; return 1; }); #else BOTAN_UNUSED(cert, key_usage); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_destroy(botan_x509_cert_t cert) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_CHECKED_DELETE(cert); #else BOTAN_UNUSED(cert); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.not_before().to_string()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.not_after().to_string()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { *time_since_epoch = c.not_before().time_since_epoch(); }); #else BOTAN_UNUSED(cert, time_since_epoch); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { *time_since_epoch = c.not_after().time_since_epoch(); }); #else BOTAN_UNUSED(cert, time_since_epoch); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.serial_number()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.fingerprint(hash)); }); #else BOTAN_UNUSED(cert, hash, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.authority_key_id()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_key_id()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_public_key_bits()); }); #else BOTAN_UNUSED(cert, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) { if(hostname == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return c.matches_dns_name(hostname) ? 0 : -1; }); #else BOTAN_UNUSED(cert); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_verify(int* result_code, botan_x509_cert_t cert, const botan_x509_cert_t* intermediates, size_t intermediates_len, const botan_x509_cert_t* trusted, size_t trusted_len, const char* trusted_path, size_t required_strength, const char* hostname_cstr, uint64_t reference_time) { if(required_strength == 0) required_strength = 110; #if defined(BOTAN_HAS_X509_CERTIFICATES) return ffi_guard_thunk(__func__, [=]() -> int { const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr); const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED; const auto validation_time = reference_time == 0 ? std::chrono::system_clock::now() : std::chrono::system_clock::from_time_t(static_cast(reference_time)); std::vector end_certs; end_certs.push_back(safe_get(cert)); for(size_t i = 0; i != intermediates_len; ++i) end_certs.push_back(safe_get(intermediates[i])); std::unique_ptr trusted_from_path; std::unique_ptr trusted_extra; std::vector trusted_roots; if(trusted_path && *trusted_path) { trusted_from_path.reset(new Botan::Certificate_Store_In_Memory(trusted_path)); trusted_roots.push_back(trusted_from_path.get()); } if(trusted_len > 0) { trusted_extra.reset(new Botan::Certificate_Store_In_Memory); for(size_t i = 0; i != trusted_len; ++i) { trusted_extra->add_certificate(safe_get(trusted[i])); } trusted_roots.push_back(trusted_extra.get()); } Botan::Path_Validation_Restrictions restrictions(false, required_strength); auto validation_result = Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time); if(result_code) *result_code = static_cast(validation_result.result()); if(validation_result.successful_validation()) return 0; else return 1; }); #else BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted); BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } const char* botan_x509_cert_validation_status(int code) { if(code < 0) return nullptr; #if defined(BOTAN_HAS_X509_CERTIFICATES) Botan::Certificate_Status_Code sc = static_cast(code); return Botan::to_string(sc); #else return nullptr; #endif } #if defined(BOTAN_HAS_X509_CERTIFICATES) BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910); #endif int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) { if(!crl_obj || !crl_path) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr c(new Botan::X509_CRL(crl_path)); *crl_obj = new botan_x509_crl_struct(c.release()); return BOTAN_FFI_SUCCESS; }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) { if(!crl_obj || !crl_bits) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_X509_CERTIFICATES) return ffi_guard_thunk(__func__, [=]() -> int { Botan::DataSource_Memory bits(crl_bits, crl_bits_len); std::unique_ptr c(new Botan::X509_CRL(bits)); *crl_obj = new botan_x509_crl_struct(c.release()); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(crl_bits_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_crl_destroy(botan_x509_crl_t crl) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_CHECKED_DELETE(crl); #else BOTAN_UNUSED(crl); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_RETURNING(Botan::X509_CRL, crl, c, { return c.is_revoked(safe_get(cert)) ? 0 : -1; }); #else BOTAN_UNUSED(cert); BOTAN_UNUSED(crl); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_x509_cert_verify_with_crl( int* result_code, botan_x509_cert_t cert, const botan_x509_cert_t* intermediates, size_t intermediates_len, const botan_x509_cert_t* trusted, size_t trusted_len, const botan_x509_crl_t* crls, size_t crls_len, const char* trusted_path, size_t required_strength, const char* hostname_cstr, uint64_t reference_time) { if(required_strength == 0) required_strength = 110; #if defined(BOTAN_HAS_X509_CERTIFICATES) return ffi_guard_thunk(__func__, [=]() -> int { const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr); const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED; const auto validation_time = reference_time == 0 ? std::chrono::system_clock::now() : std::chrono::system_clock::from_time_t(static_cast(reference_time)); std::vector end_certs; end_certs.push_back(safe_get(cert)); for(size_t i = 0; i != intermediates_len; ++i) end_certs.push_back(safe_get(intermediates[i])); std::unique_ptr trusted_from_path; std::unique_ptr trusted_extra; std::unique_ptr trusted_crls; std::vector trusted_roots; if(trusted_path && *trusted_path) { trusted_from_path.reset(new Botan::Certificate_Store_In_Memory(trusted_path)); trusted_roots.push_back(trusted_from_path.get()); } if(trusted_len > 0) { trusted_extra.reset(new Botan::Certificate_Store_In_Memory); for(size_t i = 0; i != trusted_len; ++i) { trusted_extra->add_certificate(safe_get(trusted[i])); } trusted_roots.push_back(trusted_extra.get()); } if(crls_len > 0) { trusted_crls.reset(new Botan::Certificate_Store_In_Memory); for(size_t i = 0; i != crls_len; ++i) { trusted_crls->add_crl(safe_get(crls[i])); } trusted_roots.push_back(trusted_crls.get()); } Botan::Path_Validation_Restrictions restrictions(false, required_strength); auto validation_result = Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time); if(result_code) *result_code = static_cast(validation_result.result()); if(validation_result.successful_validation()) return 0; else return 1; }); #else BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted); BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ extern "C" { using namespace Botan_FFI; struct botan_cipher_struct final : public botan_struct { explicit botan_cipher_struct(Botan::Cipher_Mode* x) : botan_struct(x) {} Botan::secure_vector m_buf; }; int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags) { return ffi_guard_thunk(__func__, [=]() -> int { const bool encrypt_p = ((flags & BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION) == BOTAN_CIPHER_INIT_FLAG_ENCRYPT); const Botan::Cipher_Dir dir = encrypt_p ? Botan::ENCRYPTION : Botan::DECRYPTION; std::unique_ptr mode(Botan::Cipher_Mode::create(cipher_name, dir)); if(!mode) return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; *cipher = new botan_cipher_struct(mode.release()); return BOTAN_FFI_SUCCESS; }); } int botan_cipher_destroy(botan_cipher_t cipher) { return BOTAN_FFI_CHECKED_DELETE(cipher); } int botan_cipher_clear(botan_cipher_t cipher) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.clear(); }); } int botan_cipher_reset(botan_cipher_t cipher) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.reset(); }); } int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t* out_len) { if(out_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *out_len = c.output_length(in_len); }); } int botan_cipher_query_keylen(botan_cipher_t cipher, size_t* out_minimum_keylength, size_t* out_maximum_keylength) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *out_minimum_keylength = c.key_spec().minimum_keylength(); *out_maximum_keylength = c.key_spec().maximum_keylength(); }); } int botan_cipher_get_keyspec(botan_cipher_t cipher, size_t* out_minimum_keylength, size_t* out_maximum_keylength, size_t* out_keylength_modulo) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { if(out_minimum_keylength) *out_minimum_keylength = c.key_spec().minimum_keylength(); if(out_maximum_keylength) *out_maximum_keylength = c.key_spec().maximum_keylength(); if(out_keylength_modulo) *out_keylength_modulo = c.key_spec().keylength_multiple(); }); } int botan_cipher_set_key(botan_cipher_t cipher, const uint8_t* key, size_t key_len) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.set_key(key, key_len); }); } int botan_cipher_start(botan_cipher_t cipher_obj, const uint8_t* nonce, size_t nonce_len) { return ffi_guard_thunk(__func__, [=]() -> int { Botan::Cipher_Mode& cipher = safe_get(cipher_obj); cipher.start(nonce, nonce_len); cipher_obj->m_buf.reserve(cipher.update_granularity()); return BOTAN_FFI_SUCCESS; }); } int botan_cipher_update(botan_cipher_t cipher_obj, uint32_t flags, uint8_t output_ptr[], size_t orig_output_size, size_t* output_written, const uint8_t input_ptr[], size_t orig_input_size, size_t* input_consumed) { return ffi_guard_thunk(__func__, [=]() -> int { size_t input_size = orig_input_size; size_t output_size = orig_output_size; const uint8_t* input = input_ptr; uint8_t* output = output_ptr; using namespace Botan; Cipher_Mode& cipher = safe_get(cipher_obj); secure_vector& mbuf = cipher_obj->m_buf; const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL); if(final_input) { mbuf.assign(input, input + input_size); *input_consumed = input_size; *output_written = 0; try { cipher.finish(mbuf); } catch(Invalid_Authentication_Tag&) { return BOTAN_FFI_ERROR_BAD_MAC; } *output_written = mbuf.size(); if(mbuf.size() <= output_size) { copy_mem(output, mbuf.data(), mbuf.size()); mbuf.clear(); return BOTAN_FFI_SUCCESS; } return -1; } if(input_size == 0) { // Currently must take entire buffer in this case *output_written = mbuf.size(); if(output_size >= mbuf.size()) { copy_mem(output, mbuf.data(), mbuf.size()); mbuf.clear(); return BOTAN_FFI_SUCCESS; } return -1; } const size_t ud = cipher.update_granularity(); BOTAN_ASSERT(cipher.update_granularity() > cipher.minimum_final_size(), "logic error"); mbuf.resize(ud); size_t taken = 0, written = 0; while(input_size >= ud && output_size >= ud) { // FIXME we can use process here and avoid the copy copy_mem(mbuf.data(), input, ud); cipher.update(mbuf); input_size -= ud; copy_mem(output, mbuf.data(), ud); input += ud; taken += ud; output_size -= ud; output += ud; written += ud; } *output_written = written; *input_consumed = taken; return BOTAN_FFI_SUCCESS; }); } int botan_cipher_set_associated_data(botan_cipher_t cipher, const uint8_t* ad, size_t ad_len) { return BOTAN_FFI_RETURNING(Botan::Cipher_Mode, cipher, c, { if(Botan::AEAD_Mode* aead = dynamic_cast(&c)) { aead->set_associated_data(ad, ad_len); return BOTAN_FFI_SUCCESS; } return BOTAN_FFI_ERROR_BAD_PARAMETER; }); } int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl) { return BOTAN_FFI_RETURNING(Botan::Cipher_Mode, cipher, c, { return c.valid_nonce_length(nl) ? 1 : 0; }); } int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *nl = c.default_nonce_length(); }); } int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *ug = c.update_granularity(); }); } int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *tl = c.tag_size(); }); } int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { return write_str_output(name, name_len, c.name()); }); } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_HAS_FPE_FE1) #endif extern "C" { using namespace Botan_FFI; #if defined(BOTAN_HAS_FPE_FE1) BOTAN_FFI_DECLARE_STRUCT(botan_fpe_struct, Botan::FPE_FE1, 0xD49FB820); #endif int botan_fpe_fe1_init(botan_fpe_t* fpe, botan_mp_t n, const uint8_t key[], size_t key_len, size_t rounds, uint32_t flags) { #if defined(BOTAN_HAS_FPE_FE1) return ffi_guard_thunk(__func__, [=]() { if(fpe == nullptr || key == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *fpe = nullptr; if(flags != 0 && flags != BOTAN_FPE_FLAG_FE1_COMPAT_MODE) return BOTAN_FFI_ERROR_BAD_FLAG; const bool compat_mode = (flags & BOTAN_FPE_FLAG_FE1_COMPAT_MODE); std::unique_ptr fpe_obj( new Botan::FPE_FE1(safe_get(n), rounds, compat_mode)); fpe_obj->set_key(key, key_len); *fpe = new botan_fpe_struct(fpe_obj.release()); return BOTAN_FFI_SUCCESS; }); #else *fpe = nullptr; return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_fpe_destroy(botan_fpe_t fpe) { #if defined(BOTAN_HAS_FPE_FE1) return BOTAN_FFI_CHECKED_DELETE(fpe); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_fpe_encrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len) { #if defined(BOTAN_HAS_FPE_FE1) return ffi_guard_thunk(__func__, [=]() { Botan::BigInt r = safe_get(fpe).encrypt(safe_get(x), tweak, tweak_len); safe_get(x) = r; return BOTAN_FFI_SUCCESS; }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_fpe_decrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len) { #if defined(BOTAN_HAS_FPE_FE1) return ffi_guard_thunk(__func__, [=]() { Botan::BigInt r = safe_get(fpe).decrypt(safe_get(x), tweak, tweak_len); safe_get(x) = r; return BOTAN_FFI_SUCCESS; }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ extern "C" { using namespace Botan_FFI; BOTAN_FFI_DECLARE_STRUCT(botan_hash_struct, Botan::HashFunction, 0x1F0A4F84); int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags) { return ffi_guard_thunk(__func__, [=]() -> int { if(hash == nullptr || hash_name == nullptr || *hash_name == 0) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0) return BOTAN_FFI_ERROR_BAD_FLAG; std::unique_ptr h = Botan::HashFunction::create(hash_name); if(h == nullptr) return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; *hash = new botan_hash_struct(h.release()); return BOTAN_FFI_SUCCESS; }); } int botan_hash_destroy(botan_hash_t hash) { return BOTAN_FFI_CHECKED_DELETE(hash); } int botan_hash_output_length(botan_hash_t hash, size_t* out) { if(out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.output_length(); }); } int botan_hash_block_size(botan_hash_t hash, size_t* out) { if(out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.hash_block_size(); }); } int botan_hash_clear(botan_hash_t hash) { return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.clear(); }); } int botan_hash_update(botan_hash_t hash, const uint8_t* buf, size_t len) { if(len == 0) return 0; if(buf == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.update(buf, len); }); } int botan_hash_final(botan_hash_t hash, uint8_t out[]) { if(out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.final(out); }); } int botan_hash_copy_state(botan_hash_t* dest, const botan_hash_t source) { return BOTAN_FFI_DO(Botan::HashFunction, source, src, { *dest = new botan_hash_struct(src.copy_state().release()); }); } int botan_hash_name(botan_hash_t hash, char* name, size_t* name_len) { if(name_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { return write_str_output(name, name_len, h.name()); }); } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_HOTP) #endif extern "C" { using namespace Botan_FFI; #if defined(BOTAN_HAS_HOTP) BOTAN_FFI_DECLARE_STRUCT(botan_hotp_struct, Botan::HOTP, 0x89CBF191); #endif int botan_hotp_init(botan_hotp_t* hotp, const uint8_t key[], size_t key_len, const char* hash_algo, size_t digits) { if(hotp == nullptr || key == nullptr || hash_algo == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *hotp = nullptr; #if defined(BOTAN_HAS_HOTP) return ffi_guard_thunk(__func__, [=]() -> int { *hotp = new botan_hotp_struct( new Botan::HOTP(key, key_len, hash_algo, digits)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(hotp, key, key_len, hash_algo, digits); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_hotp_destroy(botan_hotp_t hotp) { #if defined(BOTAN_HAS_HOTP) return BOTAN_FFI_CHECKED_DELETE(hotp); #else BOTAN_UNUSED(hotp); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_hotp_generate(botan_hotp_t hotp, uint32_t* hotp_code, uint64_t hotp_counter) { #if defined(BOTAN_HAS_HOTP) if(hotp == nullptr || hotp_code == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::HOTP, hotp, h, { *hotp_code = h.generate_hotp(hotp_counter); }); #else BOTAN_UNUSED(hotp, hotp_code, hotp_counter); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_hotp_check(botan_hotp_t hotp, uint64_t* next_hotp_counter, uint32_t hotp_code, uint64_t hotp_counter, size_t resync_range) { #if defined(BOTAN_HAS_HOTP) return BOTAN_FFI_RETURNING(Botan::HOTP, hotp, h, { auto resp = h.verify_hotp(hotp_code, hotp_counter, resync_range); if(next_hotp_counter) *next_hotp_counter = resp.second; return (resp.first == true) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER; }); #else BOTAN_UNUSED(hotp, next_hotp_counter, hotp_code, hotp_counter, resync_range); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_BCRYPT) #endif extern "C" { using namespace Botan_FFI; int botan_pbkdf(const char* algo, uint8_t out[], size_t out_len, const char* pass, const uint8_t salt[], size_t salt_len, size_t iterations) { return botan_pwdhash(algo, iterations, 0, 0, out, out_len, pass, 0, salt, salt_len); } int botan_pbkdf_timed(const char* algo, uint8_t out[], size_t out_len, const char* password, const uint8_t salt[], size_t salt_len, size_t ms_to_run, size_t* iterations_used) { return botan_pwdhash_timed(algo, static_cast(ms_to_run), iterations_used, nullptr, nullptr, out, out_len, password, 0, salt, salt_len); } int botan_pwdhash( const char* algo, size_t param1, size_t param2, size_t param3, uint8_t out[], size_t out_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) { if(algo == nullptr || password == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(password_len == 0) password_len = std::strlen(password); return ffi_guard_thunk(__func__, [=]() -> int { auto pwdhash_fam = Botan::PasswordHashFamily::create(algo); if(!pwdhash_fam) return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; auto pwdhash = pwdhash_fam->from_params(param1, param2, param3); pwdhash->derive_key(out, out_len, password, password_len, salt, salt_len); return BOTAN_FFI_SUCCESS; }); } int botan_pwdhash_timed( const char* algo, uint32_t msec, size_t* param1, size_t* param2, size_t* param3, uint8_t out[], size_t out_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) { if(algo == nullptr || password == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(password_len == 0) password_len = std::strlen(password); return ffi_guard_thunk(__func__, [=]() -> int { auto pwdhash_fam = Botan::PasswordHashFamily::create(algo); if(!pwdhash_fam) return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; auto pwdhash = pwdhash_fam->tune(out_len, std::chrono::milliseconds(msec)); if(param1) *param1 = pwdhash->iterations(); if(param2) *param2 = pwdhash->parallelism(); if(param3) *param3 = pwdhash->memory_param(); pwdhash->derive_key(out, out_len, password, password_len, salt, salt_len); return BOTAN_FFI_SUCCESS; }); } int botan_kdf(const char* kdf_algo, uint8_t out[], size_t out_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) { return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr kdf(Botan::get_kdf(kdf_algo)); kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len); return BOTAN_FFI_SUCCESS; }); } int botan_scrypt(uint8_t out[], size_t out_len, const char* password, const uint8_t salt[], size_t salt_len, size_t N, size_t r, size_t p) { return botan_pwdhash("Scrypt", N, r, p, out, out_len, password, 0, salt, salt_len); } int botan_bcrypt_generate(uint8_t* out, size_t* out_len, const char* pass, botan_rng_t rng_obj, size_t wf, uint32_t flags) { #if defined(BOTAN_HAS_BCRYPT) return ffi_guard_thunk(__func__, [=]() -> int { if(out == nullptr || out_len == nullptr || pass == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0) return BOTAN_FFI_ERROR_BAD_FLAG; if(wf < 4 || wf > 18) return BOTAN_FFI_ERROR_BAD_PARAMETER; Botan::RandomNumberGenerator& rng = safe_get(rng_obj); const std::string bcrypt = Botan::generate_bcrypt(pass, rng, static_cast(wf)); return write_str_output(out, out_len, bcrypt); }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_bcrypt_is_valid(const char* pass, const char* hash) { #if defined(BOTAN_HAS_BCRYPT) return ffi_guard_thunk(__func__, [=]() -> int { return Botan::check_bcrypt(pass, hash) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER; }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * (C) 2017 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_RFC3394_KEYWRAP) #endif extern "C" { using namespace Botan_FFI; int botan_key_wrap3394(const uint8_t key[], size_t key_len, const uint8_t kek[], size_t kek_len, uint8_t wrapped_key[], size_t* wrapped_key_len) { #if defined(BOTAN_HAS_RFC3394_KEYWRAP) return ffi_guard_thunk(__func__, [=]() -> int { const Botan::SymmetricKey kek_sym(kek, kek_len); const Botan::secure_vector key_pt(key, key + key_len); const Botan::secure_vector key_ct = Botan::rfc3394_keywrap(key_pt, kek_sym); return write_vec_output(wrapped_key, wrapped_key_len, key_ct); }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_key_unwrap3394(const uint8_t wrapped_key[], size_t wrapped_key_len, const uint8_t kek[], size_t kek_len, uint8_t key[], size_t* key_len) { #if defined(BOTAN_HAS_RFC3394_KEYWRAP) return ffi_guard_thunk(__func__, [=]() -> int { const Botan::SymmetricKey kek_sym(kek, kek_len); const Botan::secure_vector key_ct(wrapped_key, wrapped_key + wrapped_key_len); const Botan::secure_vector key_pt = Botan::rfc3394_keyunwrap(key_ct, kek_sym); return write_vec_output(key, key_len, key_pt); }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ extern "C" { using namespace Botan_FFI; BOTAN_FFI_DECLARE_STRUCT(botan_mac_struct, Botan::MessageAuthenticationCode, 0xA06E8FC1); int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags) { return ffi_guard_thunk(__func__, [=]() -> int { if(!mac || !mac_name || flags != 0) return BOTAN_FFI_ERROR_NULL_POINTER; std::unique_ptr m = Botan::MessageAuthenticationCode::create(mac_name); if(m == nullptr) return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; *mac = new botan_mac_struct(m.release()); return BOTAN_FFI_SUCCESS; }); } int botan_mac_destroy(botan_mac_t mac) { return BOTAN_FFI_CHECKED_DELETE(mac); } int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.set_key(key, key_len); }); } int botan_mac_output_length(botan_mac_t mac, size_t* out) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { *out = m.output_length(); }); } int botan_mac_clear(botan_mac_t mac) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.clear(); }); } int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.update(buf, len); }); } int botan_mac_final(botan_mac_t mac, uint8_t out[]) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.final(out); }); } int botan_mac_name(botan_mac_t mac, char* name, size_t* name_len) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { return write_str_output(name, name_len, m.name()); }); } int botan_mac_get_keyspec(botan_mac_t mac, size_t* out_minimum_keylength, size_t* out_maximum_keylength, size_t* out_keylength_modulo) { return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { if(out_minimum_keylength) *out_minimum_keylength = m.minimum_keylength(); if(out_maximum_keylength) *out_maximum_keylength = m.maximum_keylength(); if(out_keylength_modulo) *out_keylength_modulo = m.key_spec().keylength_multiple(); }); } } /* * (C) 2015,2017 Jack Lloyd * (C) 2017 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ extern "C" { using namespace Botan_FFI; int botan_mp_init(botan_mp_t* mp_out) { return ffi_guard_thunk(__func__, [=]() -> int { if(mp_out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *mp_out = new botan_mp_struct(new Botan::BigInt); return BOTAN_FFI_SUCCESS; }); } int botan_mp_clear(botan_mp_t mp) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.clear(); }); } int botan_mp_set_from_int(botan_mp_t mp, int initial_value) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { if(initial_value >= 0) { bn = Botan::BigInt(static_cast(initial_value)); } else { bn = Botan::BigInt(static_cast(-initial_value)); bn.flip_sign(); } }); } int botan_mp_set_from_str(botan_mp_t mp, const char* str) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn = Botan::BigInt(str); }); } int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { Botan::BigInt::Base base; if(radix == 10) base = Botan::BigInt::Decimal; else if(radix == 16) base = Botan::BigInt::Hexadecimal; else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; const uint8_t* bytes = Botan::cast_char_ptr_to_uint8(str); const size_t len = strlen(str); bn = Botan::BigInt(bytes, len, base); }); } int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source) { return BOTAN_FFI_DO(Botan::BigInt, dest, bn, { bn = safe_get(source); }); } int botan_mp_is_negative(const botan_mp_t mp) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_negative() ? 1 : 0; }); } int botan_mp_is_positive(const botan_mp_t mp) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_positive() ? 1 : 0; }); } int botan_mp_flip_sign(botan_mp_t mp) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.flip_sign(); }); } int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_decode(bin, bin_len); }); } int botan_mp_to_hex(const botan_mp_t mp, char* out) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { const std::string hex = bn.to_hex_string(); std::memcpy(out, hex.c_str(), 1 + hex.size()); }); } int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len) { return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { if(digit_base == 0 || digit_base == 10) return write_str_output(out, out_len, bn.to_dec_string()); else if(digit_base == 16) return write_str_output(out, out_len, bn.to_hex_string()); else return BOTAN_FFI_ERROR_BAD_PARAMETER; }); } int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[]) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_encode(vec); }); } int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val) { if(val == nullptr) { return BOTAN_FFI_ERROR_NULL_POINTER; } return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { *val = bn.to_u32bit(); }); } int botan_mp_destroy(botan_mp_t mp) { return BOTAN_FFI_CHECKED_DELETE(mp); } int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y) { return BOTAN_FFI_DO(Botan::BigInt, result, res, { if(result == x) res += safe_get(y); else res = safe_get(x) + safe_get(y); }); } int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y) { return BOTAN_FFI_DO(Botan::BigInt, result, res, { if(result == x) res -= safe_get(y); else res = safe_get(x) - safe_get(y); }); } int botan_mp_add_u32(botan_mp_t result, const botan_mp_t x, uint32_t y) { return BOTAN_FFI_DO(Botan::BigInt, result, res, { if(result == x) res += static_cast(y); else res = safe_get(x) + static_cast(y); }); } int botan_mp_sub_u32(botan_mp_t result, const botan_mp_t x, uint32_t y) { return BOTAN_FFI_DO(Botan::BigInt, result, res, { if(result == x) res -= static_cast(y); else res = safe_get(x) - static_cast(y); }); } int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y) { return BOTAN_FFI_DO(Botan::BigInt, result, res, { if(result == x) res *= safe_get(y); else res = safe_get(x) * safe_get(y); }); } int botan_mp_div(botan_mp_t quotient, botan_mp_t remainder, const botan_mp_t x, const botan_mp_t y) { return BOTAN_FFI_DO(Botan::BigInt, quotient, q, { Botan::BigInt r; Botan::vartime_divide(safe_get(x), safe_get(y), q, r); safe_get(remainder) = r; }); } int botan_mp_equal(const botan_mp_t x_w, const botan_mp_t y_w) { return BOTAN_FFI_RETURNING(Botan::BigInt, x_w, x, { return x == safe_get(y_w); }); } int botan_mp_is_zero(const botan_mp_t mp) { return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_zero(); }); } int botan_mp_is_odd(const botan_mp_t mp) { return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_odd(); }); } int botan_mp_is_even(const botan_mp_t mp) { return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_even(); }); } int botan_mp_cmp(int* result, const botan_mp_t x_w, const botan_mp_t y_w) { return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { *result = x.cmp(safe_get(y_w)); }); } int botan_mp_swap(botan_mp_t x_w, botan_mp_t y_w) { return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { x.swap(safe_get(y_w)); }); } // Return (base^exponent) % modulus int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus) { return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::power_mod(safe_get(base), safe_get(exponent), safe_get(modulus)); }); } int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift) { return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) << shift; }); } int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift) { return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) >> shift; }); } int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus) { return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::inverse_mod(safe_get(in), safe_get(modulus)); }); } int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus) { return BOTAN_FFI_DO(Botan::BigInt, out, o, { Botan::Modular_Reducer reducer(safe_get(modulus)); o = reducer.multiply(safe_get(x), safe_get(y)); }); } int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits) { return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { safe_get(rand_out).randomize(r, bits); }); } int botan_mp_rand_range(botan_mp_t rand_out, botan_rng_t rng, const botan_mp_t lower, const botan_mp_t upper) { return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { safe_get(rand_out) = Botan::BigInt::random_integer(r, safe_get(lower), safe_get(upper)); }); } int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y) { return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::gcd(safe_get(x), safe_get(y)); }); } int botan_mp_is_prime(const botan_mp_t mp, botan_rng_t rng, size_t test_prob) { return BOTAN_FFI_RETURNING(Botan::BigInt, mp, n, { return (Botan::is_prime(n, safe_get(rng), test_prob)) ? 1 : 0; }); } int botan_mp_get_bit(const botan_mp_t mp, size_t bit) { return BOTAN_FFI_RETURNING(Botan::BigInt, mp, n, { return (n.get_bit(bit)); }); } int botan_mp_set_bit(botan_mp_t mp, size_t bit) { return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.set_bit(bit); }); } int botan_mp_clear_bit(botan_mp_t mp, size_t bit) { return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.clear_bit(bit); }); } int botan_mp_num_bits(const botan_mp_t mp, size_t* bits) { return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bits = n.bits(); }); } int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes) { return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); }); } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ extern "C" { using namespace Botan_FFI; BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3); BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37); BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F); BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936); BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1); int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, botan_pubkey_t key_obj, const char* padding, uint32_t flags) { if(op == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) return BOTAN_FFI_ERROR_BAD_FLAG; return ffi_guard_thunk(__func__, [=]() -> int { *op = nullptr; std::unique_ptr pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), Botan::system_rng(), padding)); *op = new botan_pk_op_encrypt_struct(pk.release()); return BOTAN_FFI_SUCCESS; }); } int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, size_t ptext_len, size_t* ctext_len) { if(ctext_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, { *ctext_len = o.ciphertext_length(ptext_len); }); } int botan_pk_op_encrypt(botan_pk_op_encrypt_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len, const uint8_t plaintext[], size_t plaintext_len) { return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, { return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj))); }); } /* * Public Key Decryption */ int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, botan_privkey_t key_obj, const char* padding, uint32_t flags) { if(op == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0) return BOTAN_FFI_ERROR_BAD_FLAG; return ffi_guard_thunk(__func__, [=]() -> int { *op = nullptr; std::unique_ptr pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), Botan::system_rng(), padding)); *op = new botan_pk_op_decrypt_struct(pk.release()); return BOTAN_FFI_SUCCESS; }); } int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, size_t ctext_len, size_t* ptext_len) { if(ptext_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, { *ptext_len = o.plaintext_length(ctext_len); }); } int botan_pk_op_decrypt(botan_pk_op_decrypt_t op, uint8_t out[], size_t* out_len, const uint8_t ciphertext[], size_t ciphertext_len) { return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, { return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len)); }); } /* * Signature Generation */ int botan_pk_op_sign_create(botan_pk_op_sign_t* op, botan_privkey_t key_obj, const char* hash, uint32_t flags) { if(op == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) return BOTAN_FFI_ERROR_BAD_FLAG; return ffi_guard_thunk(__func__, [=]() -> int { *op = nullptr; auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::DER_SEQUENCE : Botan::IEEE_1363; std::unique_ptr pk(new Botan::PK_Signer(safe_get(key_obj), Botan::system_rng(), hash, format)); *op = new botan_pk_op_sign_struct(pk.release()); return BOTAN_FFI_SUCCESS; }); } int botan_pk_op_sign_destroy(botan_pk_op_sign_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } int botan_pk_op_sign_output_length(botan_pk_op_sign_t op, size_t* sig_len) { if(sig_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { *sig_len = o.signature_length(); }); } int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len) { return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { o.update(in, in_len); }); } int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len) { return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { return write_vec_output(out, out_len, o.signature(safe_get(rng_obj))); }); } int botan_pk_op_verify_create(botan_pk_op_verify_t* op, botan_pubkey_t key_obj, const char* hash, uint32_t flags) { if(op == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) return BOTAN_FFI_ERROR_BAD_FLAG; return ffi_guard_thunk(__func__, [=]() -> int { *op = nullptr; auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::DER_SEQUENCE : Botan::IEEE_1363; std::unique_ptr pk(new Botan::PK_Verifier(safe_get(key_obj), hash, format)); *op = new botan_pk_op_verify_struct(pk.release()); return BOTAN_FFI_SUCCESS; }); } int botan_pk_op_verify_destroy(botan_pk_op_verify_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len) { return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, { o.update(in, in_len); }); } int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len) { return BOTAN_FFI_RETURNING(Botan::PK_Verifier, op, o, { const bool legit = o.check_signature(sig, sig_len); if(legit) return BOTAN_FFI_SUCCESS; else return BOTAN_FFI_INVALID_VERIFIER; }); } int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, botan_privkey_t key_obj, const char* kdf, uint32_t flags) { if(op == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(flags != 0) return BOTAN_FFI_ERROR_BAD_FLAG; return ffi_guard_thunk(__func__, [=]() -> int { *op = nullptr; std::unique_ptr pk(new Botan::PK_Key_Agreement(safe_get(key_obj), Botan::system_rng(), kdf)); *op = new botan_pk_op_ka_struct(pk.release()); return BOTAN_FFI_SUCCESS; }); } int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } int botan_pk_op_key_agreement_export_public(botan_privkey_t key, uint8_t out[], size_t* out_len) { return BOTAN_FFI_DO(Botan::Private_Key, key, k, { if(auto kak = dynamic_cast(&k)) return write_vec_output(out, out_len, kak->public_value()); return BOTAN_FFI_ERROR_BAD_FLAG; }); } int botan_pk_op_key_agreement_size(botan_pk_op_ka_t op, size_t* out_len) { return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, { if(out_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *out_len = o.agreed_value_size(); }); } int botan_pk_op_key_agreement(botan_pk_op_ka_t op, uint8_t out[], size_t* out_len, const uint8_t other_key[], size_t other_key_len, const uint8_t salt[], size_t salt_len) { return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, { auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of(); return write_vec_output(out, out_len, k); }); } } /* * (C) 2015,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_HASH_ID) #endif extern "C" { using namespace Botan_FFI; int botan_privkey_create(botan_privkey_t* key_obj, const char* algo_name, const char* algo_params, botan_rng_t rng_obj) { return ffi_guard_thunk(__func__, [=]() -> int { if(key_obj == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *key_obj = nullptr; if(rng_obj == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; Botan::RandomNumberGenerator& rng = safe_get(rng_obj); std::unique_ptr key( Botan::create_private_key(algo_name ? algo_name : "RSA", rng, algo_params ? algo_params : "")); if(key) { *key_obj = new botan_privkey_struct(key.release()); return BOTAN_FFI_SUCCESS; } else { return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; } }); } int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj, const uint8_t bits[], size_t len, const char* password) { BOTAN_UNUSED(rng_obj); *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::DataSource_Memory src(bits, len); std::unique_ptr pkcs8; if(password == nullptr) { pkcs8 = Botan::PKCS8::load_key(src); } else { pkcs8 = Botan::PKCS8::load_key(src, std::string(password)); } if(pkcs8) { *key = new botan_privkey_struct(pkcs8.release()); return BOTAN_FFI_SUCCESS; } return BOTAN_FFI_ERROR_UNKNOWN_ERROR; }); } int botan_privkey_destroy(botan_privkey_t key) { return BOTAN_FFI_CHECKED_DELETE(key); } int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t bits_len) { *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::DataSource_Memory src(bits, bits_len); std::unique_ptr pubkey(Botan::X509::load_key(src)); if(pubkey == nullptr) return BOTAN_FFI_ERROR_UNKNOWN_ERROR; *key = new botan_pubkey_struct(pubkey.release()); return BOTAN_FFI_SUCCESS; }); } int botan_pubkey_destroy(botan_pubkey_t key) { return BOTAN_FFI_CHECKED_DELETE(key); } int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) { return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr pubkey(Botan::X509::load_key(Botan::X509::BER_encode(safe_get(key_obj)))); *pubout = new botan_pubkey_struct(pubkey.release()); return BOTAN_FFI_SUCCESS; }); } int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len) { return BOTAN_FFI_DO(Botan::Private_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); }); } int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) { return BOTAN_FFI_DO(Botan::Public_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); }); } int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) { const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS); return BOTAN_FFI_RETURNING(Botan::Public_Key, key, k, { return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT; }); } int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) { const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS); return BOTAN_FFI_RETURNING(Botan::Private_Key, key, k, { return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT; }); } int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) { return BOTAN_FFI_DO(Botan::Public_Key, key, k, { if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) return write_vec_output(out, out_len, Botan::X509::BER_encode(k)); else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) return write_str_output(out, out_len, Botan::X509::PEM_encode(k)); else return BOTAN_FFI_ERROR_BAD_FLAG; }); } int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) { return BOTAN_FFI_DO(Botan::Private_Key, key, k, { if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) return write_vec_output(out, out_len, Botan::PKCS8::BER_encode(k)); else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) return write_str_output(out, out_len, Botan::PKCS8::PEM_encode(k)); else return BOTAN_FFI_ERROR_BAD_FLAG; }); } int botan_privkey_export_encrypted(botan_privkey_t key, uint8_t out[], size_t* out_len, botan_rng_t rng_obj, const char* pass, const char* /*ignored - pbe*/, uint32_t flags) { return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags); } int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key, uint8_t out[], size_t* out_len, botan_rng_t rng_obj, const char* pass, uint32_t pbkdf_msec, size_t* pbkdf_iters_out, const char* maybe_cipher, const char* maybe_pbkdf_hash, uint32_t flags) { return BOTAN_FFI_DO(Botan::Private_Key, key, k, { const std::chrono::milliseconds pbkdf_time(pbkdf_msec); Botan::RandomNumberGenerator& rng = safe_get(rng_obj); const std::string cipher = (maybe_cipher ? maybe_cipher : ""); const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : ""); if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) { return write_vec_output(out, out_len, Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash)); } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) { return write_str_output(out, out_len, Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash)); } else { return -2; } }); } int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key, uint8_t out[], size_t* out_len, botan_rng_t rng_obj, const char* pass, size_t pbkdf_iter, const char* maybe_cipher, const char* maybe_pbkdf_hash, uint32_t flags) { return BOTAN_FFI_DO(Botan::Private_Key, key, k, { Botan::RandomNumberGenerator& rng = safe_get(rng_obj); const std::string cipher = (maybe_cipher ? maybe_cipher : ""); const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : ""); if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) { return write_vec_output(out, out_len, Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash)); } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) { return write_str_output(out, out_len, Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash)); } else { return -2; } }); } int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) { return BOTAN_FFI_DO(Botan::Public_Key, key, k, { *estimate = k.estimated_strength(); }); } int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, uint8_t out[], size_t* out_len) { return BOTAN_FFI_DO(Botan::Public_Key, key, k, { std::unique_ptr h(Botan::HashFunction::create(hash_fn)); return write_vec_output(out, out_len, h->process(k.public_key_bits())); }); } int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) { #if defined(BOTAN_HAS_HASH_ID) return ffi_guard_thunk(__func__, [=]() -> int { const std::vector hash_id = Botan::pkcs_hash_id(hash_name); return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size()); }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * (C) 2015,2017 Jack Lloyd * (C) 2017 Ribose Inc * (C) 2018 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) #endif #if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY) #endif #if defined(BOTAN_HAS_RSA) #endif #if defined(BOTAN_HAS_ELGAMAL) #endif #if defined(BOTAN_HAS_DSA) #endif #if defined(BOTAN_HAS_ECDSA) #endif #if defined(BOTAN_HAS_SM2) #endif #if defined(BOTAN_HAS_ECDH) #endif #if defined(BOTAN_HAS_CURVE_25519) #endif #if defined(BOTAN_HAS_ED25519) #endif #if defined(BOTAN_HAS_MCELIECE) #endif #if defined(BOTAN_HAS_MCEIES) #endif #if defined(BOTAN_HAS_DIFFIE_HELLMAN) #endif namespace { #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) // These are always called within an existing try/catch block template int privkey_load_ec(std::unique_ptr& key, const Botan::BigInt& scalar, const char* curve_name) { if(curve_name == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; Botan::Null_RNG null_rng; Botan::EC_Group grp(curve_name); key.reset(new ECPrivateKey_t(null_rng, grp, scalar)); return BOTAN_FFI_SUCCESS; } template int pubkey_load_ec(std::unique_ptr& key, const Botan::BigInt& public_x, const Botan::BigInt& public_y, const char* curve_name) { if(curve_name == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; Botan::EC_Group grp(curve_name); Botan::PointGFp uncompressed_point = grp.point(public_x, public_y); key.reset(new ECPublicKey_t(grp, uncompressed_point)); return BOTAN_FFI_SUCCESS; } #endif Botan::BigInt pubkey_get_field(const Botan::Public_Key& key, const std::string& field) { // Maybe this should be `return key.get_integer_field(field_name)`? #if defined(BOTAN_HAS_RSA) if(const Botan::RSA_PublicKey* rsa = dynamic_cast(&key)) { if(field == "n") return rsa->get_n(); else if(field == "e") return rsa->get_e(); else throw Botan_FFI::FFI_Error("Bad field", BOTAN_FFI_ERROR_BAD_PARAMETER); } #endif #if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY) // Handles DSA, ElGamal, etc if(const Botan::DL_Scheme_PublicKey* dl = dynamic_cast(&key)) { if(field == "p") return dl->group_p(); else if(field == "q") return dl->group_q(); else if(field == "g") return dl->group_g(); else if(field == "y") return dl->get_y(); else throw Botan_FFI::FFI_Error("Bad field", BOTAN_FFI_ERROR_BAD_PARAMETER); } #endif #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) if(const Botan::EC_PublicKey* ecc = dynamic_cast(&key)) { if(field == "public_x") return ecc->public_point().get_affine_x(); else if(field == "public_y") return ecc->public_point().get_affine_y(); else if(field == "base_x") return ecc->domain().get_g_x(); else if(field == "base_y") return ecc->domain().get_g_y(); else if(field == "p") return ecc->domain().get_p(); else if(field == "a") return ecc->domain().get_a(); else if(field == "b") return ecc->domain().get_b(); else if(field == "cofactor") return ecc->domain().get_cofactor(); else if(field == "order") return ecc->domain().get_order(); else throw Botan_FFI::FFI_Error("Bad field", BOTAN_FFI_ERROR_BAD_PARAMETER); } #endif // Some other algorithm type not supported by this function throw Botan_FFI::FFI_Error("Field getter not implemented for this algorithm type", BOTAN_FFI_ERROR_NOT_IMPLEMENTED); } Botan::BigInt privkey_get_field(const Botan::Private_Key& key, const std::string& field) { //return key.get_integer_field(field); #if defined(BOTAN_HAS_RSA) if(const Botan::RSA_PrivateKey* rsa = dynamic_cast(&key)) { if(field == "p") return rsa->get_p(); else if(field == "q") return rsa->get_q(); else if(field == "d") return rsa->get_d(); else if(field == "c") return rsa->get_c(); else if(field == "d1") return rsa->get_d1(); else if(field == "d2") return rsa->get_d2(); else return pubkey_get_field(key, field); } #endif #if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY) // Handles DSA, ElGamal, etc if(const Botan::DL_Scheme_PrivateKey* dl = dynamic_cast(&key)) { if(field == "x") return dl->get_x(); else return pubkey_get_field(key, field); } #endif #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) if(const Botan::EC_PrivateKey* ecc = dynamic_cast(&key)) { if(field == "x") return ecc->private_value(); else return pubkey_get_field(key, field); } #endif return pubkey_get_field(key, field); } } extern "C" { using namespace Botan_FFI; int botan_pubkey_get_field(botan_mp_t output, botan_pubkey_t key, const char* field_name_cstr) { if(field_name_cstr == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; const std::string field_name(field_name_cstr); return BOTAN_FFI_DO(Botan::Public_Key, key, k, { safe_get(output) = pubkey_get_field(k, field_name); }); } int botan_privkey_get_field(botan_mp_t output, botan_privkey_t key, const char* field_name_cstr) { if(field_name_cstr == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; const std::string field_name(field_name_cstr); return BOTAN_FFI_DO(Botan::Private_Key, key, k, { safe_get(output) = privkey_get_field(k, field_name); }); } /* RSA specific operations */ int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits) { if(n_bits < 1024 || n_bits > 16*1024) return BOTAN_FFI_ERROR_BAD_PARAMETER; std::string n_str = std::to_string(n_bits); return botan_privkey_create(key_obj, "RSA", n_str.c_str(), rng_obj); } int botan_privkey_load_rsa(botan_privkey_t* key, botan_mp_t rsa_p, botan_mp_t rsa_q, botan_mp_t rsa_e) { #if defined(BOTAN_HAS_RSA) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { *key = new botan_privkey_struct(new Botan::RSA_PrivateKey(safe_get(rsa_p), safe_get(rsa_q), safe_get(rsa_e))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, rsa_p, rsa_q, rsa_e); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_load_rsa_pkcs1(botan_privkey_t* key, const uint8_t bits[], size_t len) { #if defined(BOTAN_HAS_RSA) *key = nullptr; Botan::secure_vector src(bits, bits + len); return ffi_guard_thunk(__func__, [=]() -> int { Botan::AlgorithmIdentifier alg_id("RSA", Botan::AlgorithmIdentifier::USE_NULL_PARAM); *key = new botan_privkey_struct(new Botan::RSA_PrivateKey(alg_id, src)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, bits, len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_rsa(botan_pubkey_t* key, botan_mp_t n, botan_mp_t e) { #if defined(BOTAN_HAS_RSA) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { *key = new botan_pubkey_struct(new Botan::RSA_PublicKey(safe_get(n), safe_get(e))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, n, e); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t key) { return botan_privkey_get_field(p, key, "p"); } int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t key) { return botan_privkey_get_field(q, key, "q"); } int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t key) { return botan_privkey_get_field(n, key, "n"); } int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t key) { return botan_privkey_get_field(e, key, "e"); } int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t key) { return botan_privkey_get_field(d, key, "d"); } int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t key) { return botan_pubkey_get_field(e, key, "e"); } int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t key) { return botan_pubkey_get_field(n, key, "n"); } int botan_privkey_rsa_get_privkey(botan_privkey_t rsa_key, uint8_t out[], size_t* out_len, uint32_t flags) { #if defined(BOTAN_HAS_RSA) return BOTAN_FFI_DO(Botan::Private_Key, rsa_key, k, { if(const Botan::RSA_PrivateKey* rsa = dynamic_cast(&k)) { if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) return write_vec_output(out, out_len, rsa->private_key_bits()); else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) return write_str_output(out, out_len, Botan::PEM_Code::encode(rsa->private_key_bits(), "RSA PRIVATE KEY")); else return BOTAN_FFI_ERROR_BAD_FLAG; } else { return BOTAN_FFI_ERROR_BAD_PARAMETER; } }); #else BOTAN_UNUSED(rsa_key, out, out_len); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } /* DSA specific operations */ int botan_privkey_create_dsa(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) { #if defined(BOTAN_HAS_DSA) if ((rng_obj == nullptr) || (key == nullptr)) return BOTAN_FFI_ERROR_NULL_POINTER; if ((pbits % 64) || (qbits % 8) || (pbits < 1024) || (pbits > 3072) || (qbits < 160) || (qbits > 256)) { return BOTAN_FFI_ERROR_BAD_PARAMETER; } return ffi_guard_thunk(__func__, [=]() -> int { Botan::RandomNumberGenerator& rng = safe_get(rng_obj); Botan::DL_Group group(rng, Botan::DL_Group::Prime_Subgroup, pbits, qbits); *key = new botan_privkey_struct(new Botan::DSA_PrivateKey(rng, group)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, rng_obj, pbits, qbits); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_load_dsa(botan_privkey_t* key, botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x) { #if defined(BOTAN_HAS_DSA) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::Null_RNG null_rng; Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g)); *key = new botan_privkey_struct(new Botan::DSA_PrivateKey(null_rng, group, safe_get(x))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, p, q, g, x); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_dsa(botan_pubkey_t* key, botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y) { #if defined(BOTAN_HAS_DSA) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g)); *key = new botan_pubkey_struct(new Botan::DSA_PublicKey(group, safe_get(y))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, p, q, g, y); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_dsa_get_x(botan_mp_t x, botan_privkey_t key) { return botan_privkey_get_field(x, key, "x"); } int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key) { return botan_pubkey_get_field(p, key, "p"); } int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key) { return botan_pubkey_get_field(q, key, "q"); } int botan_pubkey_dsa_get_g(botan_mp_t g, botan_pubkey_t key) { return botan_pubkey_get_field(g, key, "g"); } int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key) { return botan_pubkey_get_field(y, key, "y"); } int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) { return botan_privkey_create(key_obj, "ECDSA", param_str, rng_obj); } /* ECDSA specific operations */ int botan_pubkey_load_ecdsa(botan_pubkey_t* key, const botan_mp_t public_x, const botan_mp_t public_y, const char* curve_name) { #if defined(BOTAN_HAS_ECDSA) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr p_key; int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name); if(rc == BOTAN_FFI_SUCCESS) *key = new botan_pubkey_struct(p_key.release()); return rc; }); #else BOTAN_UNUSED(key, public_x, public_y, curve_name); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_load_ecdsa(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) { #if defined(BOTAN_HAS_ECDSA) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr p_key; int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name); if(rc == BOTAN_FFI_SUCCESS) *key = new botan_privkey_struct(p_key.release()); return rc; }); #else BOTAN_UNUSED(key, scalar, curve_name); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } /* ElGamal specific operations */ int botan_privkey_create_elgamal(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) { #if defined(BOTAN_HAS_ELGAMAL) if ((rng_obj == nullptr) || (key == nullptr)) return BOTAN_FFI_ERROR_NULL_POINTER; if ((pbits < 1024) || (qbits<160)) { return BOTAN_FFI_ERROR_BAD_PARAMETER; } Botan::DL_Group::PrimeType prime_type = ((pbits-1) == qbits) ? Botan::DL_Group::Strong : Botan::DL_Group::Prime_Subgroup; return ffi_guard_thunk(__func__, [=]() -> int { Botan::RandomNumberGenerator& rng = safe_get(rng_obj); Botan::DL_Group group(rng, prime_type, pbits, qbits); *key = new botan_privkey_struct(new Botan::ElGamal_PrivateKey(rng, group)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, rng_obj, pbits); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_elgamal(botan_pubkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t y) { #if defined(BOTAN_HAS_ELGAMAL) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::DL_Group group(safe_get(p), safe_get(g)); *key = new botan_pubkey_struct(new Botan::ElGamal_PublicKey(group, safe_get(y))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, p, g, y); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_load_elgamal(botan_privkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t x) { #if defined(BOTAN_HAS_ELGAMAL) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::Null_RNG null_rng; Botan::DL_Group group(safe_get(p), safe_get(g)); *key = new botan_privkey_struct(new Botan::ElGamal_PrivateKey(null_rng, group, safe_get(x))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, p, g, x); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } /* Diffie Hellman specific operations */ int botan_privkey_create_dh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) { return botan_privkey_create(key_obj, "DH", param_str, rng_obj); } int botan_privkey_load_dh(botan_privkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t x) { #if defined(BOTAN_HAS_DIFFIE_HELLMAN) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::Null_RNG null_rng; Botan::DL_Group group(safe_get(p), safe_get(g)); *key = new botan_privkey_struct(new Botan::DH_PrivateKey(null_rng, group, safe_get(x))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, p, g, x); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_dh(botan_pubkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t y) { #if defined(BOTAN_HAS_DIFFIE_HELLMAN) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { Botan::DL_Group group(safe_get(p), safe_get(g)); *key = new botan_pubkey_struct(new Botan::DH_PublicKey(group, safe_get(y))); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, p, g, y); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } /* ECDH + x25519 specific operations */ int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) { if(param_str == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; const std::string params(param_str); if(params == "curve25519") return botan_privkey_create(key_obj, "Curve25519", "", rng_obj); return botan_privkey_create(key_obj, "ECDH", param_str, rng_obj); } int botan_pubkey_load_ecdh(botan_pubkey_t* key, const botan_mp_t public_x, const botan_mp_t public_y, const char* curve_name) { #if defined(BOTAN_HAS_ECDH) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr p_key; int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name); if(rc == BOTAN_FFI_SUCCESS) *key = new botan_pubkey_struct(p_key.release()); return rc; }); #else BOTAN_UNUSED(key, public_x, public_y, curve_name); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_load_ecdh(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) { #if defined(BOTAN_HAS_ECDH) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr p_key; int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name); if(rc == BOTAN_FFI_SUCCESS) *key = new botan_privkey_struct(p_key.release()); return rc; }); #else BOTAN_UNUSED(key, scalar, curve_name); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } /* SM2 specific operations */ int botan_pubkey_sm2_compute_za(uint8_t out[], size_t* out_len, const char* ident, const char* hash_algo, const botan_pubkey_t key) { if(out == nullptr || out_len == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(ident == nullptr || hash_algo == nullptr || key == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; #if defined(BOTAN_HAS_SM2) return ffi_guard_thunk(__func__, [=]() -> int { const Botan::Public_Key& pub_key = safe_get(key); const Botan::EC_PublicKey* ec_key = dynamic_cast(&pub_key); if(ec_key == nullptr) return BOTAN_FFI_ERROR_BAD_PARAMETER; if(ec_key->algo_name() != "SM2") return BOTAN_FFI_ERROR_BAD_PARAMETER; const std::string ident_str(ident); std::unique_ptr hash = Botan::HashFunction::create_or_throw(hash_algo); const std::vector za = Botan::sm2_compute_za(*hash, ident_str, ec_key->domain(), ec_key->public_point()); return write_vec_output(out, out_len, za); }); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_sm2(botan_pubkey_t* key, const botan_mp_t public_x, const botan_mp_t public_y, const char* curve_name) { #if defined(BOTAN_HAS_SM2) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr p_key; if(!pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name)) { *key = new botan_pubkey_struct(p_key.release()); return BOTAN_FFI_SUCCESS; } return BOTAN_FFI_ERROR_UNKNOWN_ERROR; }); #else BOTAN_UNUSED(key, public_x, public_y, curve_name); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_load_sm2(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) { #if defined(BOTAN_HAS_SM2) return ffi_guard_thunk(__func__, [=]() -> int { std::unique_ptr p_key; int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name); if(rc == BOTAN_FFI_SUCCESS) *key = new botan_privkey_struct(p_key.release()); return rc; }); #else BOTAN_UNUSED(key, scalar, curve_name); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_sm2_enc(botan_pubkey_t* key, const botan_mp_t public_x, const botan_mp_t public_y, const char* curve_name) { return botan_pubkey_load_sm2(key, public_x, public_y, curve_name); } int botan_privkey_load_sm2_enc(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) { return botan_privkey_load_sm2(key, scalar, curve_name); } /* Ed25519 specific operations */ int botan_privkey_load_ed25519(botan_privkey_t* key, const uint8_t privkey[32]) { #if defined(BOTAN_HAS_ED25519) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { const Botan::secure_vector privkey_vec(privkey, privkey + 32); *key = new botan_privkey_struct(new Botan::Ed25519_PrivateKey(privkey_vec)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, privkey); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_ed25519(botan_pubkey_t* key, const uint8_t pubkey[32]) { #if defined(BOTAN_HAS_ED25519) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { const std::vector pubkey_vec(pubkey, pubkey + 32); *key = new botan_pubkey_struct(new Botan::Ed25519_PublicKey(pubkey_vec)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, pubkey); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_ed25519_get_privkey(botan_privkey_t key, uint8_t output[64]) { #if defined(BOTAN_HAS_ED25519) return BOTAN_FFI_DO(Botan::Private_Key, key, k, { if(Botan::Ed25519_PrivateKey* ed = dynamic_cast(&k)) { const Botan::secure_vector& ed_key = ed->get_private_key(); if(ed_key.size() != 64) return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; Botan::copy_mem(output, ed_key.data(), ed_key.size()); return BOTAN_FFI_SUCCESS; } else { return BOTAN_FFI_ERROR_BAD_PARAMETER; } }); #else BOTAN_UNUSED(key, output); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key, uint8_t output[32]) { #if defined(BOTAN_HAS_ED25519) return BOTAN_FFI_DO(Botan::Public_Key, key, k, { if(Botan::Ed25519_PublicKey* ed = dynamic_cast(&k)) { const std::vector& ed_key = ed->get_public_key(); if(ed_key.size() != 32) return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; Botan::copy_mem(output, ed_key.data(), ed_key.size()); return BOTAN_FFI_SUCCESS; } else { return BOTAN_FFI_ERROR_BAD_PARAMETER; } }); #else BOTAN_UNUSED(key, output); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } /* X25519 specific operations */ int botan_privkey_load_x25519(botan_privkey_t* key, const uint8_t privkey[32]) { #if defined(BOTAN_HAS_X25519) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { const Botan::secure_vector privkey_vec(privkey, privkey + 32); *key = new botan_privkey_struct(new Botan::X25519_PrivateKey(privkey_vec)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, privkey); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_load_x25519(botan_pubkey_t* key, const uint8_t pubkey[32]) { #if defined(BOTAN_HAS_X25519) *key = nullptr; return ffi_guard_thunk(__func__, [=]() -> int { const std::vector pubkey_vec(pubkey, pubkey + 32); *key = new botan_pubkey_struct(new Botan::X25519_PublicKey(pubkey_vec)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(key, pubkey); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_x25519_get_privkey(botan_privkey_t key, uint8_t output[32]) { #if defined(BOTAN_HAS_X25519) return BOTAN_FFI_DO(Botan::Private_Key, key, k, { if(Botan::X25519_PrivateKey* x25519 = dynamic_cast(&k)) { const Botan::secure_vector& x25519_key = x25519->get_x(); if(x25519_key.size() != 32) return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; Botan::copy_mem(output, x25519_key.data(), x25519_key.size()); return BOTAN_FFI_SUCCESS; } else { return BOTAN_FFI_ERROR_BAD_PARAMETER; } }); #else BOTAN_UNUSED(key, output); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_pubkey_x25519_get_pubkey(botan_pubkey_t key, uint8_t output[32]) { #if defined(BOTAN_HAS_X25519) return BOTAN_FFI_DO(Botan::Public_Key, key, k, { if(Botan::X25519_PublicKey* x25519 = dynamic_cast(&k)) { const std::vector& x25519_key = x25519->public_value(); if(x25519_key.size() != 32) return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; Botan::copy_mem(output, x25519_key.data(), x25519_key.size()); return BOTAN_FFI_SUCCESS; } else { return BOTAN_FFI_ERROR_BAD_PARAMETER; } }); #else BOTAN_UNUSED(key, output); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_privkey_create_mceliece(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n, size_t t) { const std::string mce_params = std::to_string(n) + "," + std::to_string(t); return botan_privkey_create(key_obj, "McEliece", mce_params.c_str(), rng_obj); } int botan_mceies_decrypt(botan_privkey_t mce_key_obj, const char* aead, const uint8_t ct[], size_t ct_len, const uint8_t ad[], size_t ad_len, uint8_t out[], size_t* out_len) { return ffi_guard_thunk(__func__, [=]() -> int { Botan::Private_Key& key = safe_get(mce_key_obj); #if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES) Botan::McEliece_PrivateKey* mce = dynamic_cast(&key); if(!mce) return BOTAN_FFI_ERROR_BAD_PARAMETER; const Botan::secure_vector pt = mceies_decrypt(*mce, ct, ct_len, ad, ad_len, aead); return write_vec_output(out, out_len, pt); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif }); } int botan_mceies_encrypt(botan_pubkey_t mce_key_obj, botan_rng_t rng_obj, const char* aead, const uint8_t pt[], size_t pt_len, const uint8_t ad[], size_t ad_len, uint8_t out[], size_t* out_len) { return ffi_guard_thunk(__func__, [=]() -> int { Botan::Public_Key& key = safe_get(mce_key_obj); Botan::RandomNumberGenerator& rng = safe_get(rng_obj); #if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES) Botan::McEliece_PublicKey* mce = dynamic_cast(&key); if(!mce) return BOTAN_FFI_ERROR_BAD_PARAMETER; Botan::secure_vector ct = mceies_encrypt(*mce, pt, pt_len, ad, ad_len, rng, aead); return write_vec_output(out, out_len, ct); #else return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif }); } } /* * (C) 2015,2017 Jack Lloyd * (C) 2021 René Fischer * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_HAS_PROCESSOR_RNG) #endif extern "C" { using namespace Botan_FFI; int botan_rng_init(botan_rng_t* rng_out, const char* rng_type) { return ffi_guard_thunk(__func__, [=]() -> int { if(rng_out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; const std::string rng_type_s(rng_type ? rng_type : "system"); std::unique_ptr rng; if(rng_type_s == "system") { rng.reset(new Botan::System_RNG); } else if(rng_type_s == "user" || rng_type_s == "user-threadsafe") { rng.reset(new Botan::AutoSeeded_RNG); } else if(rng_type_s == "null") { rng.reset(new Botan::Null_RNG); } #if defined(BOTAN_HAS_PROCESSOR_RNG) else if((rng_type_s == "rdrand" || rng_type_s == "hwrng") && Botan::Processor_RNG::available()) { rng.reset(new Botan::Processor_RNG); } #endif if(!rng) { return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; } *rng_out = new botan_rng_struct(rng.release()); return BOTAN_FFI_SUCCESS; }); } int botan_rng_init_custom(botan_rng_t* rng_out, const char* rng_name, void* context, int(* get_cb)(void* context, uint8_t* out, size_t out_len), int(* add_entropy_cb)(void* context, const uint8_t input[], size_t length), void(* destroy_cb)(void* context)) { return ffi_guard_thunk(__func__,[=]() -> int { if(rng_out == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(rng_name == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; if(get_cb == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; class Custom_RNG : public Botan::RandomNumberGenerator { public: Custom_RNG(const std::string& name, void* context, int(* get_cb)(void* context, uint8_t* out, size_t out_len), int(* add_entropy_cb)(void* context, const uint8_t input[], size_t length), void(* destroy_cb)(void* context)) : m_name(name) { m_context = context; m_get_cb = get_cb; m_add_entropy_cb = add_entropy_cb; m_destroy_cb = destroy_cb; } ~Custom_RNG() { if(m_destroy_cb) { m_destroy_cb(m_context); } } void randomize(uint8_t output[], size_t length) override { int rc = m_get_cb(m_context, output, length); if(rc) { throw Botan::Invalid_State("Failed to get random from C callback, rc=" + std::to_string(rc)); } } bool accepts_input() const override { return m_add_entropy_cb != nullptr; } void add_entropy(const uint8_t input[], size_t length) override { if(m_add_entropy_cb == nullptr) { return; } int rc = m_add_entropy_cb(m_context, input, length); if(rc) { throw Botan::Invalid_State("Failed to add entropy via C callback, rc=" + std::to_string(rc)); } } std::string name() const override { return m_name; } void clear() override { } bool is_seeded() const override { return true; } private: std::string m_name; void* m_context; std::function m_get_cb; std::function m_add_entropy_cb; std::function m_destroy_cb; }; std::unique_ptr rng(new Custom_RNG(rng_name, context, get_cb, add_entropy_cb, destroy_cb)); *rng_out = new botan_rng_struct(rng.release()); return BOTAN_FFI_SUCCESS; }); } int botan_rng_destroy(botan_rng_t rng) { return BOTAN_FFI_CHECKED_DELETE(rng); } int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len) { return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.randomize(out, out_len); }); } int botan_rng_reseed(botan_rng_t rng, size_t bits) { return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(Botan::system_rng(), bits); }); } int botan_rng_add_entropy(botan_rng_t rng, const uint8_t* input, size_t len) { return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.add_entropy(input, len); }); } int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t source_rng, size_t bits) { return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(safe_get(source_rng), bits); }); } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_TOTP) #endif extern "C" { using namespace Botan_FFI; #if defined(BOTAN_HAS_TOTP) BOTAN_FFI_DECLARE_STRUCT(botan_totp_struct, Botan::TOTP, 0x3D9D2CD1); #endif int botan_totp_init(botan_totp_t* totp, const uint8_t key[], size_t key_len, const char* hash_algo, size_t digits, size_t time_step) { if(totp == nullptr || key == nullptr || hash_algo == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; *totp = nullptr; #if defined(BOTAN_HAS_TOTP) return ffi_guard_thunk(__func__, [=]() -> int { *totp = new botan_totp_struct( new Botan::TOTP(key, key_len, hash_algo, digits, time_step)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(totp, key, key_len, hash_algo, digits, time_step); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_totp_destroy(botan_totp_t totp) { #if defined(BOTAN_HAS_TOTP) return BOTAN_FFI_CHECKED_DELETE(totp); #else BOTAN_UNUSED(totp); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_totp_generate(botan_totp_t totp, uint32_t* totp_code, uint64_t timestamp) { #if defined(BOTAN_HAS_TOTP) if(totp == nullptr || totp_code == nullptr) return BOTAN_FFI_ERROR_NULL_POINTER; return BOTAN_FFI_DO(Botan::TOTP, totp, t, { *totp_code = t.generate_totp(timestamp); }); #else BOTAN_UNUSED(totp, totp_code, timestamp); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } int botan_totp_check(botan_totp_t totp, uint32_t totp_code, uint64_t timestamp, size_t acceptable_clock_drift) { #if defined(BOTAN_HAS_TOTP) return BOTAN_FFI_RETURNING(Botan::TOTP, totp, t, { const bool ok = t.verify_totp(totp_code, timestamp, acceptable_clock_drift); return (ok ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER); }); #else BOTAN_UNUSED(totp, totp_code, timestamp, acceptable_clock_drift); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } } /* * Filters * (C) 1999-2007,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { #if defined(BOTAN_HAS_STREAM_CIPHER) StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher) : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE), m_cipher(cipher) { } StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key) : StreamCipher_Filter(cipher) { m_cipher->set_key(key); } StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE), m_cipher(StreamCipher::create_or_throw(sc_name)) { } StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, const SymmetricKey& key) : StreamCipher_Filter(sc_name) { m_cipher->set_key(key); } void StreamCipher_Filter::write(const uint8_t input[], size_t length) { while(length) { size_t copied = std::min(length, m_buffer.size()); m_cipher->cipher(input, m_buffer.data(), copied); send(m_buffer, copied); input += copied; length -= copied; } } #endif #if defined(BOTAN_HAS_HASH) Hash_Filter::Hash_Filter(const std::string& hash_name, size_t len) : m_hash(HashFunction::create_or_throw(hash_name)), m_out_len(len) { } void Hash_Filter::end_msg() { secure_vector output = m_hash->final(); if(m_out_len) send(output, std::min(m_out_len, output.size())); else send(output); } #endif #if defined(BOTAN_HAS_MAC) MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) : m_mac(MessageAuthenticationCode::create_or_throw(mac_name)), m_out_len(len) { } MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, size_t len) : MAC_Filter(mac_name, len) { m_mac->set_key(key); } void MAC_Filter::end_msg() { secure_vector output = m_mac->final(); if(m_out_len) send(output, std::min(m_out_len, output.size())); else send(output); } #endif } /* * Base64 Encoder/Decoder * (C) 1999-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Base64_Encoder Constructor */ Base64_Encoder::Base64_Encoder(bool breaks, size_t length, bool t_n) : m_line_length(breaks ? length : 0), m_trailing_newline(t_n && breaks), m_in(48), m_out(64), m_position(0), m_out_position(0) { } /* * Encode and send a block */ void Base64_Encoder::encode_and_send(const uint8_t input[], size_t length, bool final_inputs) { while(length) { const size_t proc = std::min(length, m_in.size()); size_t consumed = 0; size_t produced = base64_encode(cast_uint8_ptr_to_char(m_out.data()), input, proc, consumed, final_inputs); do_output(m_out.data(), produced); // FIXME: s/proc/consumed/? input += proc; length -= proc; } } /* * Handle the output */ void Base64_Encoder::do_output(const uint8_t input[], size_t length) { if(m_line_length == 0) send(input, length); else { size_t remaining = length, offset = 0; while(remaining) { size_t sent = std::min(m_line_length - m_out_position, remaining); send(input + offset, sent); m_out_position += sent; remaining -= sent; offset += sent; if(m_out_position == m_line_length) { send('\n'); m_out_position = 0; } } } } /* * Convert some data into Base64 */ void Base64_Encoder::write(const uint8_t input[], size_t length) { buffer_insert(m_in, m_position, input, length); if(m_position + length >= m_in.size()) { encode_and_send(m_in.data(), m_in.size()); input += (m_in.size() - m_position); length -= (m_in.size() - m_position); while(length >= m_in.size()) { encode_and_send(input, m_in.size()); input += m_in.size(); length -= m_in.size(); } copy_mem(m_in.data(), input, length); m_position = 0; } m_position += length; } /* * Flush buffers */ void Base64_Encoder::end_msg() { encode_and_send(m_in.data(), m_position, true); if(m_trailing_newline || (m_out_position && m_line_length)) send('\n'); m_out_position = m_position = 0; } /* * Base64_Decoder Constructor */ Base64_Decoder::Base64_Decoder(Decoder_Checking c) : m_checking(c), m_in(64), m_out(48), m_position(0) { } /* * Convert some data from Base64 */ void Base64_Decoder::write(const uint8_t input[], size_t length) { while(length) { size_t to_copy = std::min(length, m_in.size() - m_position); if(to_copy == 0) { m_in.resize(m_in.size()*2); m_out.resize(m_out.size()*2); } copy_mem(&m_in[m_position], input, to_copy); m_position += to_copy; size_t consumed = 0; size_t written = base64_decode(m_out.data(), cast_uint8_ptr_to_char(m_in.data()), m_position, consumed, false, m_checking != FULL_CHECK); send(m_out, written); if(consumed != m_position) { copy_mem(m_in.data(), m_in.data() + consumed, m_position - consumed); m_position = m_position - consumed; } else m_position = 0; length -= to_copy; input += to_copy; } } /* * Flush buffers */ void Base64_Decoder::end_msg() { size_t consumed = 0; size_t written = base64_decode(m_out.data(), cast_uint8_ptr_to_char(m_in.data()), m_position, consumed, true, m_checking != FULL_CHECK); send(m_out, written); const bool not_full_bytes = consumed != m_position; m_position = 0; if(not_full_bytes) throw Invalid_Argument("Base64_Decoder: Input not full bytes"); } } /* * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Chain Constructor */ Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) { if(f1) { attach(f1); incr_owns(); } if(f2) { attach(f2); incr_owns(); } if(f3) { attach(f3); incr_owns(); } if(f4) { attach(f4); incr_owns(); } } /* * Chain Constructor */ Chain::Chain(Filter* filters[], size_t count) { for(size_t j = 0; j != count; ++j) if(filters[j]) { attach(filters[j]); incr_owns(); } } /* * Fork Constructor */ Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) { Filter* filters[4] = { f1, f2, f3, f4 }; set_next(filters, 4); } /* * Fork Constructor */ Fork::Fork(Filter* filters[], size_t count) { set_next(filters, count); } } /* * Buffered Filter * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Buffered_Filter Constructor */ Buffered_Filter::Buffered_Filter(size_t b, size_t f) : m_main_block_mod(b), m_final_minimum(f) { if(m_main_block_mod == 0) throw Invalid_Argument("m_main_block_mod == 0"); if(m_final_minimum > m_main_block_mod) throw Invalid_Argument("m_final_minimum > m_main_block_mod"); m_buffer.resize(2 * m_main_block_mod); m_buffer_pos = 0; } /* * Buffer input into blocks, trying to minimize copying */ void Buffered_Filter::write(const uint8_t input[], size_t input_size) { if(!input_size) return; if(m_buffer_pos + input_size >= m_main_block_mod + m_final_minimum) { size_t to_copy = std::min(m_buffer.size() - m_buffer_pos, input_size); copy_mem(&m_buffer[m_buffer_pos], input, to_copy); m_buffer_pos += to_copy; input += to_copy; input_size -= to_copy; size_t total_to_consume = round_down(std::min(m_buffer_pos, m_buffer_pos + input_size - m_final_minimum), m_main_block_mod); buffered_block(m_buffer.data(), total_to_consume); m_buffer_pos -= total_to_consume; copy_mem(m_buffer.data(), m_buffer.data() + total_to_consume, m_buffer_pos); } if(input_size >= m_final_minimum) { size_t full_blocks = (input_size - m_final_minimum) / m_main_block_mod; size_t to_copy = full_blocks * m_main_block_mod; if(to_copy) { buffered_block(input, to_copy); input += to_copy; input_size -= to_copy; } } copy_mem(&m_buffer[m_buffer_pos], input, input_size); m_buffer_pos += input_size; } /* * Finish/flush operation */ void Buffered_Filter::end_msg() { if(m_buffer_pos < m_final_minimum) throw Invalid_State("Buffered filter end_msg without enough input"); size_t spare_blocks = (m_buffer_pos - m_final_minimum) / m_main_block_mod; if(spare_blocks) { size_t spare_bytes = m_main_block_mod * spare_blocks; buffered_block(m_buffer.data(), spare_bytes); buffered_final(&m_buffer[spare_bytes], m_buffer_pos - spare_bytes); } else { buffered_final(m_buffer.data(), m_buffer_pos); } m_buffer_pos = 0; } } /* * Filter interface for Cipher_Modes * (C) 2013,2014,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { size_t choose_update_size(size_t update_granularity) { const size_t target_size = 1024; if(update_granularity >= target_size) return update_granularity; return round_up(target_size, update_granularity); } } Cipher_Mode_Filter::Cipher_Mode_Filter(Cipher_Mode* mode) : Buffered_Filter(choose_update_size(mode->update_granularity()), mode->minimum_final_size()), m_mode(mode), m_nonce(mode->default_nonce_length()), m_buffer(m_mode->update_granularity()) { } std::string Cipher_Mode_Filter::name() const { return m_mode->name(); } void Cipher_Mode_Filter::set_iv(const InitializationVector& iv) { m_nonce = unlock(iv.bits_of()); } void Cipher_Mode_Filter::set_key(const SymmetricKey& key) { m_mode->set_key(key); } Key_Length_Specification Cipher_Mode_Filter::key_spec() const { return m_mode->key_spec(); } bool Cipher_Mode_Filter::valid_iv_length(size_t length) const { return m_mode->valid_nonce_length(length); } void Cipher_Mode_Filter::write(const uint8_t input[], size_t input_length) { Buffered_Filter::write(input, input_length); } void Cipher_Mode_Filter::end_msg() { Buffered_Filter::end_msg(); } void Cipher_Mode_Filter::start_msg() { if(m_nonce.empty() && !m_mode->valid_nonce_length(0)) throw Invalid_State("Cipher " + m_mode->name() + " requires a fresh nonce for each message"); m_mode->start(m_nonce); m_nonce.clear(); } void Cipher_Mode_Filter::buffered_block(const uint8_t input[], size_t input_length) { while(input_length) { const size_t take = std::min(m_mode->update_granularity(), input_length); m_buffer.assign(input, input + take); m_mode->update(m_buffer); send(m_buffer); input += take; input_length -= take; } } void Cipher_Mode_Filter::buffered_final(const uint8_t input[], size_t input_length) { secure_vector buf(input, input + input_length); m_mode->finish(buf); send(buf); } } /* * Filter interface for compression * (C) 2014,2015,2016 Jack Lloyd * (C) 2015 Matej Kenda * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_COMPRESSION) #endif namespace Botan { #if defined(BOTAN_HAS_COMPRESSION) Compression_Filter::Compression_Filter(const std::string& type, size_t level, size_t bs) : m_comp(make_compressor(type)), m_buffersize(std::max(bs, 256)), m_level(level) { if(!m_comp) { throw Invalid_Argument("Compression type '" + type + "' not found"); } } Compression_Filter::~Compression_Filter() { /* for unique_ptr */ } std::string Compression_Filter::name() const { return m_comp->name(); } void Compression_Filter::start_msg() { m_comp->start(m_level); } void Compression_Filter::write(const uint8_t input[], size_t input_length) { while(input_length) { const size_t take = std::min(m_buffersize, input_length); BOTAN_ASSERT(take > 0, "Consumed something"); m_buffer.assign(input, input + take); m_comp->update(m_buffer); send(m_buffer); input += take; input_length -= take; } } void Compression_Filter::flush() { m_buffer.clear(); m_comp->update(m_buffer, 0, true); send(m_buffer); } void Compression_Filter::end_msg() { m_buffer.clear(); m_comp->finish(m_buffer); send(m_buffer); } Decompression_Filter::Decompression_Filter(const std::string& type, size_t bs) : m_comp(make_decompressor(type)), m_buffersize(std::max(bs, 256)) { if(!m_comp) { throw Invalid_Argument("Compression type '" + type + "' not found"); } } Decompression_Filter::~Decompression_Filter() { /* for unique_ptr */ } std::string Decompression_Filter::name() const { return m_comp->name(); } void Decompression_Filter::start_msg() { m_comp->start(); } void Decompression_Filter::write(const uint8_t input[], size_t input_length) { while(input_length) { const size_t take = std::min(m_buffersize, input_length); BOTAN_ASSERT(take > 0, "Consumed something"); m_buffer.assign(input, input + take); m_comp->update(m_buffer); send(m_buffer); input += take; input_length -= take; } } void Decompression_Filter::end_msg() { m_buffer.clear(); m_comp->finish(m_buffer); send(m_buffer); } #endif } /* * DataSink * (C) 1999-2007 Jack Lloyd * 2005 Matthew Gregan * 2017 Philippe Lieser * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) #include #endif namespace Botan { /* * Write to a stream */ void DataSink_Stream::write(const uint8_t out[], size_t length) { m_sink.write(cast_uint8_ptr_to_char(out), length); if(!m_sink.good()) throw Stream_IO_Error("DataSink_Stream: Failure writing to " + m_identifier); } /* * Flush the stream */ void DataSink_Stream::end_msg() { m_sink.flush(); } /* * DataSink_Stream Constructor */ DataSink_Stream::DataSink_Stream(std::ostream& out, const std::string& name) : m_identifier(name), m_sink(out) { } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) /* * DataSink_Stream Constructor */ DataSink_Stream::DataSink_Stream(const std::string& path, bool use_binary) : m_identifier(path), m_sink_memory(new std::ofstream(path, use_binary ? std::ios::binary : std::ios::out)), m_sink(*m_sink_memory) { if(!m_sink.good()) { throw Stream_IO_Error("DataSink_Stream: Failure opening " + path); } } #endif /* * DataSink_Stream Destructor */ DataSink_Stream::~DataSink_Stream() { // for ~unique_ptr } } /* * Filter * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Filter Constructor */ Filter::Filter() { m_next.resize(1); m_port_num = 0; m_filter_owns = 0; m_owned = false; } /* * Send data to all ports */ void Filter::send(const uint8_t input[], size_t length) { if(!length) return; bool nothing_attached = true; for(size_t j = 0; j != total_ports(); ++j) if(m_next[j]) { if(m_write_queue.size()) m_next[j]->write(m_write_queue.data(), m_write_queue.size()); m_next[j]->write(input, length); nothing_attached = false; } if(nothing_attached) m_write_queue += std::make_pair(input, length); else m_write_queue.clear(); } /* * Start a new message */ void Filter::new_msg() { start_msg(); for(size_t j = 0; j != total_ports(); ++j) if(m_next[j]) m_next[j]->new_msg(); } /* * End the current message */ void Filter::finish_msg() { end_msg(); for(size_t j = 0; j != total_ports(); ++j) if(m_next[j]) m_next[j]->finish_msg(); } /* * Attach a filter to the current port */ void Filter::attach(Filter* new_filter) { if(new_filter) { Filter* last = this; while(last->get_next()) last = last->get_next(); last->m_next[last->current_port()] = new_filter; } } /* * Set the active port on a filter */ void Filter::set_port(size_t new_port) { if(new_port >= total_ports()) throw Invalid_Argument("Filter: Invalid port number"); m_port_num = new_port; } /* * Return the next Filter in the logical chain */ Filter* Filter::get_next() const { if(m_port_num < m_next.size()) return m_next[m_port_num]; return nullptr; } /* * Set the next Filters */ void Filter::set_next(Filter* filters[], size_t size) { m_next.clear(); m_port_num = 0; m_filter_owns = 0; while(size && filters && (filters[size-1] == nullptr)) --size; if(filters && size) m_next.assign(filters, filters + size); } /* * Return the total number of ports */ size_t Filter::total_ports() const { return m_next.size(); } } /* * Hex Encoder/Decoder * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /** * Size used for internal buffer in hex encoder/decoder */ const size_t HEX_CODEC_BUFFER_SIZE = 256; /* * Hex_Encoder Constructor */ Hex_Encoder::Hex_Encoder(bool breaks, size_t length, Case c) : m_casing(c), m_line_length(breaks ? length : 0) { m_in.resize(HEX_CODEC_BUFFER_SIZE); m_out.resize(2*m_in.size()); m_counter = m_position = 0; } /* * Hex_Encoder Constructor */ Hex_Encoder::Hex_Encoder(Case c) : m_casing(c), m_line_length(0) { m_in.resize(HEX_CODEC_BUFFER_SIZE); m_out.resize(2*m_in.size()); m_counter = m_position = 0; } /* * Encode and send a block */ void Hex_Encoder::encode_and_send(const uint8_t block[], size_t length) { hex_encode(cast_uint8_ptr_to_char(m_out.data()), block, length, m_casing == Uppercase); if(m_line_length == 0) send(m_out, 2*length); else { size_t remaining = 2*length, offset = 0; while(remaining) { size_t sent = std::min(m_line_length - m_counter, remaining); send(&m_out[offset], sent); m_counter += sent; remaining -= sent; offset += sent; if(m_counter == m_line_length) { send('\n'); m_counter = 0; } } } } /* * Convert some data into hex format */ void Hex_Encoder::write(const uint8_t input[], size_t length) { buffer_insert(m_in, m_position, input, length); if(m_position + length >= m_in.size()) { encode_and_send(m_in.data(), m_in.size()); input += (m_in.size() - m_position); length -= (m_in.size() - m_position); while(length >= m_in.size()) { encode_and_send(input, m_in.size()); input += m_in.size(); length -= m_in.size(); } copy_mem(m_in.data(), input, length); m_position = 0; } m_position += length; } /* * Flush buffers */ void Hex_Encoder::end_msg() { encode_and_send(m_in.data(), m_position); if(m_counter && m_line_length) send('\n'); m_counter = m_position = 0; } /* * Hex_Decoder Constructor */ Hex_Decoder::Hex_Decoder(Decoder_Checking c) : m_checking(c) { m_in.resize(HEX_CODEC_BUFFER_SIZE); m_out.resize(m_in.size() / 2); m_position = 0; } /* * Convert some data from hex format */ void Hex_Decoder::write(const uint8_t input[], size_t length) { while(length) { size_t to_copy = std::min(length, m_in.size() - m_position); copy_mem(&m_in[m_position], input, to_copy); m_position += to_copy; size_t consumed = 0; size_t written = hex_decode(m_out.data(), cast_uint8_ptr_to_char(m_in.data()), m_position, consumed, m_checking != FULL_CHECK); send(m_out, written); if(consumed != m_position) { copy_mem(m_in.data(), m_in.data() + consumed, m_position - consumed); m_position = m_position - consumed; } else m_position = 0; length -= to_copy; input += to_copy; } } /* * Flush buffers */ void Hex_Decoder::end_msg() { size_t consumed = 0; size_t written = hex_decode(m_out.data(), cast_uint8_ptr_to_char(m_in.data()), m_position, consumed, m_checking != FULL_CHECK); send(m_out, written); const bool not_full_bytes = consumed != m_position; m_position = 0; if(not_full_bytes) throw Invalid_Argument("Hex_Decoder: Input not full bytes"); } } /* * Pipe Output Buffer * (C) 1999-2007,2011 Jack Lloyd * 2012 Markus Wanner * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Read data from a message */ size_t Output_Buffers::read(uint8_t output[], size_t length, Pipe::message_id msg) { SecureQueue* q = get(msg); if(q) return q->read(output, length); return 0; } /* * Peek at data in a message */ size_t Output_Buffers::peek(uint8_t output[], size_t length, size_t stream_offset, Pipe::message_id msg) const { SecureQueue* q = get(msg); if(q) return q->peek(output, length, stream_offset); return 0; } /* * Check available bytes in a message */ size_t Output_Buffers::remaining(Pipe::message_id msg) const { SecureQueue* q = get(msg); if(q) return q->size(); return 0; } /* * Return the total bytes of a message that have already been read. */ size_t Output_Buffers::get_bytes_read(Pipe::message_id msg) const { SecureQueue* q = get(msg); if (q) return q->get_bytes_read(); return 0; } /* * Add a new output queue */ void Output_Buffers::add(SecureQueue* queue) { BOTAN_ASSERT(queue, "queue was provided"); BOTAN_ASSERT(m_buffers.size() < m_buffers.max_size(), "Room was available in container"); m_buffers.push_back(std::unique_ptr(queue)); } /* * Retire old output queues */ void Output_Buffers::retire() { for(size_t i = 0; i != m_buffers.size(); ++i) if(m_buffers[i] && m_buffers[i]->size() == 0) { m_buffers[i].reset(); } while(m_buffers.size() && !m_buffers[0]) { m_buffers.pop_front(); m_offset = m_offset + Pipe::message_id(1); } } /* * Get a particular output queue */ SecureQueue* Output_Buffers::get(Pipe::message_id msg) const { if(msg < m_offset) return nullptr; BOTAN_ASSERT(msg < message_count(), "Message number is in range"); return m_buffers[msg-m_offset].get(); } /* * Return the total number of messages */ Pipe::message_id Output_Buffers::message_count() const { return (m_offset + m_buffers.size()); } /* * Output_Buffers Constructor */ Output_Buffers::Output_Buffers() { m_offset = 0; } } /* * Pipe * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * A Filter that does nothing */ class Null_Filter final : public Filter { public: void write(const uint8_t input[], size_t length) override { send(input, length); } std::string name() const override { return "Null"; } }; } /* * Pipe Constructor */ Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : Pipe({f1,f2,f3,f4}) { } /* * Pipe Constructor */ Pipe::Pipe(std::initializer_list args) { m_outputs.reset(new Output_Buffers); m_pipe = nullptr; m_default_read = 0; m_inside_msg = false; for(auto i = args.begin(); i != args.end(); ++i) do_append(*i); } /* * Pipe Destructor */ Pipe::~Pipe() { destruct(m_pipe); } /* * Reset the Pipe */ void Pipe::reset() { destruct(m_pipe); m_pipe = nullptr; m_inside_msg = false; } /* * Destroy the Pipe */ void Pipe::destruct(Filter* to_kill) { if(!to_kill || dynamic_cast(to_kill)) return; for(size_t j = 0; j != to_kill->total_ports(); ++j) destruct(to_kill->m_next[j]); delete to_kill; } /* * Test if the Pipe has any data in it */ bool Pipe::end_of_data() const { return (remaining() == 0); } /* * Set the default read message */ void Pipe::set_default_msg(message_id msg) { if(msg >= message_count()) throw Invalid_Argument("Pipe::set_default_msg: msg number is too high"); m_default_read = msg; } /* * Process a full message at once */ void Pipe::process_msg(const uint8_t input[], size_t length) { start_msg(); write(input, length); end_msg(); } /* * Process a full message at once */ void Pipe::process_msg(const secure_vector& input) { process_msg(input.data(), input.size()); } void Pipe::process_msg(const std::vector& input) { process_msg(input.data(), input.size()); } /* * Process a full message at once */ void Pipe::process_msg(const std::string& input) { process_msg(cast_char_ptr_to_uint8(input.data()), input.length()); } /* * Process a full message at once */ void Pipe::process_msg(DataSource& input) { start_msg(); write(input); end_msg(); } /* * Start a new message */ void Pipe::start_msg() { if(m_inside_msg) throw Invalid_State("Pipe::start_msg: Message was already started"); if(m_pipe == nullptr) m_pipe = new Null_Filter; find_endpoints(m_pipe); m_pipe->new_msg(); m_inside_msg = true; } /* * End the current message */ void Pipe::end_msg() { if(!m_inside_msg) throw Invalid_State("Pipe::end_msg: Message was already ended"); m_pipe->finish_msg(); clear_endpoints(m_pipe); if(dynamic_cast(m_pipe)) { delete m_pipe; m_pipe = nullptr; } m_inside_msg = false; m_outputs->retire(); } /* * Find the endpoints of the Pipe */ void Pipe::find_endpoints(Filter* f) { for(size_t j = 0; j != f->total_ports(); ++j) if(f->m_next[j] && !dynamic_cast(f->m_next[j])) find_endpoints(f->m_next[j]); else { SecureQueue* q = new SecureQueue; f->m_next[j] = q; m_outputs->add(q); } } /* * Remove the SecureQueues attached to the Filter */ void Pipe::clear_endpoints(Filter* f) { if(!f) return; for(size_t j = 0; j != f->total_ports(); ++j) { if(f->m_next[j] && dynamic_cast(f->m_next[j])) f->m_next[j] = nullptr; clear_endpoints(f->m_next[j]); } } void Pipe::append(Filter* filter) { do_append(filter); } void Pipe::append_filter(Filter* filter) { if(m_outputs->message_count() != 0) throw Invalid_State("Cannot call Pipe::append_filter after start_msg"); do_append(filter); } void Pipe::prepend(Filter* filter) { do_prepend(filter); } void Pipe::prepend_filter(Filter* filter) { if(m_outputs->message_count() != 0) throw Invalid_State("Cannot call Pipe::prepend_filter after start_msg"); do_prepend(filter); } /* * Append a Filter to the Pipe */ void Pipe::do_append(Filter* filter) { if(!filter) return; if(dynamic_cast(filter)) throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); if(filter->m_owned) throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); if(m_inside_msg) throw Invalid_State("Cannot append to a Pipe while it is processing"); filter->m_owned = true; if(!m_pipe) m_pipe = filter; else m_pipe->attach(filter); } /* * Prepend a Filter to the Pipe */ void Pipe::do_prepend(Filter* filter) { if(m_inside_msg) throw Invalid_State("Cannot prepend to a Pipe while it is processing"); if(!filter) return; if(dynamic_cast(filter)) throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); if(filter->m_owned) throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); filter->m_owned = true; if(m_pipe) filter->attach(m_pipe); m_pipe = filter; } /* * Pop a Filter off the Pipe */ void Pipe::pop() { if(m_inside_msg) throw Invalid_State("Cannot pop off a Pipe while it is processing"); if(!m_pipe) return; if(m_pipe->total_ports() > 1) throw Invalid_State("Cannot pop off a Filter with multiple ports"); size_t to_remove = m_pipe->owns() + 1; while(to_remove--) { std::unique_ptr to_destroy(m_pipe); m_pipe = m_pipe->m_next[0]; } } /* * Return the number of messages in this Pipe */ Pipe::message_id Pipe::message_count() const { return m_outputs->message_count(); } /* * Static Member Variables */ const Pipe::message_id Pipe::LAST_MESSAGE = static_cast(-2); const Pipe::message_id Pipe::DEFAULT_MESSAGE = static_cast(-1); } /* * Pipe I/O * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Write data from a pipe into an ostream */ std::ostream& operator<<(std::ostream& stream, Pipe& pipe) { secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); while(stream.good() && pipe.remaining()) { const size_t got = pipe.read(buffer.data(), buffer.size()); stream.write(cast_uint8_ptr_to_char(buffer.data()), got); } if(!stream.good()) throw Stream_IO_Error("Pipe output operator (iostream) has failed"); return stream; } /* * Read data from an istream into a pipe */ std::istream& operator>>(std::istream& stream, Pipe& pipe) { secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); while(stream.good()) { stream.read(cast_uint8_ptr_to_char(buffer.data()), buffer.size()); const size_t got = static_cast(stream.gcount()); pipe.write(buffer.data(), got); } if(stream.bad() || (stream.fail() && !stream.eof())) throw Stream_IO_Error("Pipe input operator (iostream) has failed"); return stream; } } /* * Pipe Reading/Writing * (C) 1999-2007 Jack Lloyd * 2012 Markus Wanner * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Look up the canonical ID for a queue */ Pipe::message_id Pipe::get_message_no(const std::string& func_name, message_id msg) const { if(msg == DEFAULT_MESSAGE) msg = default_msg(); else if(msg == LAST_MESSAGE) msg = message_count() - 1; if(msg >= message_count()) throw Invalid_Message_Number(func_name, msg); return msg; } /* * Write into a Pipe */ void Pipe::write(const uint8_t input[], size_t length) { if(!m_inside_msg) throw Invalid_State("Cannot write to a Pipe while it is not processing"); m_pipe->write(input, length); } /* * Write a string into a Pipe */ void Pipe::write(const std::string& str) { write(cast_char_ptr_to_uint8(str.data()), str.size()); } /* * Write a single byte into a Pipe */ void Pipe::write(uint8_t input) { write(&input, 1); } /* * Write the contents of a DataSource into a Pipe */ void Pipe::write(DataSource& source) { secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); while(!source.end_of_data()) { size_t got = source.read(buffer.data(), buffer.size()); write(buffer.data(), got); } } /* * Read some data from the pipe */ size_t Pipe::read(uint8_t output[], size_t length, message_id msg) { return m_outputs->read(output, length, get_message_no("read", msg)); } /* * Read some data from the pipe */ size_t Pipe::read(uint8_t output[], size_t length) { return read(output, length, DEFAULT_MESSAGE); } /* * Read a single byte from the pipe */ size_t Pipe::read(uint8_t& out, message_id msg) { return read(&out, 1, msg); } /* * Return all data in the pipe */ secure_vector Pipe::read_all(message_id msg) { msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); secure_vector buffer(remaining(msg)); size_t got = read(buffer.data(), buffer.size(), msg); buffer.resize(got); return buffer; } /* * Return all data in the pipe as a string */ std::string Pipe::read_all_as_string(message_id msg) { msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); std::string str; str.reserve(remaining(msg)); while(true) { size_t got = read(buffer.data(), buffer.size(), msg); if(got == 0) break; str.append(cast_uint8_ptr_to_char(buffer.data()), got); } return str; } /* * Find out how many bytes are ready to read */ size_t Pipe::remaining(message_id msg) const { return m_outputs->remaining(get_message_no("remaining", msg)); } /* * Peek at some data in the pipe */ size_t Pipe::peek(uint8_t output[], size_t length, size_t offset, message_id msg) const { return m_outputs->peek(output, length, offset, get_message_no("peek", msg)); } /* * Peek at some data in the pipe */ size_t Pipe::peek(uint8_t output[], size_t length, size_t offset) const { return peek(output, length, offset, DEFAULT_MESSAGE); } /* * Peek at a byte in the pipe */ size_t Pipe::peek(uint8_t& out, size_t offset, message_id msg) const { return peek(&out, 1, offset, msg); } size_t Pipe::get_bytes_read() const { return m_outputs->get_bytes_read(default_msg()); } size_t Pipe::get_bytes_read(message_id msg) const { return m_outputs->get_bytes_read(msg); } bool Pipe::check_available(size_t n) { return (n <= remaining(default_msg())); } bool Pipe::check_available_msg(size_t n, message_id msg) { return (n <= remaining(msg)); } } /* * SecureQueue * (C) 1999-2007 Jack Lloyd * 2012 Markus Wanner * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /** * A node in a SecureQueue */ class SecureQueueNode final { public: SecureQueueNode() : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE) { m_next = nullptr; m_start = m_end = 0; } ~SecureQueueNode() { m_next = nullptr; m_start = m_end = 0; } size_t write(const uint8_t input[], size_t length) { size_t copied = std::min(length, m_buffer.size() - m_end); copy_mem(m_buffer.data() + m_end, input, copied); m_end += copied; return copied; } size_t read(uint8_t output[], size_t length) { size_t copied = std::min(length, m_end - m_start); copy_mem(output, m_buffer.data() + m_start, copied); m_start += copied; return copied; } size_t peek(uint8_t output[], size_t length, size_t offset = 0) { const size_t left = m_end - m_start; if(offset >= left) return 0; size_t copied = std::min(length, left - offset); copy_mem(output, m_buffer.data() + m_start + offset, copied); return copied; } size_t size() const { return (m_end - m_start); } private: friend class SecureQueue; SecureQueueNode* m_next; secure_vector m_buffer; size_t m_start, m_end; }; /* * Create a SecureQueue */ SecureQueue::SecureQueue() { m_bytes_read = 0; set_next(nullptr, 0); m_head = m_tail = new SecureQueueNode; } /* * Copy a SecureQueue */ SecureQueue::SecureQueue(const SecureQueue& input) : Fanout_Filter(), DataSource() { m_bytes_read = 0; set_next(nullptr, 0); m_head = m_tail = new SecureQueueNode; SecureQueueNode* temp = input.m_head; while(temp) { write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start); temp = temp->m_next; } } /* * Destroy this SecureQueue */ void SecureQueue::destroy() { SecureQueueNode* temp = m_head; while(temp) { SecureQueueNode* holder = temp->m_next; delete temp; temp = holder; } m_head = m_tail = nullptr; } /* * Copy a SecureQueue */ SecureQueue& SecureQueue::operator=(const SecureQueue& input) { if(this == &input) return *this; destroy(); m_bytes_read = input.get_bytes_read(); m_head = m_tail = new SecureQueueNode; SecureQueueNode* temp = input.m_head; while(temp) { write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start); temp = temp->m_next; } return (*this); } /* * Add some bytes to the queue */ void SecureQueue::write(const uint8_t input[], size_t length) { if(!m_head) m_head = m_tail = new SecureQueueNode; while(length) { const size_t n = m_tail->write(input, length); input += n; length -= n; if(length) { m_tail->m_next = new SecureQueueNode; m_tail = m_tail->m_next; } } } /* * Read some bytes from the queue */ size_t SecureQueue::read(uint8_t output[], size_t length) { size_t got = 0; while(length && m_head) { const size_t n = m_head->read(output, length); output += n; got += n; length -= n; if(m_head->size() == 0) { SecureQueueNode* holder = m_head->m_next; delete m_head; m_head = holder; } } m_bytes_read += got; return got; } /* * Read data, but do not remove it from queue */ size_t SecureQueue::peek(uint8_t output[], size_t length, size_t offset) const { SecureQueueNode* current = m_head; while(offset && current) { if(offset >= current->size()) { offset -= current->size(); current = current->m_next; } else break; } size_t got = 0; while(length && current) { const size_t n = current->peek(output, length, offset); offset = 0; output += n; got += n; length -= n; current = current->m_next; } return got; } /** * Return how many bytes have been read so far. */ size_t SecureQueue::get_bytes_read() const { return m_bytes_read; } /* * Return how many bytes the queue holds */ size_t SecureQueue::size() const { SecureQueueNode* current = m_head; size_t count = 0; while(current) { count += current->size(); current = current->m_next; } return count; } /* * Test if the queue has any data in it */ bool SecureQueue::end_of_data() const { return (size() == 0); } bool SecureQueue::empty() const { return (size() == 0); } } /* * Threaded Fork * (C) 2013 Joel Low * 2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_THREAD_UTILS) namespace Botan { struct Threaded_Fork_Data { /* * Semaphore for indicating that there is work to be done (or to * quit) */ Semaphore m_input_ready_semaphore; /* * Synchronises all threads to complete processing data in lock-step. */ Barrier m_input_complete_barrier; /* * The work that needs to be done. This should be only when the threads * are NOT running (i.e. before notifying the work condition, after * the input_complete_barrier has reset.) */ const uint8_t* m_input = nullptr; /* * The length of the work that needs to be done. */ size_t m_input_length = 0; }; /* * Threaded_Fork constructor */ Threaded_Fork::Threaded_Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : Fork(nullptr, static_cast(0)), m_thread_data(new Threaded_Fork_Data) { Filter* filters[4] = { f1, f2, f3, f4 }; set_next(filters, 4); } /* * Threaded_Fork constructor */ Threaded_Fork::Threaded_Fork(Filter* filters[], size_t count) : Fork(nullptr, static_cast(0)), m_thread_data(new Threaded_Fork_Data) { set_next(filters, count); } Threaded_Fork::~Threaded_Fork() { m_thread_data->m_input = nullptr; m_thread_data->m_input_length = 0; m_thread_data->m_input_ready_semaphore.release(m_threads.size()); for(auto& thread : m_threads) thread->join(); } std::string Threaded_Fork::name() const { return "Threaded Fork"; } void Threaded_Fork::set_next(Filter* f[], size_t n) { Fork::set_next(f, n); n = m_next.size(); if(n < m_threads.size()) m_threads.resize(n); else { m_threads.reserve(n); for(size_t i = m_threads.size(); i != n; ++i) { m_threads.push_back( std::shared_ptr( new std::thread( std::bind(&Threaded_Fork::thread_entry, this, m_next[i])))); } } } void Threaded_Fork::send(const uint8_t input[], size_t length) { if(m_write_queue.size()) thread_delegate_work(m_write_queue.data(), m_write_queue.size()); thread_delegate_work(input, length); bool nothing_attached = true; for(size_t j = 0; j != total_ports(); ++j) if(m_next[j]) nothing_attached = false; if(nothing_attached) m_write_queue += std::make_pair(input, length); else m_write_queue.clear(); } void Threaded_Fork::thread_delegate_work(const uint8_t input[], size_t length) { //Set the data to do. m_thread_data->m_input = input; m_thread_data->m_input_length = length; //Let the workers start processing. m_thread_data->m_input_complete_barrier.wait(total_ports() + 1); m_thread_data->m_input_ready_semaphore.release(total_ports()); //Wait for all the filters to finish processing. m_thread_data->m_input_complete_barrier.sync(); //Reset the thread data m_thread_data->m_input = nullptr; m_thread_data->m_input_length = 0; } void Threaded_Fork::thread_entry(Filter* filter) { while(true) { m_thread_data->m_input_ready_semaphore.acquire(); if(!m_thread_data->m_input) break; filter->write(m_thread_data->m_input, m_thread_data->m_input_length); m_thread_data->m_input_complete_barrier.sync(); } } } #endif /* * Format Preserving Encryption (FE1 scheme) * (C) 2009,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { // Normally FPE is for SSNs, CC#s, etc, nothing too big const size_t MAX_N_BYTES = 128/8; /* * Factor n into a and b which are as close together as possible. * Assumes n is composed mostly of small factors which is the case for * typical uses of FPE (typically, n is a power of 10) */ void factor(BigInt n, BigInt& a, BigInt& b) { a = 1; b = 1; size_t n_low_zero = low_zero_bits(n); a <<= (n_low_zero / 2); b <<= n_low_zero - (n_low_zero / 2); n >>= n_low_zero; for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) { while(n % PRIMES[i] == 0) { a *= PRIMES[i]; if(a > b) std::swap(a, b); n /= PRIMES[i]; } } if(a > b) std::swap(a, b); a *= n; if(a <= 1 || b <= 1) throw Internal_Error("Could not factor n for use in FPE"); } } FPE_FE1::FPE_FE1(const BigInt& n, size_t rounds, bool compat_mode, const std::string& mac_algo) : m_rounds(rounds) { if(m_rounds < 3) throw Invalid_Argument("FPE_FE1 rounds too small"); m_mac = MessageAuthenticationCode::create_or_throw(mac_algo); m_n_bytes = BigInt::encode(n); if(m_n_bytes.size() > MAX_N_BYTES) throw Invalid_Argument("N is too large for FPE encryption"); factor(n, m_a, m_b); if(compat_mode) { if(m_a < m_b) std::swap(m_a, m_b); } else { if(m_a > m_b) std::swap(m_a, m_b); } mod_a.reset(new Modular_Reducer(m_a)); } FPE_FE1::~FPE_FE1() { // for ~unique_ptr } void FPE_FE1::clear() { m_mac->clear(); } std::string FPE_FE1::name() const { return "FPE_FE1(" + m_mac->name() + "," + std::to_string(m_rounds) + ")"; } Key_Length_Specification FPE_FE1::key_spec() const { return m_mac->key_spec(); } void FPE_FE1::key_schedule(const uint8_t key[], size_t length) { m_mac->set_key(key, length); } BigInt FPE_FE1::F(const BigInt& R, size_t round, const secure_vector& tweak_mac, secure_vector& tmp) const { tmp = BigInt::encode_locked(R); m_mac->update(tweak_mac); m_mac->update_be(static_cast(round)); m_mac->update_be(static_cast(tmp.size())); m_mac->update(tmp.data(), tmp.size()); tmp = m_mac->final(); return BigInt(tmp.data(), tmp.size()); } secure_vector FPE_FE1::compute_tweak_mac(const uint8_t tweak[], size_t tweak_len) const { m_mac->update_be(static_cast(m_n_bytes.size())); m_mac->update(m_n_bytes.data(), m_n_bytes.size()); m_mac->update_be(static_cast(tweak_len)); if(tweak_len > 0) m_mac->update(tweak, tweak_len); return m_mac->final(); } BigInt FPE_FE1::encrypt(const BigInt& input, const uint8_t tweak[], size_t tweak_len) const { const secure_vector tweak_mac = compute_tweak_mac(tweak, tweak_len); BigInt X = input; secure_vector tmp; BigInt L, R, Fi; for(size_t i = 0; i != m_rounds; ++i) { ct_divide(X, m_b, L, R); Fi = F(R, i, tweak_mac, tmp); X = m_a * R + mod_a->reduce(L + Fi); } return X; } BigInt FPE_FE1::decrypt(const BigInt& input, const uint8_t tweak[], size_t tweak_len) const { const secure_vector tweak_mac = compute_tweak_mac(tweak, tweak_len); BigInt X = input; secure_vector tmp; BigInt W, R, Fi; for(size_t i = 0; i != m_rounds; ++i) { ct_divide(X, m_a, R, W); Fi = F(R, m_rounds-i-1, tweak_mac, tmp); X = m_b * mod_a->reduce(W - Fi) + R; } return X; } BigInt FPE_FE1::encrypt(const BigInt& x, uint64_t tweak) const { uint8_t tweak8[8]; store_be(tweak, tweak8); return encrypt(x, tweak8, sizeof(tweak8)); } BigInt FPE_FE1::decrypt(const BigInt& x, uint64_t tweak) const { uint8_t tweak8[8]; store_be(tweak, tweak8); return decrypt(x, tweak8, sizeof(tweak8)); } namespace FPE { BigInt fe1_encrypt(const BigInt& n, const BigInt& X, const SymmetricKey& key, const std::vector& tweak) { FPE_FE1 fpe(n, 3, true, "HMAC(SHA-256)"); fpe.set_key(key); return fpe.encrypt(X, tweak.data(), tweak.size()); } BigInt fe1_decrypt(const BigInt& n, const BigInt& X, const SymmetricKey& key, const std::vector& tweak) { FPE_FE1 fpe(n, 3, true, "HMAC(SHA-256)"); fpe.set_key(key); return fpe.decrypt(X, tweak.data(), tweak.size()); } } } /* * GCM Mode Encryption * (C) 2013,2015 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * GCM_Mode Constructor */ GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) : m_tag_size(tag_size), m_cipher_name(cipher->name()), m_ctr(new CTR_BE(cipher, 4)), m_ghash(new GHASH) { if(cipher->block_size() != GCM_BS) throw Invalid_Argument("Invalid block cipher for GCM"); /* We allow any of the values 128, 120, 112, 104, or 96 bits as a tag size */ /* 64 bit tag is still supported but deprecated and will be removed in the future */ if(m_tag_size != 8 && (m_tag_size < 12 || m_tag_size > 16)) throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size)); } GCM_Mode::~GCM_Mode() { /* for unique_ptr */ } void GCM_Mode::clear() { m_ctr->clear(); m_ghash->clear(); reset(); } void GCM_Mode::reset() { m_ghash->reset(); } std::string GCM_Mode::name() const { return (m_cipher_name + "/GCM(" + std::to_string(tag_size()) + ")"); } std::string GCM_Mode::provider() const { return m_ghash->provider(); } size_t GCM_Mode::update_granularity() const { return GCM_BS * std::max(2, BOTAN_BLOCK_CIPHER_PAR_MULT); } bool GCM_Mode::valid_nonce_length(size_t len) const { // GCM does not support empty nonces return (len > 0); } Key_Length_Specification GCM_Mode::key_spec() const { return m_ctr->key_spec(); } void GCM_Mode::key_schedule(const uint8_t key[], size_t keylen) { m_ctr->set_key(key, keylen); const std::vector zeros(GCM_BS); m_ctr->set_iv(zeros.data(), zeros.size()); secure_vector H(GCM_BS); m_ctr->encipher(H); m_ghash->set_key(H); } void GCM_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) { m_ghash->set_associated_data(ad, ad_len); } void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); if(m_y0.size() != GCM_BS) m_y0.resize(GCM_BS); clear_mem(m_y0.data(), m_y0.size()); if(nonce_len == 12) { copy_mem(m_y0.data(), nonce, nonce_len); m_y0[15] = 1; } else { m_ghash->nonce_hash(m_y0, nonce, nonce_len); } m_ctr->set_iv(m_y0.data(), m_y0.size()); clear_mem(m_y0.data(), m_y0.size()); m_ctr->encipher(m_y0); m_ghash->start(m_y0.data(), m_y0.size()); clear_mem(m_y0.data(), m_y0.size()); } size_t GCM_Encryption::process(uint8_t buf[], size_t sz) { BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size"); m_ctr->cipher(buf, buf, sz); m_ghash->update(buf, sz); return sz; } void GCM_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; m_ctr->cipher(buf, buf, sz); m_ghash->update(buf, sz); uint8_t mac[16] = { 0 }; m_ghash->final(mac, tag_size()); buffer += std::make_pair(mac, tag_size()); } size_t GCM_Decryption::process(uint8_t buf[], size_t sz) { BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size"); m_ghash->update(buf, sz); m_ctr->cipher(buf, buf, sz); return sz; } void GCM_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; if(sz < tag_size()) throw Decoding_Error("Insufficient input for GCM decryption, tag missing"); const size_t remaining = sz - tag_size(); // handle any final input before the tag if(remaining) { m_ghash->update(buf, remaining); m_ctr->cipher(buf, buf, remaining); } uint8_t mac[16] = { 0 }; m_ghash->final(mac, tag_size()); const uint8_t* included_tag = &buffer[remaining+offset]; if(!constant_time_compare(mac, included_tag, tag_size())) throw Invalid_Authentication_Tag("GCM tag check failed"); buffer.resize(offset + remaining); } } /* * GCM GHASH * (C) 2013,2015,2017 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string GHASH::provider() const { #if defined(BOTAN_HAS_GHASH_CLMUL_CPU) if(CPUID::has_carryless_multiply()) return "clmul"; #endif #if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) if(CPUID::has_vperm()) return "vperm"; #endif return "base"; } void GHASH::ghash_multiply(secure_vector& x, const uint8_t input[], size_t blocks) { #if defined(BOTAN_HAS_GHASH_CLMUL_CPU) if(CPUID::has_carryless_multiply()) { return ghash_multiply_cpu(x.data(), m_H_pow.data(), input, blocks); } #endif #if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) if(CPUID::has_vperm()) { return ghash_multiply_vperm(x.data(), m_HM.data(), input, blocks); } #endif CT::poison(x.data(), x.size()); const uint64_t ALL_BITS = 0xFFFFFFFFFFFFFFFF; uint64_t X[2] = { load_be(x.data(), 0), load_be(x.data(), 1) }; for(size_t b = 0; b != blocks; ++b) { X[0] ^= load_be(input, 2*b); X[1] ^= load_be(input, 2*b+1); uint64_t Z[2] = { 0, 0 }; for(size_t i = 0; i != 64; ++i) { const uint64_t X0MASK = (ALL_BITS + (X[0] >> 63)) ^ ALL_BITS; const uint64_t X1MASK = (ALL_BITS + (X[1] >> 63)) ^ ALL_BITS; X[0] <<= 1; X[1] <<= 1; Z[0] ^= m_HM[4*i ] & X0MASK; Z[1] ^= m_HM[4*i+1] & X0MASK; Z[0] ^= m_HM[4*i+2] & X1MASK; Z[1] ^= m_HM[4*i+3] & X1MASK; } X[0] = Z[0]; X[1] = Z[1]; } store_be(x.data(), X[0], X[1]); CT::unpoison(x.data(), x.size()); } void GHASH::ghash_update(secure_vector& ghash, const uint8_t input[], size_t length) { verify_key_set(!m_HM.empty()); /* This assumes if less than block size input then we're just on the final block and should pad with zeros */ const size_t full_blocks = length / GCM_BS; const size_t final_bytes = length - (full_blocks * GCM_BS); if(full_blocks > 0) { ghash_multiply(ghash, input, full_blocks); } if(final_bytes) { uint8_t last_block[GCM_BS] = { 0 }; copy_mem(last_block, input + full_blocks * GCM_BS, final_bytes); ghash_multiply(ghash, last_block, 1); secure_scrub_memory(last_block, final_bytes); } } void GHASH::key_schedule(const uint8_t key[], size_t length) { m_H.assign(key, key+length); m_H_ad.resize(GCM_BS); m_ad_len = 0; m_text_len = 0; uint64_t H0 = load_be(m_H.data(), 0); uint64_t H1 = load_be(m_H.data(), 1); const uint64_t R = 0xE100000000000000; m_HM.resize(256); // precompute the multiples of H for(size_t i = 0; i != 2; ++i) { for(size_t j = 0; j != 64; ++j) { /* we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68 to make indexing nicer in the multiplication code */ m_HM[4*j+2*i] = H0; m_HM[4*j+2*i+1] = H1; // GCM's bit ops are reversed so we carry out of the bottom const uint64_t carry = R * (H1 & 1); H1 = (H1 >> 1) | (H0 << 63); H0 = (H0 >> 1) ^ carry; } } #if defined(BOTAN_HAS_GHASH_CLMUL_CPU) if(CPUID::has_carryless_multiply()) { m_H_pow.resize(8); ghash_precompute_cpu(m_H.data(), m_H_pow.data()); } #endif } void GHASH::start(const uint8_t nonce[], size_t len) { BOTAN_ARG_CHECK(len == 16, "GHASH requires a 128-bit nonce"); m_nonce.assign(nonce, nonce + len); m_ghash = m_H_ad; } void GHASH::set_associated_data(const uint8_t input[], size_t length) { if(m_ghash.empty() == false) throw Invalid_State("Too late to set AD in GHASH"); zeroise(m_H_ad); ghash_update(m_H_ad, input, length); m_ad_len = length; } void GHASH::update_associated_data(const uint8_t ad[], size_t length) { verify_key_set(m_ghash.size() == GCM_BS); m_ad_len += length; ghash_update(m_ghash, ad, length); } void GHASH::update(const uint8_t input[], size_t length) { verify_key_set(m_ghash.size() == GCM_BS); m_text_len += length; ghash_update(m_ghash, input, length); } void GHASH::add_final_block(secure_vector& hash, size_t ad_len, size_t text_len) { /* * stack buffer is fine here since the text len is public * and the length of the AD is probably not sensitive either. */ uint8_t final_block[GCM_BS]; store_be(final_block, 8*ad_len, 8*text_len); ghash_update(hash, final_block, GCM_BS); } void GHASH::final(uint8_t mac[], size_t mac_len) { BOTAN_ARG_CHECK(mac_len > 0 && mac_len <= 16, "GHASH output length"); add_final_block(m_ghash, m_ad_len, m_text_len); for(size_t i = 0; i != mac_len; ++i) mac[i] = m_ghash[i] ^ m_nonce[i]; m_ghash.clear(); m_text_len = 0; } void GHASH::nonce_hash(secure_vector& y0, const uint8_t nonce[], size_t nonce_len) { BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time"); ghash_update(y0, nonce, nonce_len); add_final_block(y0, 0, nonce_len); } void GHASH::clear() { zap(m_H); zap(m_HM); reset(); } void GHASH::reset() { zeroise(m_H_ad); m_ghash.clear(); m_nonce.clear(); m_text_len = m_ad_len = 0; } } /* * Hook for CLMUL/PMULL/VPMSUM * (C) 2013,2017,2019,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_SIMD_USE_SSE2) #include #endif namespace Botan { namespace { BOTAN_FORCE_INLINE SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) reverse_vector(const SIMD_4x32& in) { #if defined(BOTAN_SIMD_USE_SSE2) const __m128i BSWAP_MASK = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); return SIMD_4x32(_mm_shuffle_epi8(in.raw(), BSWAP_MASK)); #elif defined(BOTAN_SIMD_USE_NEON) const uint8_t maskb[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; const uint8x16_t mask = vld1q_u8(maskb); return SIMD_4x32(vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(in.raw()), mask))); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const __vector unsigned char mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; return SIMD_4x32(vec_perm(in.raw(), in.raw(), mask)); #endif } template BOTAN_FORCE_INLINE SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_CLMUL_ISA) clmul(const SIMD_4x32& H, const SIMD_4x32& x) { static_assert(M == 0x00 || M == 0x01 || M == 0x10 || M == 0x11, "Valid clmul mode"); #if defined(BOTAN_SIMD_USE_SSE2) return SIMD_4x32(_mm_clmulepi64_si128(x.raw(), H.raw(), M)); #elif defined(BOTAN_SIMD_USE_NEON) const uint64_t a = vgetq_lane_u64(vreinterpretq_u64_u32(x.raw()), M & 0x01); const uint64_t b = vgetq_lane_u64(vreinterpretq_u64_u32(H.raw()), (M & 0x10) >> 4); return SIMD_4x32(reinterpret_cast(vmull_p64(a, b))); #elif defined(BOTAN_SIMD_USE_ALTIVEC) const SIMD_4x32 mask_lo = SIMD_4x32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF); SIMD_4x32 i1 = x; SIMD_4x32 i2 = H; if(M == 0x11) { i1 &= mask_lo; i2 &= mask_lo; } else if(M == 0x10) { i1 = i1.shift_elems_left<2>(); } else if(M == 0x01) { i2 = i2.shift_elems_left<2>(); } else if(M == 0x00) { i1 = mask_lo.andc(i1); i2 = mask_lo.andc(i2); } auto i1v = reinterpret_cast<__vector unsigned long long>(i1.raw()); auto i2v = reinterpret_cast<__vector unsigned long long>(i2.raw()); #if defined(__clang__) auto rv = __builtin_altivec_crypto_vpmsumd(i1v, i2v); #else auto rv = __builtin_crypto_vpmsumd(i1v, i2v); #endif return SIMD_4x32(reinterpret_cast<__vector unsigned int>(rv)); #endif } inline SIMD_4x32 gcm_reduce(const SIMD_4x32& B0, const SIMD_4x32& B1) { SIMD_4x32 X0 = B1.shr<31>(); SIMD_4x32 X1 = B1.shl<1>(); SIMD_4x32 X2 = B0.shr<31>(); SIMD_4x32 X3 = B0.shl<1>(); X3 |= X0.shift_elems_right<3>(); X3 |= X2.shift_elems_left<1>(); X1 |= X0.shift_elems_left<1>(); X0 = X1.shl<31>() ^ X1.shl<30>() ^ X1.shl<25>(); X1 ^= X0.shift_elems_left<3>(); X0 = X1 ^ X3 ^ X0.shift_elems_right<1>(); X0 ^= X1.shr<7>() ^ X1.shr<2>() ^ X1.shr<1>(); return X0; } inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_CLMUL_ISA) gcm_multiply(const SIMD_4x32& H, const SIMD_4x32& x) { SIMD_4x32 T0 = clmul<0x11>(H, x); SIMD_4x32 T1 = clmul<0x10>(H, x); SIMD_4x32 T2 = clmul<0x01>(H, x); SIMD_4x32 T3 = clmul<0x00>(H, x); T1 ^= T2; T0 ^= T1.shift_elems_right<2>(); T3 ^= T1.shift_elems_left<2>(); return gcm_reduce(T0, T3); } inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_CLMUL_ISA) gcm_multiply_x4(const SIMD_4x32& H1, const SIMD_4x32& H2, const SIMD_4x32& H3, const SIMD_4x32& H4, const SIMD_4x32& X1, const SIMD_4x32& X2, const SIMD_4x32& X3, const SIMD_4x32& X4) { /* * Mutiply with delayed reduction, algorithm by Krzysztof Jankowski * and Pierre Laurent of Intel */ const SIMD_4x32 lo = (clmul<0x00>(H1, X1) ^ clmul<0x00>(H2, X2)) ^ (clmul<0x00>(H3, X3) ^ clmul<0x00>(H4, X4)); const SIMD_4x32 hi = (clmul<0x11>(H1, X1) ^ clmul<0x11>(H2, X2)) ^ (clmul<0x11>(H3, X3) ^ clmul<0x11>(H4, X4)); SIMD_4x32 T; T ^= clmul<0x00>(H1 ^ H1.shift_elems_right<2>(), X1 ^ X1.shift_elems_right<2>()); T ^= clmul<0x00>(H2 ^ H2.shift_elems_right<2>(), X2 ^ X2.shift_elems_right<2>()); T ^= clmul<0x00>(H3 ^ H3.shift_elems_right<2>(), X3 ^ X3.shift_elems_right<2>()); T ^= clmul<0x00>(H4 ^ H4.shift_elems_right<2>(), X4 ^ X4.shift_elems_right<2>()); T ^= lo; T ^= hi; return gcm_reduce(hi ^ T.shift_elems_right<2>(), lo ^ T.shift_elems_left<2>()); } } BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) void GHASH::ghash_precompute_cpu(const uint8_t H_bytes[16], uint64_t H_pow[4*2]) { const SIMD_4x32 H1 = reverse_vector(SIMD_4x32::load_le(H_bytes)); const SIMD_4x32 H2 = gcm_multiply(H1, H1); const SIMD_4x32 H3 = gcm_multiply(H1, H2); const SIMD_4x32 H4 = gcm_multiply(H2, H2); H1.store_le(H_pow); H2.store_le(H_pow + 2); H3.store_le(H_pow + 4); H4.store_le(H_pow + 6); } BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) void GHASH::ghash_multiply_cpu(uint8_t x[16], const uint64_t H_pow[8], const uint8_t input[], size_t blocks) { /* * Algorithms 1 and 5 from Intel's CLMUL guide */ const SIMD_4x32 H1 = SIMD_4x32::load_le(H_pow); SIMD_4x32 a = reverse_vector(SIMD_4x32::load_le(x)); if(blocks >= 4) { const SIMD_4x32 H2 = SIMD_4x32::load_le(H_pow + 2); const SIMD_4x32 H3 = SIMD_4x32::load_le(H_pow + 4); const SIMD_4x32 H4 = SIMD_4x32::load_le(H_pow + 6); while(blocks >= 4) { const SIMD_4x32 m0 = reverse_vector(SIMD_4x32::load_le(input )); const SIMD_4x32 m1 = reverse_vector(SIMD_4x32::load_le(input + 16*1)); const SIMD_4x32 m2 = reverse_vector(SIMD_4x32::load_le(input + 16*2)); const SIMD_4x32 m3 = reverse_vector(SIMD_4x32::load_le(input + 16*3)); a ^= m0; a = gcm_multiply_x4(H1, H2, H3, H4, m3, m2, m1, a); input += 4*16; blocks -= 4; } } for(size_t i = 0; i != blocks; ++i) { const SIMD_4x32 m = reverse_vector(SIMD_4x32::load_le(input + 16*i)); a ^= m; a = gcm_multiply(H1, a); } a = reverse_vector(a); a.store_le(x); } } /* * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { // TODO: extend this to support NEON and AltiVec BOTAN_FUNC_ISA("ssse3") void GHASH::ghash_multiply_vperm(uint8_t x[16], const uint64_t HM[256], const uint8_t input_bytes[], size_t blocks) { const __m128i BSWAP_MASK = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); const __m128i* HM_mm = reinterpret_cast(HM); __m128i X = _mm_loadu_si128(reinterpret_cast<__m128i*>(x)); X = _mm_shuffle_epi8(X, BSWAP_MASK); const __m128i ones = _mm_set1_epi8(-1); for(size_t b = 0; b != blocks; ++b) { __m128i M = _mm_loadu_si128(reinterpret_cast(input_bytes) + b); M = _mm_shuffle_epi8(M, BSWAP_MASK); X = _mm_xor_si128(X, M); __m128i Z = _mm_setzero_si128(); for(size_t i = 0; i != 64; i += 2) { const __m128i HM0 = _mm_loadu_si128(HM_mm + 2*i); const __m128i HM1 = _mm_loadu_si128(HM_mm + 2*i + 1); const __m128i HM2 = _mm_loadu_si128(HM_mm + 2*i + 2); const __m128i HM3 = _mm_loadu_si128(HM_mm + 2*i + 3); const __m128i XMASK1 = _mm_add_epi64(_mm_srli_epi64(X, 63), ones); X = _mm_slli_epi64(X, 1); const __m128i XMASK2 = _mm_add_epi64(_mm_srli_epi64(X, 63), ones); X = _mm_slli_epi64(X, 1); Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpackhi_epi64(XMASK1, XMASK1), HM0)); Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpacklo_epi64(XMASK1, XMASK1), HM1)); Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpackhi_epi64(XMASK2, XMASK2), HM2)); Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpacklo_epi64(XMASK2, XMASK2), HM3)); } X = _mm_shuffle_epi32(Z, _MM_SHUFFLE(1, 0, 3, 2)); } X = _mm_shuffle_epi8(X, BSWAP_MASK); _mm_storeu_si128(reinterpret_cast<__m128i*>(x), X); } } /* * GMAC * (C) 2016 Matthias Gierlings, René Korthaus * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { GMAC::GMAC(BlockCipher* cipher) : m_cipher(cipher), m_ghash(new GHASH), m_aad_buf(GCM_BS), m_aad_buf_pos(0), m_initialized(false) { } void GMAC::clear() { m_cipher->clear(); m_ghash->clear(); zeroise(m_aad_buf); m_aad_buf_pos = 0; m_initialized = false; } GMAC::~GMAC() { /* for unique_ptr */ } Key_Length_Specification GMAC::key_spec() const { return m_cipher->key_spec(); } std::string GMAC::name() const { return "GMAC(" + m_cipher->name() + ")"; } size_t GMAC::output_length() const { return GCM_BS; } void GMAC::add_data(const uint8_t input[], size_t size) { if(m_aad_buf_pos > 0) { const size_t taking = std::min(GCM_BS - m_aad_buf_pos, size); copy_mem(&m_aad_buf[m_aad_buf_pos], input, taking); m_aad_buf_pos += taking; input += taking; size -= taking; if(m_aad_buf_pos == GCM_BS) { m_ghash->update_associated_data(m_aad_buf.data(), GCM_BS); m_aad_buf_pos = 0; } } const size_t left_over = size % GCM_BS; const size_t full_blocks = size - left_over; m_ghash->update_associated_data(input, full_blocks); input += full_blocks; if(left_over > 0) { copy_mem(&m_aad_buf[m_aad_buf_pos], input, left_over); m_aad_buf_pos += left_over; } } void GMAC::key_schedule(const uint8_t key[], size_t size) { clear(); m_cipher->set_key(key, size); secure_vector H(GCM_BS); m_cipher->encrypt(H); m_ghash->set_key(H); } void GMAC::start_msg(const uint8_t nonce[], size_t nonce_len) { secure_vector y0(GCM_BS); if(nonce_len == 12) { copy_mem(y0.data(), nonce, nonce_len); y0[GCM_BS - 1] = 1; } else { m_ghash->ghash_update(y0, nonce, nonce_len); m_ghash->add_final_block(y0, 0, nonce_len); } secure_vector m_enc_y0(GCM_BS); m_cipher->encrypt(y0.data(), m_enc_y0.data()); m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); m_initialized = true; } void GMAC::final_result(uint8_t mac[]) { // This ensures the GMAC computation has been initialized with a fresh // nonce. The aim of this check is to prevent developers from re-using // nonces (and potential nonce-reuse attacks). if(m_initialized == false) throw Invalid_State("GMAC was not used with a fresh nonce"); // process the rest of the aad buffer. Even if it is a partial block only // ghash_update will process it properly. if(m_aad_buf_pos > 0) { m_ghash->update_associated_data(m_aad_buf.data(), m_aad_buf_pos); } m_ghash->final(mac, output_length()); clear(); } MessageAuthenticationCode* GMAC::clone() const { return new GMAC(m_cipher->clone()); } } /* * GOST 28147-89 * (C) 1999-2009,2011 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { uint8_t GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const { const uint8_t x = m_sboxes[4 * col + (row / 2)]; return (row % 2 == 0) ? (x >> 4) : (x & 0x0F); } uint8_t GOST_28147_89_Params::sbox_pair(size_t row, size_t col) const { const uint8_t x = m_sboxes[4 * (col % 16) + row]; const uint8_t y = m_sboxes[4 * (col / 16) + row]; return (x >> 4) | (y << 4); } GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : m_name(n) { // Encoded in the packed fromat from RFC 4357 // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0) static const uint8_t GOST_R_3411_TEST_PARAMS[64] = { 0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A, 0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38, 0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62, 0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3, 0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C, 0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC }; // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1) static const uint8_t GOST_R_3411_CRYPTOPRO_PARAMS[64] = { 0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42, 0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F, 0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1, 0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87, 0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE, 0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC }; if(m_name == "R3411_94_TestParam") m_sboxes = GOST_R_3411_TEST_PARAMS; else if(m_name == "R3411_CryptoPro") m_sboxes = GOST_R_3411_CRYPTOPRO_PARAMS; else throw Invalid_Argument("GOST_28147_89_Params: Unknown " + m_name); } /* * GOST Constructor */ GOST_28147_89::GOST_28147_89(const GOST_28147_89_Params& param) : m_SBOX(1024) { // Convert the parallel 4x4 sboxes into larger word-based sboxes for(size_t i = 0; i != 256; ++i) { m_SBOX[i ] = rotl<11, uint32_t>(param.sbox_pair(0, i)); m_SBOX[i+256] = rotl<19, uint32_t>(param.sbox_pair(1, i)); m_SBOX[i+512] = rotl<27, uint32_t>(param.sbox_pair(2, i)); m_SBOX[i+768] = rotl< 3, uint32_t>(param.sbox_pair(3, i)); } } std::string GOST_28147_89::name() const { /* 'Guess' the right name for the sbox on the basis of the values. This would need to be updated if support for other sbox parameters is added. Preferably, we would just store the string value in the constructor, but can't break binary compat. */ std::string sbox_name = ""; if(m_SBOX[0] == 0x00072000) sbox_name = "R3411_94_TestParam"; else if(m_SBOX[0] == 0x0002D000) sbox_name = "R3411_CryptoPro"; else throw Internal_Error("GOST-28147 unrecognized sbox value"); return "GOST-28147-89(" + sbox_name + ")"; } /* * Two rounds of GOST */ #define GOST_2ROUND(N1, N2, R1, R2) \ do { \ uint32_t T0 = N1 + m_EK[R1]; \ N2 ^= m_SBOX[get_byte(3, T0)] | \ m_SBOX[get_byte(2, T0)+256] | \ m_SBOX[get_byte(1, T0)+512] | \ m_SBOX[get_byte(0, T0)+768]; \ \ uint32_t T1 = N2 + m_EK[R2]; \ N1 ^= m_SBOX[get_byte(3, T1)] | \ m_SBOX[get_byte(2, T1)+256] | \ m_SBOX[get_byte(1, T1)+512] | \ m_SBOX[get_byte(0, T1)+768]; \ } while(0) /* * GOST Encryption */ void GOST_28147_89::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint32_t N1 = load_le(in, 0); uint32_t N2 = load_le(in, 1); for(size_t j = 0; j != 3; ++j) { GOST_2ROUND(N1, N2, 0, 1); GOST_2ROUND(N1, N2, 2, 3); GOST_2ROUND(N1, N2, 4, 5); GOST_2ROUND(N1, N2, 6, 7); } GOST_2ROUND(N1, N2, 7, 6); GOST_2ROUND(N1, N2, 5, 4); GOST_2ROUND(N1, N2, 3, 2); GOST_2ROUND(N1, N2, 1, 0); store_le(out, N2, N1); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * GOST Decryption */ void GOST_28147_89::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint32_t N1 = load_le(in, 0); uint32_t N2 = load_le(in, 1); GOST_2ROUND(N1, N2, 0, 1); GOST_2ROUND(N1, N2, 2, 3); GOST_2ROUND(N1, N2, 4, 5); GOST_2ROUND(N1, N2, 6, 7); for(size_t j = 0; j != 3; ++j) { GOST_2ROUND(N1, N2, 7, 6); GOST_2ROUND(N1, N2, 5, 4); GOST_2ROUND(N1, N2, 3, 2); GOST_2ROUND(N1, N2, 1, 0); } store_le(out, N2, N1); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * GOST Key Schedule */ void GOST_28147_89::key_schedule(const uint8_t key[], size_t) { m_EK.resize(8); for(size_t i = 0; i != 8; ++i) m_EK[i] = load_le(key, i); } void GOST_28147_89::clear() { zap(m_EK); } } /* * GOST 34.10-2012 * (C) 2007 Falko Strenzke, FlexSecure GmbH * Manuel Hartl, FlexSecure GmbH * (C) 2008-2010,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::vector GOST_3410_PublicKey::public_key_bits() const { const BigInt x = public_point().get_affine_x(); const BigInt y = public_point().get_affine_y(); size_t part_size = std::max(x.bytes(), y.bytes()); std::vector bits(2*part_size); x.binary_encode(&bits[part_size - x.bytes()]); y.binary_encode(&bits[2*part_size - y.bytes()]); // Keys are stored in little endian format (WTF) for(size_t i = 0; i != part_size / 2; ++i) { std::swap(bits[i], bits[part_size-1-i]); std::swap(bits[part_size+i], bits[2*part_size-1-i]); } std::vector output; DER_Encoder(output).encode(bits, OCTET_STRING); return output; } std::string GOST_3410_PublicKey::algo_name() const { const size_t p_bits = domain().get_p_bits(); if(p_bits == 256 || p_bits == 512) return "GOST-34.10-2012-" + std::to_string(p_bits); else throw Encoding_Error("GOST-34.10-2012 is not defined for parameters of this size"); } AlgorithmIdentifier GOST_3410_PublicKey::algorithm_identifier() const { std::vector params; const OID gost_oid = get_oid(); const OID domain_oid = domain().get_curve_oid(); DER_Encoder(params).start_cons(SEQUENCE).encode(domain_oid).end_cons(); return AlgorithmIdentifier(gost_oid, params); } GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, const std::vector& key_bits) { OID ecc_param_id; // The parameters also includes hash and cipher OIDs BER_Decoder(alg_id.get_parameters()).start_cons(SEQUENCE).decode(ecc_param_id); m_domain_params = EC_Group(ecc_param_id); const size_t p_bits = m_domain_params.get_p_bits(); if(p_bits != 256 && p_bits != 512) throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + std::to_string(p_bits)); secure_vector bits; BER_Decoder(key_bits).decode(bits, OCTET_STRING); const size_t part_size = bits.size() / 2; // Keys are stored in little endian format (WTF) for(size_t i = 0; i != part_size / 2; ++i) { std::swap(bits[i], bits[part_size-1-i]); std::swap(bits[part_size+i], bits[2*part_size-1-i]); } BigInt x(bits.data(), part_size); BigInt y(&bits[part_size], part_size); m_public_key = domain().point(x, y); BOTAN_ASSERT(m_public_key.on_the_curve(), "Loaded GOST 34.10 public key is on the curve"); } GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) : EC_PrivateKey(rng, domain, x) { const size_t p_bits = m_domain_params.get_p_bits(); if(p_bits != 256 && p_bits != 512) throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + std::to_string(p_bits)); } namespace { BigInt decode_le(const uint8_t msg[], size_t msg_len) { secure_vector msg_le(msg, msg + msg_len); for(size_t i = 0; i != msg_le.size() / 2; ++i) std::swap(msg_le[i], msg_le[msg_le.size()-1-i]); return BigInt(msg_le.data(), msg_le.size()); } /** * GOST-34.10 signature operation */ class GOST_3410_Signature_Operation final : public PK_Ops::Signature_with_EMSA { public: GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410, const std::string& emsa) : PK_Ops::Signature_with_EMSA(emsa), m_group(gost_3410.domain()), m_x(gost_3410.private_value()) {} size_t signature_length() const override { return 2*m_group.get_order_bytes(); } size_t max_input_bits() const override { return m_group.get_order_bits(); } secure_vector raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; private: const EC_Group m_group; const BigInt& m_x; std::vector m_ws; }; secure_vector GOST_3410_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) { const BigInt k = m_group.random_scalar(rng); BigInt e = decode_le(msg, msg_len); e = m_group.mod_order(e); if(e == 0) e = 1; const BigInt r = m_group.mod_order( m_group.blinded_base_point_multiply_x(k, rng, m_ws)); const BigInt s = m_group.mod_order( m_group.multiply_mod_order(r, m_x) + m_group.multiply_mod_order(k, e)); if(r == 0 || s == 0) throw Internal_Error("GOST 34.10 signature generation failed, r/s equal to zero"); return BigInt::encode_fixed_length_int_pair(s, r, m_group.get_order_bytes()); } /** * GOST-34.10 verification operation */ class GOST_3410_Verification_Operation final : public PK_Ops::Verification_with_EMSA { public: GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost, const std::string& emsa) : PK_Ops::Verification_with_EMSA(emsa), m_group(gost.domain()), m_gy_mul(m_group.get_base_point(), gost.public_point()) {} size_t max_input_bits() const override { return m_group.get_order_bits(); } bool with_recovery() const override { return false; } bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override; private: const EC_Group m_group; const PointGFp_Multi_Point_Precompute m_gy_mul; }; bool GOST_3410_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) { if(sig_len != m_group.get_order_bytes() * 2) return false; const BigInt s(sig, sig_len / 2); const BigInt r(sig + sig_len / 2, sig_len / 2); const BigInt& order = m_group.get_order(); if(r <= 0 || r >= order || s <= 0 || s >= order) return false; BigInt e = decode_le(msg, msg_len); e = m_group.mod_order(e); if(e == 0) e = 1; const BigInt v = m_group.inverse_mod_order(e); const BigInt z1 = m_group.multiply_mod_order(s, v); const BigInt z2 = m_group.multiply_mod_order(-r, v); const PointGFp R = m_gy_mul.multi_exp(z1, z2); if(R.is_zero()) return false; return (R.get_affine_x() == r); } } std::unique_ptr GOST_3410_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new GOST_3410_Verification_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr GOST_3410_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new GOST_3410_Signature_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } } /* * GOST 34.11 * (C) 2009 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /** * GOST 34.11 Constructor */ GOST_34_11::GOST_34_11() : m_cipher(GOST_28147_89_Params("R3411_CryptoPro")), m_buffer(32), m_sum(32), m_hash(32) { m_count = 0; m_position = 0; } void GOST_34_11::clear() { m_cipher.clear(); zeroise(m_sum); zeroise(m_hash); m_count = 0; m_position = 0; } std::unique_ptr GOST_34_11::copy_state() const { return std::unique_ptr(new GOST_34_11(*this)); } /** * Hash additional inputs */ void GOST_34_11::add_data(const uint8_t input[], size_t length) { m_count += length; if(m_position) { buffer_insert(m_buffer, m_position, input, length); if(m_position + length >= hash_block_size()) { compress_n(m_buffer.data(), 1); input += (hash_block_size() - m_position); length -= (hash_block_size() - m_position); m_position = 0; } } const size_t full_blocks = length / hash_block_size(); const size_t remaining = length % hash_block_size(); if(full_blocks) compress_n(input, full_blocks); buffer_insert(m_buffer, m_position, input + full_blocks * hash_block_size(), remaining); m_position += remaining; } /** * The GOST 34.11 compression function */ void GOST_34_11::compress_n(const uint8_t input[], size_t blocks) { for(size_t i = 0; i != blocks; ++i) { for(uint16_t j = 0, carry = 0; j != 32; ++j) { uint16_t s = m_sum[j] + input[32*i+j] + carry; carry = get_byte(0, s); m_sum[j] = get_byte(1, s); } uint8_t S[32] = { 0 }; uint64_t U[4], V[4]; load_be(U, m_hash.data(), 4); load_be(V, input + 32*i, 4); for(size_t j = 0; j != 4; ++j) { uint8_t key[32] = { 0 }; // P transformation for(size_t k = 0; k != 4; ++k) { const uint64_t UVk = U[k] ^ V[k]; for(size_t l = 0; l != 8; ++l) key[4*l+k] = get_byte(l, UVk); } m_cipher.set_key(key, 32); m_cipher.encrypt(&m_hash[8*j], S + 8*j); if(j == 3) break; // A(x) uint64_t A_U = U[0]; U[0] = U[1]; U[1] = U[2]; U[2] = U[3]; U[3] = U[0] ^ A_U; if(j == 1) // C_3 { U[0] ^= 0x00FF00FF00FF00FF; U[1] ^= 0xFF00FF00FF00FF00; U[2] ^= 0x00FFFF00FF0000FF; U[3] ^= 0xFF000000FFFF00FF; } // A(A(x)) uint64_t AA_V_1 = V[0] ^ V[1]; uint64_t AA_V_2 = V[1] ^ V[2]; V[0] = V[2]; V[1] = V[3]; V[2] = AA_V_1; V[3] = AA_V_2; } uint8_t S2[32] = { 0 }; // 12 rounds of psi S2[ 0] = S[24]; S2[ 1] = S[25]; S2[ 2] = S[26]; S2[ 3] = S[27]; S2[ 4] = S[28]; S2[ 5] = S[29]; S2[ 6] = S[30]; S2[ 7] = S[31]; S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30]; S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31]; S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30]; S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31]; S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28]; S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29]; S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30]; S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31]; S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28]; S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29]; S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30]; S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31]; S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30]; S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31]; S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26]; S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27]; S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28]; S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29]; S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28]; S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29]; xor_buf(S, S2, input + 32*i, 32); S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30]; S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31]; copy_mem(S, S+2, 30); S[30] = S2[0]; S[31] = S2[1]; xor_buf(S, m_hash.data(), 32); // 61 rounds of psi S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28]; S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29]; S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30]; S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31]; S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30]; S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31]; S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28]; S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29]; S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30]; S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31]; S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24]; S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25]; S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26]; S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27]; S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28]; S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29]; S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30]; S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31]; S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^ S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^ S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^ S[26] ^ S[28]; S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^ S[27] ^ S[29]; S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28]; S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29]; S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30]; S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31]; copy_mem(m_hash.data(), S2, 32); } } /** * Produce the final GOST 34.11 output */ void GOST_34_11::final_result(uint8_t out[]) { if(m_position) { clear_mem(m_buffer.data() + m_position, m_buffer.size() - m_position); compress_n(m_buffer.data(), 1); } secure_vector length_buf(32); const uint64_t bit_count = m_count * 8; store_le(bit_count, length_buf.data()); secure_vector sum_buf = m_sum; compress_n(length_buf.data(), 1); compress_n(sum_buf.data(), 1); copy_mem(out, m_hash.data(), 32); clear(); } } /* * Hash Functions * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_ADLER32) #endif #if defined(BOTAN_HAS_CRC24) #endif #if defined(BOTAN_HAS_CRC32) #endif #if defined(BOTAN_HAS_GOST_34_11) #endif #if defined(BOTAN_HAS_KECCAK) #endif #if defined(BOTAN_HAS_MD4) #endif #if defined(BOTAN_HAS_MD5) #endif #if defined(BOTAN_HAS_RIPEMD_160) #endif #if defined(BOTAN_HAS_SHA1) #endif #if defined(BOTAN_HAS_SHA2_32) #endif #if defined(BOTAN_HAS_SHA2_64) #endif #if defined(BOTAN_HAS_SHA3) #endif #if defined(BOTAN_HAS_SHAKE) #endif #if defined(BOTAN_HAS_SKEIN_512) #endif #if defined(BOTAN_HAS_STREEBOG) #endif #if defined(BOTAN_HAS_SM3) #endif #if defined(BOTAN_HAS_TIGER) #endif #if defined(BOTAN_HAS_WHIRLPOOL) #endif #if defined(BOTAN_HAS_PARALLEL_HASH) #endif #if defined(BOTAN_HAS_COMB4P) #endif #if defined(BOTAN_HAS_BLAKE2B) #endif #if defined(BOTAN_HAS_OPENSSL) #endif #if defined(BOTAN_HAS_COMMONCRYPTO) #endif namespace Botan { std::unique_ptr HashFunction::create(const std::string& algo_spec, const std::string& provider) { #if defined(BOTAN_HAS_COMMONCRYPTO) if(provider.empty() || provider == "commoncrypto") { if(auto hash = make_commoncrypto_hash(algo_spec)) return hash; if(!provider.empty()) return nullptr; } #endif #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { if(auto hash = make_openssl_hash(algo_spec)) return hash; if(!provider.empty()) return nullptr; } #endif if(provider.empty() == false && provider != "base") return nullptr; // unknown provider #if defined(BOTAN_HAS_SHA1) if(algo_spec == "SHA-160" || algo_spec == "SHA-1" || algo_spec == "SHA1") { return std::unique_ptr(new SHA_160); } #endif #if defined(BOTAN_HAS_SHA2_32) if(algo_spec == "SHA-224") { return std::unique_ptr(new SHA_224); } if(algo_spec == "SHA-256") { return std::unique_ptr(new SHA_256); } #endif #if defined(BOTAN_HAS_SHA2_64) if(algo_spec == "SHA-384") { return std::unique_ptr(new SHA_384); } if(algo_spec == "SHA-512") { return std::unique_ptr(new SHA_512); } if(algo_spec == "SHA-512-256") { return std::unique_ptr(new SHA_512_256); } #endif #if defined(BOTAN_HAS_RIPEMD_160) if(algo_spec == "RIPEMD-160") { return std::unique_ptr(new RIPEMD_160); } #endif #if defined(BOTAN_HAS_WHIRLPOOL) if(algo_spec == "Whirlpool") { return std::unique_ptr(new Whirlpool); } #endif #if defined(BOTAN_HAS_MD5) if(algo_spec == "MD5") { return std::unique_ptr(new MD5); } #endif #if defined(BOTAN_HAS_MD4) if(algo_spec == "MD4") { return std::unique_ptr(new MD4); } #endif #if defined(BOTAN_HAS_GOST_34_11) if(algo_spec == "GOST-R-34.11-94" || algo_spec == "GOST-34.11") { return std::unique_ptr(new GOST_34_11); } #endif #if defined(BOTAN_HAS_ADLER32) if(algo_spec == "Adler32") { return std::unique_ptr(new Adler32); } #endif #if defined(BOTAN_HAS_CRC24) if(algo_spec == "CRC24") { return std::unique_ptr(new CRC24); } #endif #if defined(BOTAN_HAS_CRC32) if(algo_spec == "CRC32") { return std::unique_ptr(new CRC32); } #endif const SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_TIGER) if(req.algo_name() == "Tiger") { return std::unique_ptr( new Tiger(req.arg_as_integer(0, 24), req.arg_as_integer(1, 3))); } #endif #if defined(BOTAN_HAS_SKEIN_512) if(req.algo_name() == "Skein-512") { return std::unique_ptr( new Skein_512(req.arg_as_integer(0, 512), req.arg(1, ""))); } #endif #if defined(BOTAN_HAS_BLAKE2B) if(req.algo_name() == "Blake2b" || req.algo_name() == "BLAKE2b") { return std::unique_ptr( new Blake2b(req.arg_as_integer(0, 512))); } #endif #if defined(BOTAN_HAS_KECCAK) if(req.algo_name() == "Keccak-1600") { return std::unique_ptr( new Keccak_1600(req.arg_as_integer(0, 512))); } #endif #if defined(BOTAN_HAS_SHA3) if(req.algo_name() == "SHA-3") { return std::unique_ptr( new SHA_3(req.arg_as_integer(0, 512))); } #endif #if defined(BOTAN_HAS_SHAKE) if(req.algo_name() == "SHAKE-128") { return std::unique_ptr(new SHAKE_128(req.arg_as_integer(0, 128))); } if(req.algo_name() == "SHAKE-256") { return std::unique_ptr(new SHAKE_256(req.arg_as_integer(0, 256))); } #endif #if defined(BOTAN_HAS_STREEBOG) if(algo_spec == "Streebog-256") { return std::unique_ptr(new Streebog_256); } if(algo_spec == "Streebog-512") { return std::unique_ptr(new Streebog_512); } #endif #if defined(BOTAN_HAS_SM3) if(algo_spec == "SM3") { return std::unique_ptr(new SM3); } #endif #if defined(BOTAN_HAS_WHIRLPOOL) if(req.algo_name() == "Whirlpool") { return std::unique_ptr(new Whirlpool); } #endif #if defined(BOTAN_HAS_PARALLEL_HASH) if(req.algo_name() == "Parallel") { std::vector> hashes; for(size_t i = 0; i != req.arg_count(); ++i) { auto h = HashFunction::create(req.arg(i)); if(!h) { return nullptr; } hashes.push_back(std::move(h)); } return std::unique_ptr(new Parallel(hashes)); } #endif #if defined(BOTAN_HAS_COMB4P) if(req.algo_name() == "Comb4P" && req.arg_count() == 2) { std::unique_ptr h1(HashFunction::create(req.arg(0))); std::unique_ptr h2(HashFunction::create(req.arg(1))); if(h1 && h2) return std::unique_ptr(new Comb4P(h1.release(), h2.release())); } #endif return nullptr; } //static std::unique_ptr HashFunction::create_or_throw(const std::string& algo, const std::string& provider) { if(auto hash = HashFunction::create(algo, provider)) { return hash; } throw Lookup_Error("Hash", algo, provider); } std::vector HashFunction::providers(const std::string& algo_spec) { return probe_providers_of(algo_spec, {"base", "openssl", "commoncrypto"}); } } /* * Hash Function Identification * (C) 1999-2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { const uint8_t MD5_PKCS_ID[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; const uint8_t RIPEMD_160_PKCS_ID[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; const uint8_t SHA_160_PKCS_ID[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 }; const uint8_t SHA_224_PKCS_ID[] = { 0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C }; const uint8_t SHA_256_PKCS_ID[] = { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; const uint8_t SHA_384_PKCS_ID[] = { 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; const uint8_t SHA_512_PKCS_ID[] = { 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; const uint8_t SHA_512_256_PKCS_ID[] = { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20 }; const uint8_t SHA3_224_PKCS_ID[] = { 0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07, 0x05, 0x00, 0x04, 0x1C }; const uint8_t SHA3_256_PKCS_ID[] = { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20 }; const uint8_t SHA3_384_PKCS_ID[] = { 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, 0x30 }; const uint8_t SHA3_512_PKCS_ID[] = { 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A, 0x05, 0x00, 0x04, 0x40 }; const uint8_t SM3_PKCS_ID[] = { 0x30, 0x30, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x83, 0x11, 0x05, 0x00, 0x04, 0x20, }; const uint8_t TIGER_PKCS_ID[] = { 0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 }; } /* * HashID as specified by PKCS */ std::vector pkcs_hash_id(const std::string& name) { // Special case for SSL/TLS RSA signatures if(name == "Parallel(MD5,SHA-160)") return std::vector(); // If you add a value to this function, also update test_hash_id.cpp if(name == "MD5") return std::vector(MD5_PKCS_ID, MD5_PKCS_ID + sizeof(MD5_PKCS_ID)); if(name == "RIPEMD-160") return std::vector(RIPEMD_160_PKCS_ID, RIPEMD_160_PKCS_ID + sizeof(RIPEMD_160_PKCS_ID)); if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") return std::vector(SHA_160_PKCS_ID, SHA_160_PKCS_ID + sizeof(SHA_160_PKCS_ID)); if(name == "SHA-224") return std::vector(SHA_224_PKCS_ID, SHA_224_PKCS_ID + sizeof(SHA_224_PKCS_ID)); if(name == "SHA-256") return std::vector(SHA_256_PKCS_ID, SHA_256_PKCS_ID + sizeof(SHA_256_PKCS_ID)); if(name == "SHA-384") return std::vector(SHA_384_PKCS_ID, SHA_384_PKCS_ID + sizeof(SHA_384_PKCS_ID)); if(name == "SHA-512") return std::vector(SHA_512_PKCS_ID, SHA_512_PKCS_ID + sizeof(SHA_512_PKCS_ID)); if(name == "SHA-512-256") return std::vector(SHA_512_256_PKCS_ID, SHA_512_256_PKCS_ID + sizeof(SHA_512_256_PKCS_ID)); if(name == "SHA-3(224)") return std::vector(SHA3_224_PKCS_ID, SHA3_224_PKCS_ID + sizeof(SHA3_224_PKCS_ID)); if(name == "SHA-3(256)") return std::vector(SHA3_256_PKCS_ID, SHA3_256_PKCS_ID + sizeof(SHA3_256_PKCS_ID)); if(name == "SHA-3(384)") return std::vector(SHA3_384_PKCS_ID, SHA3_384_PKCS_ID + sizeof(SHA3_384_PKCS_ID)); if(name == "SHA-3(512)") return std::vector(SHA3_512_PKCS_ID, SHA3_512_PKCS_ID + sizeof(SHA3_512_PKCS_ID)); if(name == "SM3") return std::vector(SM3_PKCS_ID, SM3_PKCS_ID + sizeof(SM3_PKCS_ID)); if(name == "Tiger(24,3)") return std::vector(TIGER_PKCS_ID, TIGER_PKCS_ID + sizeof(TIGER_PKCS_ID)); throw Invalid_Argument("No PKCS #1 identifier for " + name); } /* * HashID as specified by IEEE 1363/X9.31 */ uint8_t ieee1363_hash_id(const std::string& name) { if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") return 0x33; if(name == "SHA-224") return 0x38; if(name == "SHA-256") return 0x34; if(name == "SHA-384") return 0x36; if(name == "SHA-512") return 0x35; if(name == "RIPEMD-160") return 0x31; if(name == "Whirlpool") return 0x37; return 0; } } /* * Hex Encoding and Decoding * (C) 2010,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { char hex_encode_nibble(uint8_t n, bool uppercase) { BOTAN_DEBUG_ASSERT(n <= 15); const auto in_09 = CT::Mask::is_lt(n, 10); const char c_09 = n + '0'; const char c_af = n + (uppercase ? 'A' : 'a') - 10; return in_09.select(c_09, c_af); } } void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase) { for(size_t i = 0; i != input_length; ++i) { const uint8_t n0 = (input[i] >> 4) & 0xF; const uint8_t n1 = (input[i] ) & 0xF; output[2*i ] = hex_encode_nibble(n0, uppercase); output[2*i+1] = hex_encode_nibble(n1, uppercase); } } std::string hex_encode(const uint8_t input[], size_t input_length, bool uppercase) { std::string output(2 * input_length, 0); if(input_length) hex_encode(&output.front(), input, input_length, uppercase); return output; } namespace { uint8_t hex_char_to_bin(char input) { const uint8_t c = static_cast(input); const auto is_alpha_upper = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('F')); const auto is_alpha_lower = CT::Mask::is_within_range(c, uint8_t('a'), uint8_t('f')); const auto is_decimal = CT::Mask::is_within_range(c, uint8_t('0'), uint8_t('9')); const auto is_whitespace = CT::Mask::is_any_of(c, { uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') }); const uint8_t c_upper = c - uint8_t('A') + 10; const uint8_t c_lower = c - uint8_t('a') + 10; const uint8_t c_decim = c - uint8_t('0'); uint8_t ret = 0xFF; // default value ret = is_alpha_upper.select(c_upper, ret); ret = is_alpha_lower.select(c_lower, ret); ret = is_decimal.select(c_decim, ret); ret = is_whitespace.select(0x80, ret); return ret; } } size_t hex_decode(uint8_t output[], const char input[], size_t input_length, size_t& input_consumed, bool ignore_ws) { uint8_t* out_ptr = output; bool top_nibble = true; clear_mem(output, input_length / 2); for(size_t i = 0; i != input_length; ++i) { const uint8_t bin = hex_char_to_bin(input[i]); if(bin >= 0x10) { if(bin == 0x80 && ignore_ws) continue; std::string bad_char(1, input[i]); if(bad_char == "\t") bad_char = "\\t"; else if(bad_char == "\n") bad_char = "\\n"; throw Invalid_Argument( std::string("hex_decode: invalid hex character '") + bad_char + "'"); } if(top_nibble) *out_ptr |= bin << 4; else *out_ptr |= bin; top_nibble = !top_nibble; if(top_nibble) ++out_ptr; } input_consumed = input_length; size_t written = (out_ptr - output); /* * We only got half of a uint8_t at the end; zap the half-written * output and mark it as unread */ if(!top_nibble) { *out_ptr = 0; input_consumed -= 1; } return written; } size_t hex_decode(uint8_t output[], const char input[], size_t input_length, bool ignore_ws) { size_t consumed = 0; size_t written = hex_decode(output, input, input_length, consumed, ignore_ws); if(consumed != input_length) throw Invalid_Argument("hex_decode: input did not have full bytes"); return written; } size_t hex_decode(uint8_t output[], const std::string& input, bool ignore_ws) { return hex_decode(output, input.data(), input.length(), ignore_ws); } secure_vector hex_decode_locked(const char input[], size_t input_length, bool ignore_ws) { secure_vector bin(1 + input_length / 2); size_t written = hex_decode(bin.data(), input, input_length, ignore_ws); bin.resize(written); return bin; } secure_vector hex_decode_locked(const std::string& input, bool ignore_ws) { return hex_decode_locked(input.data(), input.size(), ignore_ws); } std::vector hex_decode(const char input[], size_t input_length, bool ignore_ws) { std::vector bin(1 + input_length / 2); size_t written = hex_decode(bin.data(), input, input_length, ignore_ws); bin.resize(written); return bin; } std::vector hex_decode(const std::string& input, bool ignore_ws) { return hex_decode(input.data(), input.size(), ignore_ws); } } /* * HKDF * (C) 2013,2015,2017 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t HKDF::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { HKDF_Extract extract(m_prf->clone()); HKDF_Expand expand(m_prf->clone()); secure_vector prk(m_prf->output_length()); extract.kdf(prk.data(), prk.size(), secret, secret_len, salt, salt_len, nullptr, 0); return expand.kdf(key, key_len, prk.data(), prk.size(), nullptr, 0, label, label_len); } size_t HKDF_Extract::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t[], size_t) const { secure_vector prk; if(salt_len == 0) { m_prf->set_key(std::vector(m_prf->output_length())); } else { m_prf->set_key(salt, salt_len); } m_prf->update(secret, secret_len); m_prf->final(prk); const size_t written = std::min(prk.size(), key_len); copy_mem(&key[0], prk.data(), written); // FIXME: returns truncated output return written; } size_t HKDF_Expand::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { m_prf->set_key(secret, secret_len); uint8_t counter = 1; secure_vector h; size_t offset = 0; while(offset != key_len && counter != 0) { m_prf->update(h); m_prf->update(label, label_len); m_prf->update(salt, salt_len); m_prf->update(counter++); m_prf->final(h); const size_t written = std::min(h.size(), key_len - offset); copy_mem(&key[offset], h.data(), written); offset += written; } // FIXME: returns truncated output return offset; } secure_vector hkdf_expand_label(const std::string& hash_fn, const uint8_t secret[], size_t secret_len, const std::string& label, const uint8_t hash_val[], size_t hash_val_len, size_t length) { BOTAN_ARG_CHECK(length <= 0xFFFF, "HKDF-Expand-Label requested output too large"); BOTAN_ARG_CHECK(label.size() <= 0xFF, "HKDF-Expand-Label label too long"); BOTAN_ARG_CHECK(hash_val_len <= 0xFF, "HKDF-Expand-Label hash too long"); const uint16_t length16 = static_cast(length); auto mac = MessageAuthenticationCode::create_or_throw("HMAC(" + hash_fn + ")"); HKDF_Expand hkdf(mac.release()); secure_vector output(length16); std::vector prefix(3 + label.size() + 1); prefix[0] = get_byte(0, length16); prefix[1] = get_byte(1, length16); prefix[2] = static_cast(label.size()); copy_mem(prefix.data() + 3, cast_char_ptr_to_uint8(label.data()), label.size()); prefix[3 + label.size()] = static_cast(hash_val_len); /* * We do something a little dirty here to avoid copying the hash_val, * making use of the fact that Botan's KDF interface supports label+salt, * and knowing that our HKDF hashes first param label then param salt. */ hkdf.kdf(output.data(), output.size(), secret, secret_len, hash_val, hash_val_len, prefix.data(), prefix.size()); return output; } } /* * HMAC * (C) 1999-2007,2014,2020 Jack Lloyd * 2007 Yves Jerschow * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Update a HMAC Calculation */ void HMAC::add_data(const uint8_t input[], size_t length) { verify_key_set(m_ikey.empty() == false); m_hash->update(input, length); } /* * Finalize a HMAC Calculation */ void HMAC::final_result(uint8_t mac[]) { verify_key_set(m_okey.empty() == false); m_hash->final(mac); m_hash->update(m_okey); m_hash->update(mac, m_hash_output_length); m_hash->final(mac); m_hash->update(m_ikey); } Key_Length_Specification HMAC::key_spec() const { // Support very long lengths for things like PBKDF2 and the TLS PRF return Key_Length_Specification(0, 4096); } size_t HMAC::output_length() const { return m_hash_output_length; } /* * HMAC Key Schedule */ void HMAC::key_schedule(const uint8_t key[], size_t length) { const uint8_t ipad = 0x36; const uint8_t opad = 0x5C; m_hash->clear(); m_ikey.resize(m_hash_block_size); m_okey.resize(m_hash_block_size); clear_mem(m_ikey.data(), m_ikey.size()); clear_mem(m_okey.data(), m_okey.size()); /* * Sometimes the HMAC key length itself is sensitive, as with PBKDF2 where it * reveals the length of the passphrase. Make some attempt to hide this to * side channels. Clearly if the secret is longer than the block size then the * branch to hash first reveals that. In addition, counting the number of * compression functions executed reveals the size at the granularity of the * hash function's block size. * * The greater concern is for smaller keys; being able to detect when a * passphrase is say 4 bytes may assist choosing weaker targets. Even though * the loop bounds are constant, we can only actually read key[0..length] so * it doesn't seem possible to make this computation truly constant time. * * We don't mind leaking if the length is exactly zero since that's * trivial to simply check. */ if(length > m_hash_block_size) { m_hash->update(key, length); m_hash->final(m_ikey.data()); } else if(length > 0) { for(size_t i = 0, i_mod_length = 0; i != m_hash_block_size; ++i) { /* access key[i % length] but avoiding division due to variable time computation on some processors. */ auto needs_reduction = CT::Mask::is_lte(length, i_mod_length); i_mod_length = needs_reduction.select(0, i_mod_length); const uint8_t kb = key[i_mod_length]; auto in_range = CT::Mask::is_lt(i, length); m_ikey[i] = static_cast(in_range.if_set_return(kb)); i_mod_length += 1; } } for(size_t i = 0; i != m_hash_block_size; ++i) { m_ikey[i] ^= ipad; m_okey[i] = m_ikey[i] ^ ipad ^ opad; } m_hash->update(m_ikey); } /* * Clear memory of sensitive data */ void HMAC::clear() { m_hash->clear(); zap(m_ikey); zap(m_okey); } /* * Return the name of this type */ std::string HMAC::name() const { return "HMAC(" + m_hash->name() + ")"; } /* * Return a clone of this object */ MessageAuthenticationCode* HMAC::clone() const { return new HMAC(m_hash->clone()); } /* * HMAC Constructor */ HMAC::HMAC(HashFunction* hash) : m_hash(hash), m_hash_output_length(m_hash->output_length()), m_hash_block_size(m_hash->hash_block_size()) { BOTAN_ARG_CHECK(m_hash_block_size >= m_hash_output_length, "HMAC is not compatible with this hash function"); } } /* * HMAC_DRBG * (C) 2014,2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { size_t hmac_drbg_security_level(size_t mac_output_length) { // security strength of the hash function // for pre-image resistance (see NIST SP 800-57) // SHA-160: 128 bits // SHA-224, SHA-512/224: 192 bits, // SHA-256, SHA-512/256, SHA-384, SHA-512: >= 256 bits // NIST SP 800-90A only supports up to 256 bits though if(mac_output_length < 32) { return (mac_output_length - 4) * 8; } else { return 32 * 8; } } void check_limits(size_t reseed_interval, size_t max_number_of_bytes_per_request) { // SP800-90A permits up to 2^48, but it is not usable on 32 bit // platforms, so we only allow up to 2^24, which is still reasonably high if(reseed_interval == 0 || reseed_interval > static_cast(1) << 24) { throw Invalid_Argument("Invalid value for reseed_interval"); } if(max_number_of_bytes_per_request == 0 || max_number_of_bytes_per_request > 64 * 1024) { throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request"); } } } HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf, RandomNumberGenerator& underlying_rng, size_t reseed_interval, size_t max_number_of_bytes_per_request) : Stateful_RNG(underlying_rng, reseed_interval), m_mac(std::move(prf)), m_max_number_of_bytes_per_request(max_number_of_bytes_per_request), m_security_level(hmac_drbg_security_level(m_mac->output_length())) { BOTAN_ASSERT_NONNULL(m_mac); check_limits(reseed_interval, max_number_of_bytes_per_request); clear(); } HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf, RandomNumberGenerator& underlying_rng, Entropy_Sources& entropy_sources, size_t reseed_interval, size_t max_number_of_bytes_per_request) : Stateful_RNG(underlying_rng, entropy_sources, reseed_interval), m_mac(std::move(prf)), m_max_number_of_bytes_per_request(max_number_of_bytes_per_request), m_security_level(hmac_drbg_security_level(m_mac->output_length())) { BOTAN_ASSERT_NONNULL(m_mac); check_limits(reseed_interval, max_number_of_bytes_per_request); clear(); } HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf, Entropy_Sources& entropy_sources, size_t reseed_interval, size_t max_number_of_bytes_per_request) : Stateful_RNG(entropy_sources, reseed_interval), m_mac(std::move(prf)), m_max_number_of_bytes_per_request(max_number_of_bytes_per_request), m_security_level(hmac_drbg_security_level(m_mac->output_length())) { BOTAN_ASSERT_NONNULL(m_mac); check_limits(reseed_interval, max_number_of_bytes_per_request); clear(); } HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf) : Stateful_RNG(), m_mac(std::move(prf)), m_max_number_of_bytes_per_request(64*1024), m_security_level(hmac_drbg_security_level(m_mac->output_length())) { BOTAN_ASSERT_NONNULL(m_mac); clear(); } HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash) : Stateful_RNG(), m_mac(MessageAuthenticationCode::create_or_throw("HMAC(" + hmac_hash + ")")), m_max_number_of_bytes_per_request(64 * 1024), m_security_level(hmac_drbg_security_level(m_mac->output_length())) { clear(); } void HMAC_DRBG::clear_state() { if(m_V.size() == 0) { const size_t output_length = m_mac->output_length(); m_V.resize(output_length); } for(size_t i = 0; i != m_V.size(); ++i) m_V[i] = 0x01; m_mac->set_key(std::vector(m_V.size(), 0x00)); } std::string HMAC_DRBG::name() const { return "HMAC_DRBG(" + m_mac->name() + ")"; } /* * HMAC_DRBG generation * See NIST SP800-90A section 10.1.2.5 */ void HMAC_DRBG::generate_output(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) { if(input_len > 0) { update(input, input_len); } while(output_len > 0) { const size_t to_copy = std::min(output_len, m_V.size()); m_mac->update(m_V.data(), m_V.size()); m_mac->final(m_V.data()); copy_mem(output, m_V.data(), to_copy); output += to_copy; output_len -= to_copy; } update(input, input_len); } /* * Reset V and the mac key with new values * See NIST SP800-90A section 10.1.2.2 */ void HMAC_DRBG::update(const uint8_t input[], size_t input_len) { secure_vector T(m_V.size()); m_mac->update(m_V); m_mac->update(0x00); m_mac->update(input, input_len); m_mac->final(T.data()); m_mac->set_key(T); m_mac->update(m_V.data(), m_V.size()); m_mac->final(m_V.data()); if(input_len > 0) { m_mac->update(m_V); m_mac->update(0x01); m_mac->update(input, input_len); m_mac->final(T.data()); m_mac->set_key(T); m_mac->update(m_V.data(), m_V.size()); m_mac->final(m_V.data()); } } size_t HMAC_DRBG::security_level() const { return m_security_level; } } /* * HOTP * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { HOTP::HOTP(const uint8_t key[], size_t key_len, const std::string& hash_algo, size_t digits) { BOTAN_ARG_CHECK(digits == 6 || digits == 7 || digits == 8, "Invalid HOTP digits"); if(digits == 6) m_digit_mod = 1000000; else if(digits == 7) m_digit_mod = 10000000; else if(digits == 8) m_digit_mod = 100000000; /* RFC 4228 only supports SHA-1 but TOTP allows SHA-256 and SHA-512 and some HOTP libs support one or both as extensions */ if(hash_algo == "SHA-1") m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)"); else if(hash_algo == "SHA-256") m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); else if(hash_algo == "SHA-512") m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); else throw Invalid_Argument("Unsupported HOTP hash function"); m_mac->set_key(key, key_len); } uint32_t HOTP::generate_hotp(uint64_t counter) { m_mac->update_be(counter); const secure_vector mac = m_mac->final(); const size_t offset = mac[mac.size()-1] & 0x0F; const uint32_t code = load_be(mac.data() + offset, 0) & 0x7FFFFFFF; return code % m_digit_mod; } std::pair HOTP::verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range) { for(size_t i = 0; i <= resync_range; ++i) { if(generate_hotp(starting_counter + i) == otp) return std::make_pair(true, starting_counter + i + 1); } return std::make_pair(false, starting_counter); } } /* * TOTP * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { TOTP::TOTP(const uint8_t key[], size_t key_len, const std::string& hash_algo, size_t digits, size_t time_step) : m_hotp(key, key_len, hash_algo, digits) , m_time_step(time_step) , m_unix_epoch(calendar_point(1970, 1, 1, 0, 0, 0).to_std_timepoint()) { /* * Technically any time step except 0 is valid, but 30 is typical * and over 5 minutes seems unlikely. */ BOTAN_ARG_CHECK(m_time_step > 0 && m_time_step < 300, "Invalid TOTP time step"); } uint32_t TOTP::generate_totp(std::chrono::system_clock::time_point current_time) { const uint64_t unix_time = std::chrono::duration_cast(current_time - m_unix_epoch).count(); return this->generate_totp(unix_time); } uint32_t TOTP::generate_totp(uint64_t unix_time) { return m_hotp.generate_hotp(unix_time / m_time_step); } bool TOTP::verify_totp(uint32_t otp, std::chrono::system_clock::time_point current_time, size_t clock_drift_accepted) { const uint64_t unix_time = std::chrono::duration_cast(current_time - m_unix_epoch).count(); return verify_totp(otp, unix_time, clock_drift_accepted); } bool TOTP::verify_totp(uint32_t otp, uint64_t unix_time, size_t clock_drift_accepted) { uint64_t t = unix_time / m_time_step; for(size_t i = 0; i <= clock_drift_accepted; ++i) { if(m_hotp.generate_hotp(t-i) == otp) { return true; } } return false; } } /* * Sketchy HTTP client * (C) 2013,2016 Jack Lloyd * 2017 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace HTTP { namespace { /* * Connect to a host, write some bytes, then read until the server * closes the socket. */ std::string http_transact(const std::string& hostname, const std::string& service, const std::string& message, std::chrono::milliseconds timeout) { std::unique_ptr socket; const std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now(); try { socket = OS::open_socket(hostname, service, timeout); if(!socket) throw Not_Implemented("No socket support enabled in build"); } catch(std::exception& e) { throw HTTP_Error("HTTP connection to " + hostname + " failed: " + e.what()); } // Blocks until entire message has been written socket->write(cast_char_ptr_to_uint8(message.data()), message.size()); if(std::chrono::system_clock::now() - start_time > timeout) throw HTTP_Error("Timeout during writing message body"); std::ostringstream oss; std::vector buf(BOTAN_DEFAULT_BUFFER_SIZE); while(true) { const size_t got = socket->read(buf.data(), buf.size()); if(got == 0) // EOF break; if(std::chrono::system_clock::now() - start_time > timeout) throw HTTP_Error("Timeout while reading message body"); oss.write(cast_uint8_ptr_to_char(buf.data()), static_cast(got)); } return oss.str(); } } std::string url_encode(const std::string& in) { std::ostringstream out; for(auto c : in) { if(c >= 'A' && c <= 'Z') out << c; else if(c >= 'a' && c <= 'z') out << c; else if(c >= '0' && c <= '9') out << c; else if(c == '-' || c == '_' || c == '.' || c == '~') out << c; else out << '%' << hex_encode(cast_char_ptr_to_uint8(&c), 1); } return out.str(); } std::ostream& operator<<(std::ostream& o, const Response& resp) { o << "HTTP " << resp.status_code() << " " << resp.status_message() << "\n"; for(auto h : resp.headers()) o << "Header '" << h.first << "' = '" << h.second << "'\n"; o << "Body " << std::to_string(resp.body().size()) << " bytes:\n"; o.write(cast_uint8_ptr_to_char(resp.body().data()), resp.body().size()); return o; } Response http_sync(http_exch_fn http_transact, const std::string& verb, const std::string& url, const std::string& content_type, const std::vector& body, size_t allowable_redirects) { if(url.empty()) throw HTTP_Error("URL empty"); const auto protocol_host_sep = url.find("://"); if(protocol_host_sep == std::string::npos) throw HTTP_Error("Invalid URL '" + url + "'"); const auto host_loc_sep = url.find('/', protocol_host_sep + 3); std::string hostname, loc, service; if(host_loc_sep == std::string::npos) { hostname = url.substr(protocol_host_sep + 3, std::string::npos); loc = "/"; } else { hostname = url.substr(protocol_host_sep + 3, host_loc_sep-protocol_host_sep-3); loc = url.substr(host_loc_sep, std::string::npos); } const auto port_sep = hostname.find(":"); if(port_sep == std::string::npos) { service = "http"; // hostname not modified } else { service = hostname.substr(port_sep + 1, std::string::npos); hostname = hostname.substr(0, port_sep); } std::ostringstream outbuf; outbuf << verb << " " << loc << " HTTP/1.0\r\n"; outbuf << "Host: " << hostname << "\r\n"; if(verb == "GET") { outbuf << "Accept: */*\r\n"; outbuf << "Cache-Control: no-cache\r\n"; } else if(verb == "POST") outbuf << "Content-Length: " << body.size() << "\r\n"; if(!content_type.empty()) outbuf << "Content-Type: " << content_type << "\r\n"; outbuf << "Connection: close\r\n\r\n"; outbuf.write(cast_uint8_ptr_to_char(body.data()), body.size()); std::istringstream io(http_transact(hostname, service, outbuf.str())); std::string line1; std::getline(io, line1); if(!io || line1.empty()) throw HTTP_Error("No response"); std::stringstream response_stream(line1); std::string http_version; unsigned int status_code; std::string status_message; response_stream >> http_version >> status_code; std::getline(response_stream, status_message); if(!response_stream || http_version.substr(0,5) != "HTTP/") throw HTTP_Error("Not an HTTP response"); std::map headers; std::string header_line; while (std::getline(io, header_line) && header_line != "\r") { auto sep = header_line.find(": "); if(sep == std::string::npos || sep > header_line.size() - 2) throw HTTP_Error("Invalid HTTP header " + header_line); const std::string key = header_line.substr(0, sep); if(sep + 2 < header_line.size() - 1) { const std::string val = header_line.substr(sep + 2, (header_line.size() - 1) - (sep + 2)); headers[key] = val; } } if(status_code == 301 && headers.count("Location")) { if(allowable_redirects == 0) throw HTTP_Error("HTTP redirection count exceeded"); return GET_sync(headers["Location"], allowable_redirects - 1); } std::vector resp_body; std::vector buf(4096); while(io.good()) { io.read(cast_uint8_ptr_to_char(buf.data()), buf.size()); const size_t got = static_cast(io.gcount()); resp_body.insert(resp_body.end(), buf.data(), &buf[got]); } const std::string header_size = search_map(headers, std::string("Content-Length")); if(!header_size.empty()) { if(resp_body.size() != to_u32bit(header_size)) throw HTTP_Error("Content-Length disagreement, header says " + header_size + " got " + std::to_string(resp_body.size())); } return Response(status_code, status_message, resp_body, headers); } Response http_sync(const std::string& verb, const std::string& url, const std::string& content_type, const std::vector& body, size_t allowable_redirects, std::chrono::milliseconds timeout) { auto transact_with_timeout = [timeout](const std::string& hostname, const std::string& service, const std::string& message) { return http_transact(hostname, service, message, timeout); }; return http_sync( transact_with_timeout, verb, url, content_type, body, allowable_redirects); } Response GET_sync(const std::string& url, size_t allowable_redirects, std::chrono::milliseconds timeout) { return http_sync("GET", url, "", std::vector(), allowable_redirects, timeout); } Response POST_sync(const std::string& url, const std::string& content_type, const std::vector& body, size_t allowable_redirects, std::chrono::milliseconds timeout) { return http_sync("POST", url, content_type, body, allowable_redirects, timeout); } } } /* * IDEA * (C) 1999-2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Multiplication modulo 65537 */ inline uint16_t mul(uint16_t x, uint16_t y) { const uint32_t P = static_cast(x) * y; const auto P_mask = CT::Mask(CT::Mask::is_zero(P)); const uint32_t P_hi = P >> 16; const uint32_t P_lo = P & 0xFFFF; const uint16_t carry = (P_lo < P_hi); const uint16_t r_1 = static_cast((P_lo - P_hi) + carry); const uint16_t r_2 = 1 - x - y; return P_mask.select(r_2, r_1); } /* * Find multiplicative inverses modulo 65537 * * 65537 is prime; thus Fermat's little theorem tells us that * x^65537 == x modulo 65537, which means * x^(65537-2) == x^-1 modulo 65537 since * x^(65537-2) * x == 1 mod 65537 * * Do the exponentiation with a basic square and multiply: all bits are * of exponent are 1 so we always multiply */ uint16_t mul_inv(uint16_t x) { uint16_t y = x; for(size_t i = 0; i != 15; ++i) { y = mul(y, y); // square y = mul(y, x); } return y; } /** * IDEA is involutional, depending only on the key schedule */ void idea_op(const uint8_t in[], uint8_t out[], size_t blocks, const uint16_t K[52]) { const size_t BLOCK_SIZE = 8; CT::poison(in, blocks * 8); CT::poison(out, blocks * 8); CT::poison(K, 52); BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint16_t X1, X2, X3, X4; load_be(in + BLOCK_SIZE*i, X1, X2, X3, X4); for(size_t j = 0; j != 8; ++j) { X1 = mul(X1, K[6*j+0]); X2 += K[6*j+1]; X3 += K[6*j+2]; X4 = mul(X4, K[6*j+3]); const uint16_t T0 = X3; X3 = mul(X3 ^ X1, K[6*j+4]); const uint16_t T1 = X2; X2 = mul((X2 ^ X4) + X3, K[6*j+5]); X3 += X2; X1 ^= X2; X4 ^= X3; X2 ^= T0; X3 ^= T1; } X1 = mul(X1, K[48]); X2 += K[50]; X3 += K[49]; X4 = mul(X4, K[51]); store_be(out + BLOCK_SIZE*i, X1, X3, X2, X4); } CT::unpoison(in, blocks * 8); CT::unpoison(out, blocks * 8); CT::unpoison(K, 52); } } size_t IDEA::parallelism() const { #if defined(BOTAN_HAS_IDEA_SSE2) if(CPUID::has_sse2()) { return 8; } #endif return 1; } std::string IDEA::provider() const { #if defined(BOTAN_HAS_IDEA_SSE2) if(CPUID::has_sse2()) { return "sse2"; } #endif return "base"; } /* * IDEA Encryption */ void IDEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); #if defined(BOTAN_HAS_IDEA_SSE2) if(CPUID::has_sse2()) { while(blocks >= 8) { sse2_idea_op_8(in, out, m_EK.data()); in += 8 * BLOCK_SIZE; out += 8 * BLOCK_SIZE; blocks -= 8; } } #endif idea_op(in, out, blocks, m_EK.data()); } /* * IDEA Decryption */ void IDEA::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DK.empty() == false); #if defined(BOTAN_HAS_IDEA_SSE2) if(CPUID::has_sse2()) { while(blocks >= 8) { sse2_idea_op_8(in, out, m_DK.data()); in += 8 * BLOCK_SIZE; out += 8 * BLOCK_SIZE; blocks -= 8; } } #endif idea_op(in, out, blocks, m_DK.data()); } /* * IDEA Key Schedule */ void IDEA::key_schedule(const uint8_t key[], size_t) { m_EK.resize(52); m_DK.resize(52); CT::poison(key, 16); CT::poison(m_EK.data(), 52); CT::poison(m_DK.data(), 52); secure_vector K(2); K[0] = load_be(key, 0); K[1] = load_be(key, 1); for(size_t off = 0; off != 48; off += 8) { for(size_t i = 0; i != 8; ++i) m_EK[off+i] = static_cast(K[i/4] >> (48-16*(i % 4))); const uint64_t Kx = (K[0] >> 39); const uint64_t Ky = (K[1] >> 39); K[0] = (K[0] << 25) | Ky; K[1] = (K[1] << 25) | Kx; } for(size_t i = 0; i != 4; ++i) m_EK[48+i] = static_cast(K[i/4] >> (48-16*(i % 4))); m_DK[0] = mul_inv(m_EK[48]); m_DK[1] = -m_EK[49]; m_DK[2] = -m_EK[50]; m_DK[3] = mul_inv(m_EK[51]); for(size_t i = 0; i != 8*6; i += 6) { m_DK[i+4] = m_EK[46-i]; m_DK[i+5] = m_EK[47-i]; m_DK[i+6] = mul_inv(m_EK[42-i]); m_DK[i+7] = -m_EK[44-i]; m_DK[i+8] = -m_EK[43-i]; m_DK[i+9] = mul_inv(m_EK[45-i]); } std::swap(m_DK[49], m_DK[50]); CT::unpoison(key, 16); CT::unpoison(m_EK.data(), 52); CT::unpoison(m_DK.data(), 52); } void IDEA::clear() { zap(m_EK); zap(m_DK); } } /* * IDEA in SSE2 * (C) 2009 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace { BOTAN_FUNC_ISA("sse2") inline __m128i mul(__m128i X, uint16_t K_16) { const __m128i zeros = _mm_set1_epi16(0); const __m128i ones = _mm_set1_epi16(1); const __m128i K = _mm_set1_epi16(K_16); const __m128i X_is_zero = _mm_cmpeq_epi16(X, zeros); const __m128i K_is_zero = _mm_cmpeq_epi16(K, zeros); const __m128i mul_lo = _mm_mullo_epi16(X, K); const __m128i mul_hi = _mm_mulhi_epu16(X, K); __m128i T = _mm_sub_epi16(mul_lo, mul_hi); // Unsigned compare; cmp = 1 if mul_lo < mul_hi else 0 const __m128i subs = _mm_subs_epu16(mul_hi, mul_lo); const __m128i cmp = _mm_min_epu8( _mm_or_si128(subs, _mm_srli_epi16(subs, 8)), ones); T = _mm_add_epi16(T, cmp); /* Selection: if X[i] is zero then assign 1-K if K is zero then assign 1-X[i] Could if() off value of K_16 for the second, but this gives a constant time implementation which is a nice bonus. */ T = _mm_or_si128( _mm_andnot_si128(X_is_zero, T), _mm_and_si128(_mm_sub_epi16(ones, K), X_is_zero)); T = _mm_or_si128( _mm_andnot_si128(K_is_zero, T), _mm_and_si128(_mm_sub_epi16(ones, X), K_is_zero)); return T; } /* * 4x8 matrix transpose * * FIXME: why do I need the extra set of unpack_epi32 here? Inverse in * transpose_out doesn't need it. Something with the shuffle? Removing * that extra unpack could easily save 3-4 cycles per block, and would * also help a lot with register pressure on 32-bit x86 */ BOTAN_FUNC_ISA("sse2") void transpose_in(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) { __m128i T0 = _mm_unpackhi_epi32(B0, B1); __m128i T1 = _mm_unpacklo_epi32(B0, B1); __m128i T2 = _mm_unpackhi_epi32(B2, B3); __m128i T3 = _mm_unpacklo_epi32(B2, B3); __m128i T4 = _mm_unpacklo_epi32(T0, T1); __m128i T5 = _mm_unpackhi_epi32(T0, T1); __m128i T6 = _mm_unpacklo_epi32(T2, T3); __m128i T7 = _mm_unpackhi_epi32(T2, T3); T0 = _mm_shufflehi_epi16(T4, _MM_SHUFFLE(1, 3, 0, 2)); T1 = _mm_shufflehi_epi16(T5, _MM_SHUFFLE(1, 3, 0, 2)); T2 = _mm_shufflehi_epi16(T6, _MM_SHUFFLE(1, 3, 0, 2)); T3 = _mm_shufflehi_epi16(T7, _MM_SHUFFLE(1, 3, 0, 2)); T0 = _mm_shufflelo_epi16(T0, _MM_SHUFFLE(1, 3, 0, 2)); T1 = _mm_shufflelo_epi16(T1, _MM_SHUFFLE(1, 3, 0, 2)); T2 = _mm_shufflelo_epi16(T2, _MM_SHUFFLE(1, 3, 0, 2)); T3 = _mm_shufflelo_epi16(T3, _MM_SHUFFLE(1, 3, 0, 2)); T0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 1, 2, 0)); T1 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 1, 2, 0)); T2 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(3, 1, 2, 0)); T3 = _mm_shuffle_epi32(T3, _MM_SHUFFLE(3, 1, 2, 0)); B0 = _mm_unpacklo_epi64(T0, T2); B1 = _mm_unpackhi_epi64(T0, T2); B2 = _mm_unpacklo_epi64(T1, T3); B3 = _mm_unpackhi_epi64(T1, T3); } /* * 4x8 matrix transpose (reverse) */ BOTAN_FUNC_ISA("sse2") void transpose_out(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) { __m128i T0 = _mm_unpacklo_epi64(B0, B1); __m128i T1 = _mm_unpacklo_epi64(B2, B3); __m128i T2 = _mm_unpackhi_epi64(B0, B1); __m128i T3 = _mm_unpackhi_epi64(B2, B3); T0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 1, 2, 0)); T1 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 1, 2, 0)); T2 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(3, 1, 2, 0)); T3 = _mm_shuffle_epi32(T3, _MM_SHUFFLE(3, 1, 2, 0)); T0 = _mm_shufflehi_epi16(T0, _MM_SHUFFLE(3, 1, 2, 0)); T1 = _mm_shufflehi_epi16(T1, _MM_SHUFFLE(3, 1, 2, 0)); T2 = _mm_shufflehi_epi16(T2, _MM_SHUFFLE(3, 1, 2, 0)); T3 = _mm_shufflehi_epi16(T3, _MM_SHUFFLE(3, 1, 2, 0)); T0 = _mm_shufflelo_epi16(T0, _MM_SHUFFLE(3, 1, 2, 0)); T1 = _mm_shufflelo_epi16(T1, _MM_SHUFFLE(3, 1, 2, 0)); T2 = _mm_shufflelo_epi16(T2, _MM_SHUFFLE(3, 1, 2, 0)); T3 = _mm_shufflelo_epi16(T3, _MM_SHUFFLE(3, 1, 2, 0)); B0 = _mm_unpacklo_epi32(T0, T1); B1 = _mm_unpackhi_epi32(T0, T1); B2 = _mm_unpacklo_epi32(T2, T3); B3 = _mm_unpackhi_epi32(T2, T3); } } /* * 8 wide IDEA encryption/decryption in SSE2 */ BOTAN_FUNC_ISA("sse2") void IDEA::sse2_idea_op_8(const uint8_t in[64], uint8_t out[64], const uint16_t EK[52]) const { CT::poison(in, 64); CT::poison(out, 64); CT::poison(EK, 52); const __m128i* in_mm = reinterpret_cast(in); __m128i B0 = _mm_loadu_si128(in_mm + 0); __m128i B1 = _mm_loadu_si128(in_mm + 1); __m128i B2 = _mm_loadu_si128(in_mm + 2); __m128i B3 = _mm_loadu_si128(in_mm + 3); transpose_in(B0, B1, B2, B3); // byte swap B0 = _mm_or_si128(_mm_slli_epi16(B0, 8), _mm_srli_epi16(B0, 8)); B1 = _mm_or_si128(_mm_slli_epi16(B1, 8), _mm_srli_epi16(B1, 8)); B2 = _mm_or_si128(_mm_slli_epi16(B2, 8), _mm_srli_epi16(B2, 8)); B3 = _mm_or_si128(_mm_slli_epi16(B3, 8), _mm_srli_epi16(B3, 8)); for(size_t i = 0; i != 8; ++i) { B0 = mul(B0, EK[6*i+0]); B1 = _mm_add_epi16(B1, _mm_set1_epi16(EK[6*i+1])); B2 = _mm_add_epi16(B2, _mm_set1_epi16(EK[6*i+2])); B3 = mul(B3, EK[6*i+3]); __m128i T0 = B2; B2 = _mm_xor_si128(B2, B0); B2 = mul(B2, EK[6*i+4]); __m128i T1 = B1; B1 = _mm_xor_si128(B1, B3); B1 = _mm_add_epi16(B1, B2); B1 = mul(B1, EK[6*i+5]); B2 = _mm_add_epi16(B2, B1); B0 = _mm_xor_si128(B0, B1); B1 = _mm_xor_si128(B1, T0); B3 = _mm_xor_si128(B3, B2); B2 = _mm_xor_si128(B2, T1); } B0 = mul(B0, EK[48]); B1 = _mm_add_epi16(B1, _mm_set1_epi16(EK[50])); B2 = _mm_add_epi16(B2, _mm_set1_epi16(EK[49])); B3 = mul(B3, EK[51]); // byte swap B0 = _mm_or_si128(_mm_slli_epi16(B0, 8), _mm_srli_epi16(B0, 8)); B1 = _mm_or_si128(_mm_slli_epi16(B1, 8), _mm_srli_epi16(B1, 8)); B2 = _mm_or_si128(_mm_slli_epi16(B2, 8), _mm_srli_epi16(B2, 8)); B3 = _mm_or_si128(_mm_slli_epi16(B3, 8), _mm_srli_epi16(B3, 8)); transpose_out(B0, B2, B1, B3); __m128i* out_mm = reinterpret_cast<__m128i*>(out); _mm_storeu_si128(out_mm + 0, B0); _mm_storeu_si128(out_mm + 1, B2); _mm_storeu_si128(out_mm + 2, B1); _mm_storeu_si128(out_mm + 3, B3); CT::unpoison(in, 64); CT::unpoison(out, 64); CT::unpoison(EK, 52); } } /* * ISO-9796-2 - Digital signature schemes giving message recovery schemes 2 and 3 * (C) 2016 Tobias Niemann, Hackmanit GmbH * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { secure_vector iso9796_encoding(const secure_vector& msg, size_t output_bits, std::unique_ptr& hash, size_t SALT_SIZE, bool implicit, RandomNumberGenerator& rng) { const size_t output_length = (output_bits + 7) / 8; //set trailer length size_t tLength = 1; if(!implicit) { tLength = 2; } const size_t HASH_SIZE = hash->output_length(); if(output_length <= HASH_SIZE + SALT_SIZE + tLength) { throw Encoding_Error("ISO9796-2::encoding_of: Output length is too small"); } //calculate message capacity const size_t capacity = output_length - HASH_SIZE - SALT_SIZE - tLength - 1; //msg1 is the recoverable and msg2 the unrecoverable message part. secure_vector msg1; secure_vector msg2; if(msg.size() > capacity) { msg1 = secure_vector(msg.begin(), msg.begin() + capacity); msg2 = secure_vector(msg.begin() + capacity, msg.end()); hash->update(msg2); } else { msg1 = msg; } msg2 = hash->final(); //compute H(C||msg1 ||H(msg2)||S) const size_t msgLength = msg1.size(); secure_vector salt = rng.random_vec(SALT_SIZE); hash->update_be(static_cast(msgLength) * 8); hash->update(msg1); hash->update(msg2); hash->update(salt); secure_vector H = hash->final(); secure_vector EM(output_length); //compute message offset. const size_t offset = output_length - HASH_SIZE - SALT_SIZE - tLength - msgLength - 1; //insert message border (0x01), msg1 and salt into the output buffer EM[offset] = 0x01; buffer_insert(EM, offset + 1, msg1); buffer_insert(EM, offset + 1 + msgLength, salt); //apply mask mgf1_mask(*hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - tLength); buffer_insert(EM, output_length - HASH_SIZE - tLength, H); //set implicit/ISO trailer if(!implicit) { uint8_t hash_id = ieee1363_hash_id(hash->name()); if(!hash_id) { throw Encoding_Error("ISO9796-2::encoding_of: no hash identifier for " + hash->name()); } EM[output_length - 1] = 0xCC; EM[output_length - 2] = hash_id; } else { EM[output_length - 1] = 0xBC; } //clear the leftmost bit (confer bouncy castle) EM[0] &= 0x7F; return EM; } bool iso9796_verification(const secure_vector& const_coded, const secure_vector& raw, size_t key_bits, std::unique_ptr& hash, size_t SALT_SIZE) { const size_t HASH_SIZE = hash->output_length(); const size_t KEY_BYTES = (key_bits + 7) / 8; if(const_coded.size() != KEY_BYTES) { return false; } //get trailer length size_t tLength; if(const_coded[const_coded.size() - 1] == 0xBC) { tLength = 1; } else { uint8_t hash_id = ieee1363_hash_id(hash->name()); if((!const_coded[const_coded.size() - 2]) || (const_coded[const_coded.size() - 2] != hash_id) || (const_coded[const_coded.size() - 1] != 0xCC)) { return false; //in case of wrong ISO trailer. } tLength = 2; } secure_vector coded = const_coded; CT::poison(coded.data(), coded.size()); //remove mask uint8_t* DB = coded.data(); const size_t DB_size = coded.size() - HASH_SIZE - tLength; const uint8_t* H = &coded[DB_size]; mgf1_mask(*hash, H, HASH_SIZE, DB, DB_size); //clear the leftmost bit (confer bouncy castle) DB[0] &= 0x7F; //recover msg1 and salt size_t msg1_offset = 1; auto waiting_for_delim = CT::Mask::set(); auto bad_input = CT::Mask::cleared(); for(size_t j = 0; j < DB_size; ++j) { const auto is_zero = CT::Mask::is_zero(DB[j]); const auto is_one = CT::Mask::is_equal(DB[j], 0x01); const auto add_m = waiting_for_delim & is_zero; bad_input |= waiting_for_delim & ~(is_zero | is_one); msg1_offset += add_m.if_set_return(1); waiting_for_delim &= is_zero; } //invalid, if delimiter 0x01 was not found or msg1_offset is too big bad_input |= waiting_for_delim; bad_input |= CT::Mask::is_lt(coded.size(), tLength + HASH_SIZE + msg1_offset + SALT_SIZE); //in case that msg1_offset is too big, just continue with offset = 0. msg1_offset = CT::Mask::expand(bad_input.value()).if_not_set_return(msg1_offset); CT::unpoison(coded.data(), coded.size()); CT::unpoison(msg1_offset); secure_vector msg1(coded.begin() + msg1_offset, coded.end() - tLength - HASH_SIZE - SALT_SIZE); secure_vector salt(coded.begin() + msg1_offset + msg1.size(), coded.end() - tLength - HASH_SIZE); //compute H2(C||msg1||H(msg2)||S*). * indicates a recovered value const size_t capacity = (key_bits - 2 + 7) / 8 - HASH_SIZE - SALT_SIZE - tLength - 1; secure_vector msg1raw; secure_vector msg2; if(raw.size() > capacity) { msg1raw = secure_vector (raw.begin(), raw.begin() + capacity); msg2 = secure_vector (raw.begin() + capacity, raw.end()); hash->update(msg2); } else { msg1raw = raw; } msg2 = hash->final(); const uint64_t msg1rawLength = msg1raw.size(); hash->update_be(msg1rawLength * 8); hash->update(msg1raw); hash->update(msg2); hash->update(salt); secure_vector H3 = hash->final(); //compute H3(C*||msg1*||H(msg2)||S*) * indicates a recovered value const uint64_t msgLength = msg1.size(); hash->update_be(msgLength * 8); hash->update(msg1); hash->update(msg2); hash->update(salt); secure_vector H2 = hash->final(); //check if H3 == H2 bad_input |= CT::Mask::is_zero(ct_compare_u8(H3.data(), H2.data(), HASH_SIZE)); CT::unpoison(bad_input); return (bad_input.is_set() == false); } } EMSA* ISO_9796_DS2::clone() { return new ISO_9796_DS2(m_hash->clone(), m_implicit, m_SALT_SIZE); } /* * ISO-9796-2 signature scheme 2 * DS 2 is probabilistic */ void ISO_9796_DS2::update(const uint8_t input[], size_t length) { //need to buffer message completely, before digest m_msg_buffer.insert(m_msg_buffer.end(), input, input+length); } /* * Return the raw (unencoded) data */ secure_vector ISO_9796_DS2::raw_data() { secure_vector retbuffer = m_msg_buffer; m_msg_buffer.clear(); return retbuffer; } /* * ISO-9796-2 scheme 2 encode operation */ secure_vector ISO_9796_DS2::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator& rng) { return iso9796_encoding(msg, output_bits, m_hash, m_SALT_SIZE, m_implicit, rng); } /* * ISO-9796-2 scheme 2 verify operation */ bool ISO_9796_DS2::verify(const secure_vector& const_coded, const secure_vector& raw, size_t key_bits) { return iso9796_verification(const_coded, raw, key_bits, m_hash, m_SALT_SIZE); } /* * Return the SCAN name */ std::string ISO_9796_DS2::name() const { return "ISO_9796_DS2(" + m_hash->name() + "," + (m_implicit ? "imp" : "exp") + "," + std::to_string(m_SALT_SIZE) + ")"; } EMSA* ISO_9796_DS3::clone() { return new ISO_9796_DS3(m_hash->clone(), m_implicit); } /* * ISO-9796-2 signature scheme 3 * DS 3 is deterministic and equals DS2 without salt */ void ISO_9796_DS3::update(const uint8_t input[], size_t length) { //need to buffer message completely, before digest m_msg_buffer.insert(m_msg_buffer.end(), input, input+length); } /* * Return the raw (unencoded) data */ secure_vector ISO_9796_DS3::raw_data() { secure_vector retbuffer = m_msg_buffer; m_msg_buffer.clear(); return retbuffer; } /* * ISO-9796-2 scheme 3 encode operation */ secure_vector ISO_9796_DS3::encoding_of(const secure_vector& msg, size_t output_bits, RandomNumberGenerator& rng) { return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng); } /* * ISO-9796-2 scheme 3 verify operation */ bool ISO_9796_DS3::verify(const secure_vector& const_coded, const secure_vector& raw, size_t key_bits) { return iso9796_verification(const_coded, raw, key_bits, m_hash, 0); } /* * Return the SCAN name */ std::string ISO_9796_DS3::name() const { return "ISO_9796_DS3(" + m_hash->name() + "," + (m_implicit ? "imp" : "exp") + ")"; } } /* * KASUMI * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * KASUMI S-Boxes */ alignas(64) const uint8_t KASUMI_SBOX_S7[128] = { 0x36, 0x32, 0x3E, 0x38, 0x16, 0x22, 0x5E, 0x60, 0x26, 0x06, 0x3F, 0x5D, 0x02, 0x12, 0x7B, 0x21, 0x37, 0x71, 0x27, 0x72, 0x15, 0x43, 0x41, 0x0C, 0x2F, 0x49, 0x2E, 0x1B, 0x19, 0x6F, 0x7C, 0x51, 0x35, 0x09, 0x79, 0x4F, 0x34, 0x3C, 0x3A, 0x30, 0x65, 0x7F, 0x28, 0x78, 0x68, 0x46, 0x47, 0x2B, 0x14, 0x7A, 0x48, 0x3D, 0x17, 0x6D, 0x0D, 0x64, 0x4D, 0x01, 0x10, 0x07, 0x52, 0x0A, 0x69, 0x62, 0x75, 0x74, 0x4C, 0x0B, 0x59, 0x6A, 0x00, 0x7D, 0x76, 0x63, 0x56, 0x45, 0x1E, 0x39, 0x7E, 0x57, 0x70, 0x33, 0x11, 0x05, 0x5F, 0x0E, 0x5A, 0x54, 0x5B, 0x08, 0x23, 0x67, 0x20, 0x61, 0x1C, 0x42, 0x66, 0x1F, 0x1A, 0x2D, 0x4B, 0x04, 0x55, 0x5C, 0x25, 0x4A, 0x50, 0x31, 0x44, 0x1D, 0x73, 0x2C, 0x40, 0x6B, 0x6C, 0x18, 0x6E, 0x53, 0x24, 0x4E, 0x2A, 0x13, 0x0F, 0x29, 0x58, 0x77, 0x3B, 0x03 }; alignas(64) const uint16_t KASUMI_SBOX_S9[512] = { 0x00A7, 0x00EF, 0x00A1, 0x017B, 0x0187, 0x014E, 0x0009, 0x0152, 0x0026, 0x00E2, 0x0030, 0x0166, 0x01C4, 0x0181, 0x005A, 0x018D, 0x00B7, 0x00FD, 0x0093, 0x014B, 0x019F, 0x0154, 0x0033, 0x016A, 0x0132, 0x01F4, 0x0106, 0x0052, 0x00D8, 0x009F, 0x0164, 0x00B1, 0x00AF, 0x00F1, 0x01E9, 0x0025, 0x00CE, 0x0011, 0x0000, 0x014D, 0x002C, 0x00FE, 0x017A, 0x003A, 0x008F, 0x00DC, 0x0051, 0x0190, 0x005F, 0x0003, 0x013B, 0x00F5, 0x0036, 0x00EB, 0x00DA, 0x0195, 0x01D8, 0x0108, 0x00AC, 0x01EE, 0x0173, 0x0122, 0x018F, 0x004C, 0x00A5, 0x00C5, 0x018B, 0x0079, 0x0101, 0x01E0, 0x01A7, 0x00D4, 0x00F0, 0x001C, 0x01CE, 0x00B0, 0x0196, 0x01FB, 0x0120, 0x00DF, 0x01F5, 0x0197, 0x00F9, 0x0109, 0x0059, 0x00BA, 0x00DD, 0x01AC, 0x00A4, 0x004A, 0x01B8, 0x00C4, 0x01CA, 0x01A5, 0x015E, 0x00A3, 0x00E8, 0x009E, 0x0086, 0x0162, 0x000D, 0x00FA, 0x01EB, 0x008E, 0x00BF, 0x0045, 0x00C1, 0x01A9, 0x0098, 0x00E3, 0x016E, 0x0087, 0x0158, 0x012C, 0x0114, 0x00F2, 0x01B5, 0x0140, 0x0071, 0x0116, 0x000B, 0x00F3, 0x0057, 0x013D, 0x0024, 0x005D, 0x01F0, 0x001B, 0x01E7, 0x01BE, 0x01E2, 0x0029, 0x0044, 0x009C, 0x01C9, 0x0083, 0x0146, 0x0193, 0x0153, 0x0014, 0x0027, 0x0073, 0x01BA, 0x007C, 0x01DB, 0x0180, 0x01FC, 0x0035, 0x0070, 0x00AA, 0x01DF, 0x0097, 0x007E, 0x00A9, 0x0049, 0x010C, 0x0117, 0x0141, 0x00A8, 0x016C, 0x016B, 0x0124, 0x002E, 0x01F3, 0x0189, 0x0147, 0x0144, 0x0018, 0x01C8, 0x010B, 0x009D, 0x01CC, 0x01E8, 0x01AA, 0x0135, 0x00E5, 0x01B7, 0x01FA, 0x00D0, 0x010F, 0x015D, 0x0191, 0x01B2, 0x00EC, 0x0010, 0x00D1, 0x0167, 0x0034, 0x0038, 0x0078, 0x00C7, 0x0115, 0x01D1, 0x01A0, 0x00FC, 0x011F, 0x00F6, 0x0006, 0x0053, 0x0131, 0x01A4, 0x0159, 0x0099, 0x01F6, 0x0041, 0x003D, 0x00F4, 0x011A, 0x00AD, 0x00DE, 0x01A2, 0x0043, 0x0182, 0x0170, 0x0105, 0x0065, 0x01DC, 0x0123, 0x00C3, 0x01AE, 0x0031, 0x004F, 0x00A6, 0x014A, 0x0118, 0x017F, 0x0175, 0x0080, 0x017E, 0x0198, 0x009B, 0x01EF, 0x016F, 0x0184, 0x0112, 0x006B, 0x01CB, 0x01A1, 0x003E, 0x01C6, 0x0084, 0x00E1, 0x00CB, 0x013C, 0x00EA, 0x000E, 0x012D, 0x005B, 0x01F7, 0x011E, 0x01A8, 0x00D3, 0x015B, 0x0133, 0x008C, 0x0176, 0x0023, 0x0067, 0x007D, 0x01AB, 0x0013, 0x00D6, 0x01C5, 0x0092, 0x01F2, 0x013A, 0x01BC, 0x00E6, 0x0100, 0x0149, 0x00C6, 0x011D, 0x0032, 0x0074, 0x004E, 0x019A, 0x000A, 0x00CD, 0x01FE, 0x00AB, 0x00E7, 0x002D, 0x008B, 0x01D3, 0x001D, 0x0056, 0x01F9, 0x0020, 0x0048, 0x001A, 0x0156, 0x0096, 0x0139, 0x01EA, 0x01AF, 0x00EE, 0x019B, 0x0145, 0x0095, 0x01D9, 0x0028, 0x0077, 0x00AE, 0x0163, 0x00B9, 0x00E9, 0x0185, 0x0047, 0x01C0, 0x0111, 0x0174, 0x0037, 0x006E, 0x00B2, 0x0142, 0x000C, 0x01D5, 0x0188, 0x0171, 0x00BE, 0x0001, 0x006D, 0x0177, 0x0089, 0x00B5, 0x0058, 0x004B, 0x0134, 0x0104, 0x01E4, 0x0062, 0x0110, 0x0172, 0x0113, 0x019C, 0x006F, 0x0150, 0x013E, 0x0004, 0x01F8, 0x01EC, 0x0103, 0x0130, 0x004D, 0x0151, 0x01B3, 0x0015, 0x0165, 0x012F, 0x014C, 0x01E3, 0x0012, 0x002F, 0x0055, 0x0019, 0x01F1, 0x01DA, 0x0121, 0x0064, 0x010D, 0x0128, 0x01DE, 0x010E, 0x006A, 0x001F, 0x0068, 0x01B1, 0x0054, 0x019E, 0x01E6, 0x018A, 0x0060, 0x0063, 0x009A, 0x01FF, 0x0094, 0x019D, 0x0169, 0x0199, 0x00FF, 0x00A2, 0x00D7, 0x012E, 0x00C9, 0x010A, 0x015F, 0x0157, 0x0090, 0x01B9, 0x016D, 0x006C, 0x012A, 0x00FB, 0x0022, 0x00B6, 0x01FD, 0x008A, 0x00D2, 0x014F, 0x0085, 0x0137, 0x0160, 0x0148, 0x008D, 0x018C, 0x015A, 0x007B, 0x013F, 0x01C2, 0x0119, 0x01AD, 0x00E4, 0x01BB, 0x01E1, 0x005C, 0x0194, 0x01E5, 0x01A6, 0x00F8, 0x0129, 0x0017, 0x00D5, 0x0082, 0x01D2, 0x0016, 0x00D9, 0x011B, 0x0046, 0x0126, 0x0168, 0x01A3, 0x007F, 0x0138, 0x0179, 0x0007, 0x01D4, 0x00C2, 0x0002, 0x0075, 0x0127, 0x01CF, 0x0102, 0x00E0, 0x01BF, 0x00F7, 0x00BB, 0x0050, 0x018E, 0x011C, 0x0161, 0x0069, 0x0186, 0x012B, 0x01D7, 0x01D6, 0x00B8, 0x0039, 0x00C8, 0x015C, 0x003F, 0x00CC, 0x00BC, 0x0021, 0x01C3, 0x0061, 0x001E, 0x0136, 0x00DB, 0x005E, 0x00A0, 0x0081, 0x01ED, 0x0040, 0x00B3, 0x0107, 0x0066, 0x00BD, 0x00CF, 0x0072, 0x0192, 0x01B6, 0x01DD, 0x0183, 0x007A, 0x00C0, 0x002A, 0x017D, 0x0005, 0x0091, 0x0076, 0x00B4, 0x01C1, 0x0125, 0x0143, 0x0088, 0x017C, 0x002B, 0x0042, 0x003C, 0x01C7, 0x0155, 0x01BD, 0x00CA, 0x01B0, 0x0008, 0x00ED, 0x000F, 0x0178, 0x01B4, 0x01D0, 0x003B, 0x01CD }; /* * KASUMI FI Function */ uint16_t FI(uint16_t I, uint16_t K) { uint16_t D9 = (I >> 7); uint8_t D7 = (I & 0x7F); D9 = KASUMI_SBOX_S9[D9] ^ D7; D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); D7 ^= (K >> 9); D9 = KASUMI_SBOX_S9[D9 ^ (K & 0x1FF)] ^ D7; D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); return static_cast(D7 << 9) | D9; } } /* * KASUMI Encryption */ void KASUMI::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be(in, 0); uint16_t B1 = load_be(in, 1); uint16_t B2 = load_be(in, 2); uint16_t B3 = load_be(in, 3); for(size_t j = 0; j != 8; j += 2) { const uint16_t* K = &m_EK[8*j]; uint16_t R = B1 ^ (rotl<1>(B0) & K[0]); uint16_t L = B0 ^ (rotl<1>(R) | K[1]); L = FI(L ^ K[ 2], K[ 3]) ^ R; R = FI(R ^ K[ 4], K[ 5]) ^ L; L = FI(L ^ K[ 6], K[ 7]) ^ R; R = B2 ^= R; L = B3 ^= L; R = FI(R ^ K[10], K[11]) ^ L; L = FI(L ^ K[12], K[13]) ^ R; R = FI(R ^ K[14], K[15]) ^ L; R ^= (rotl<1>(L) & K[8]); L ^= (rotl<1>(R) | K[9]); B0 ^= L; B1 ^= R; } store_be(out, B0, B1, B2, B3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * KASUMI Decryption */ void KASUMI::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be(in, 0); uint16_t B1 = load_be(in, 1); uint16_t B2 = load_be(in, 2); uint16_t B3 = load_be(in, 3); for(size_t j = 0; j != 8; j += 2) { const uint16_t* K = &m_EK[8*(6-j)]; uint16_t L = B2, R = B3; L = FI(L ^ K[10], K[11]) ^ R; R = FI(R ^ K[12], K[13]) ^ L; L = FI(L ^ K[14], K[15]) ^ R; L ^= (rotl<1>(R) & K[8]); R ^= (rotl<1>(L) | K[9]); R = B0 ^= R; L = B1 ^= L; L ^= (rotl<1>(R) & K[0]); R ^= (rotl<1>(L) | K[1]); R = FI(R ^ K[2], K[3]) ^ L; L = FI(L ^ K[4], K[5]) ^ R; R = FI(R ^ K[6], K[7]) ^ L; B2 ^= L; B3 ^= R; } store_be(out, B0, B1, B2, B3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * KASUMI Key Schedule */ void KASUMI::key_schedule(const uint8_t key[], size_t) { static const uint16_t RC[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xFEDC, 0xBA98, 0x7654, 0x3210 }; secure_vector K(16); for(size_t i = 0; i != 8; ++i) { K[i] = load_be(key, i); K[i+8] = K[i] ^ RC[i]; } m_EK.resize(64); for(size_t i = 0; i != 8; ++i) { m_EK[8*i ] = rotl<2>(K[(i+0) % 8]); m_EK[8*i+1] = rotl<1>(K[(i+2) % 8 + 8]); m_EK[8*i+2] = rotl<5>(K[(i+1) % 8]); m_EK[8*i+3] = K[(i+4) % 8 + 8]; m_EK[8*i+4] = rotl<8>(K[(i+5) % 8]); m_EK[8*i+5] = K[(i+3) % 8 + 8]; m_EK[8*i+6] = rotl<13>(K[(i+6) % 8]); m_EK[8*i+7] = K[(i+7) % 8 + 8]; } } void KASUMI::clear() { zap(m_EK); } } /* * KDF Retrieval * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_HKDF) #endif #if defined(BOTAN_HAS_KDF1) #endif #if defined(BOTAN_HAS_KDF2) #endif #if defined(BOTAN_HAS_KDF1_18033) #endif #if defined(BOTAN_HAS_TLS_V10_PRF) || defined(BOTAN_HAS_TLS_V12_PRF) #endif #if defined(BOTAN_HAS_X942_PRF) #endif #if defined(BOTAN_HAS_SP800_108) #endif #if defined(BOTAN_HAS_SP800_56A) #endif #if defined(BOTAN_HAS_SP800_56C) #endif namespace Botan { namespace { template std::unique_ptr kdf_create_mac_or_hash(const std::string& nm) { if(auto mac = MessageAuthenticationCode::create(nm)) return std::unique_ptr(new KDF_Type(mac.release())); if(auto mac = MessageAuthenticationCode::create("HMAC(" + nm + ")")) return std::unique_ptr(new KDF_Type(mac.release())); return nullptr; } } std::unique_ptr KDF::create(const std::string& algo_spec, const std::string& provider) { const SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_HKDF) if(req.algo_name() == "HKDF" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } if(req.algo_name() == "HKDF-Extract" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } if(req.algo_name() == "HKDF-Expand" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } #endif #if defined(BOTAN_HAS_KDF2) if(req.algo_name() == "KDF2" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { if(auto hash = HashFunction::create(req.arg(0))) return std::unique_ptr(new KDF2(hash.release())); } } #endif #if defined(BOTAN_HAS_KDF1_18033) if(req.algo_name() == "KDF1-18033" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { if(auto hash = HashFunction::create(req.arg(0))) return std::unique_ptr(new KDF1_18033(hash.release())); } } #endif #if defined(BOTAN_HAS_KDF1) if(req.algo_name() == "KDF1" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { if(auto hash = HashFunction::create(req.arg(0))) return std::unique_ptr(new KDF1(hash.release())); } } #endif #if defined(BOTAN_HAS_TLS_V10_PRF) if(req.algo_name() == "TLS-PRF" && req.arg_count() == 0) { if(provider.empty() || provider == "base") { auto hmac_md5 = MessageAuthenticationCode::create("HMAC(MD5)"); auto hmac_sha1 = MessageAuthenticationCode::create("HMAC(SHA-1)"); if(hmac_md5 && hmac_sha1) return std::unique_ptr(new TLS_PRF(std::move(hmac_md5), std::move(hmac_sha1))); } } #endif #if defined(BOTAN_HAS_TLS_V12_PRF) if(req.algo_name() == "TLS-12-PRF" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } #endif #if defined(BOTAN_HAS_X942_PRF) if(req.algo_name() == "X9.42-PRF" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return std::unique_ptr(new X942_PRF(req.arg(0))); } } #endif #if defined(BOTAN_HAS_SP800_108) if(req.algo_name() == "SP800-108-Counter" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } if(req.algo_name() == "SP800-108-Feedback" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } if(req.algo_name() == "SP800-108-Pipeline" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { return kdf_create_mac_or_hash(req.arg(0)); } } #endif #if defined(BOTAN_HAS_SP800_56A) if(req.algo_name() == "SP800-56A" && req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) return std::unique_ptr(new SP800_56A_Hash(hash.release())); if(auto mac = MessageAuthenticationCode::create(req.arg(0))) return std::unique_ptr(new SP800_56A_HMAC(mac.release())); } #endif #if defined(BOTAN_HAS_SP800_56C) if(req.algo_name() == "SP800-56C" && req.arg_count() == 1) { std::unique_ptr exp(kdf_create_mac_or_hash(req.arg(0))); if(exp) { if(auto mac = MessageAuthenticationCode::create(req.arg(0))) return std::unique_ptr(new SP800_56C(mac.release(), exp.release())); if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) return std::unique_ptr(new SP800_56C(mac.release(), exp.release())); } } #endif BOTAN_UNUSED(req); BOTAN_UNUSED(provider); return nullptr; } //static std::unique_ptr KDF::create_or_throw(const std::string& algo, const std::string& provider) { if(auto kdf = KDF::create(algo, provider)) { return kdf; } throw Lookup_Error("KDF", algo, provider); } std::vector KDF::providers(const std::string& algo_spec) { return probe_providers_of(algo_spec, { "base" }); } KDF* get_kdf(const std::string& algo_spec) { SCAN_Name request(algo_spec); if(request.algo_name() == "Raw") return nullptr; // No KDF //return KDF::create_or_throw(algo_spec).release(); auto kdf = KDF::create(algo_spec); if(!kdf) throw Algorithm_Not_Found(algo_spec); return kdf.release(); } } /* * KDF1 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t KDF1::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { m_hash->update(secret, secret_len); m_hash->update(label, label_len); m_hash->update(salt, salt_len); if(key_len < m_hash->output_length()) { secure_vector v = m_hash->final(); copy_mem(key, v.data(), key_len); return key_len; } m_hash->final(key); // FIXME: returns truncated output return m_hash->output_length(); } } /* * KDF1 from ISO 18033-2 * (C) 2016 Philipp Weber * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t KDF1_18033::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { uint32_t counter = 0; secure_vector h; size_t offset = 0; while(offset != key_len && counter != 0xFFFFFFFF) { m_hash->update(secret, secret_len); m_hash->update_be(counter++); m_hash->update(label, label_len); m_hash->update(salt, salt_len); m_hash->final(h); const size_t added = std::min(h.size(), key_len - offset); copy_mem(&key[offset], h.data(), added); offset += added; } // FIXME: returns truncated output return offset; } } /* * KDF2 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t KDF2::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { uint32_t counter = 1; secure_vector h; size_t offset = 0; while(offset != key_len && counter != 0) { m_hash->update(secret, secret_len); m_hash->update_be(counter++); m_hash->update(label, label_len); m_hash->update(salt, salt_len); m_hash->final(h); const size_t added = std::min(h.size(), key_len - offset); copy_mem(&key[offset], h.data(), added); offset += added; } // FIXME: returns truncated output return offset; } } /* * Keccak * (C) 2010,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr Keccak_1600::copy_state() const { return std::unique_ptr(new Keccak_1600(*this)); } Keccak_1600::Keccak_1600(size_t output_bits) : m_output_bits(output_bits), m_bitrate(1600 - 2*output_bits), m_S(25), m_S_pos(0) { // We only support the parameters for the SHA-3 proposal if(output_bits != 224 && output_bits != 256 && output_bits != 384 && output_bits != 512) throw Invalid_Argument("Keccak_1600: Invalid output length " + std::to_string(output_bits)); } std::string Keccak_1600::name() const { return "Keccak-1600(" + std::to_string(m_output_bits) + ")"; } HashFunction* Keccak_1600::clone() const { return new Keccak_1600(m_output_bits); } void Keccak_1600::clear() { zeroise(m_S); m_S_pos = 0; } void Keccak_1600::add_data(const uint8_t input[], size_t length) { m_S_pos = SHA_3::absorb(m_bitrate, m_S, m_S_pos, input, length); } void Keccak_1600::final_result(uint8_t output[]) { SHA_3::finish(m_bitrate, m_S, m_S_pos, 0x01, 0x80); /* * We never have to run the permutation again because we only support * limited output lengths */ copy_out_vec_le(output, m_output_bits/8, m_S); clear(); } } /* * Keypair Checks * (C) 1999-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace KeyPair { /* * Check an encryption key pair for consistency */ bool encryption_consistency_check(RandomNumberGenerator& rng, const Private_Key& private_key, const Public_Key& public_key, const std::string& padding) { PK_Encryptor_EME encryptor(public_key, rng, padding); PK_Decryptor_EME decryptor(private_key, rng, padding); /* Weird corner case, if the key is too small to encrypt anything at all. This can happen with very small RSA keys with PSS */ if(encryptor.maximum_input_size() == 0) return true; std::vector plaintext; rng.random_vec(plaintext, encryptor.maximum_input_size() - 1); std::vector ciphertext = encryptor.encrypt(plaintext, rng); if(ciphertext == plaintext) return false; std::vector decrypted = unlock(decryptor.decrypt(ciphertext)); return (plaintext == decrypted); } /* * Check a signature key pair for consistency */ bool signature_consistency_check(RandomNumberGenerator& rng, const Private_Key& private_key, const Public_Key& public_key, const std::string& padding) { PK_Signer signer(private_key, rng, padding); PK_Verifier verifier(public_key, padding); std::vector message(32); rng.randomize(message.data(), message.size()); std::vector signature; try { signature = signer.sign_message(message, rng); } catch(Encoding_Error&) { return false; } if(!verifier.verify_message(message, signature)) return false; // Now try to check a corrupt signature, ensure it does not succeed ++signature[0]; if(verifier.verify_message(message, signature)) return false; return true; } } } /* * Lion * (C) 1999-2007,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Lion Encryption */ void Lion::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_key1.empty() == false); const size_t LEFT_SIZE = left_size(); const size_t RIGHT_SIZE = right_size(); secure_vector buffer_vec(LEFT_SIZE); uint8_t* buffer = buffer_vec.data(); for(size_t i = 0; i != blocks; ++i) { xor_buf(buffer, in, m_key1.data(), LEFT_SIZE); m_cipher->set_key(buffer, LEFT_SIZE); m_cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); m_hash->update(out + LEFT_SIZE, RIGHT_SIZE); m_hash->final(buffer); xor_buf(out, in, buffer, LEFT_SIZE); xor_buf(buffer, out, m_key2.data(), LEFT_SIZE); m_cipher->set_key(buffer, LEFT_SIZE); m_cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); in += m_block_size; out += m_block_size; } } /* * Lion Decryption */ void Lion::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_key1.empty() == false); const size_t LEFT_SIZE = left_size(); const size_t RIGHT_SIZE = right_size(); secure_vector buffer_vec(LEFT_SIZE); uint8_t* buffer = buffer_vec.data(); for(size_t i = 0; i != blocks; ++i) { xor_buf(buffer, in, m_key2.data(), LEFT_SIZE); m_cipher->set_key(buffer, LEFT_SIZE); m_cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); m_hash->update(out + LEFT_SIZE, RIGHT_SIZE); m_hash->final(buffer); xor_buf(out, in, buffer, LEFT_SIZE); xor_buf(buffer, out, m_key1.data(), LEFT_SIZE); m_cipher->set_key(buffer, LEFT_SIZE); m_cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); in += m_block_size; out += m_block_size; } } /* * Lion Key Schedule */ void Lion::key_schedule(const uint8_t key[], size_t length) { clear(); const size_t half = length / 2; m_key1.resize(left_size()); m_key2.resize(left_size()); clear_mem(m_key1.data(), m_key1.size()); clear_mem(m_key2.data(), m_key2.size()); copy_mem(m_key1.data(), key, half); copy_mem(m_key2.data(), key + half, half); } /* * Return the name of this type */ std::string Lion::name() const { return "Lion(" + m_hash->name() + "," + m_cipher->name() + "," + std::to_string(block_size()) + ")"; } /* * Return a clone of this object */ BlockCipher* Lion::clone() const { return new Lion(m_hash->clone(), m_cipher->clone(), block_size()); } /* * Clear memory of sensitive data */ void Lion::clear() { zap(m_key1); zap(m_key2); m_hash->clear(); m_cipher->clear(); } /* * Lion Constructor */ Lion::Lion(HashFunction* hash, StreamCipher* cipher, size_t bs) : m_block_size(std::max(2*hash->output_length() + 1, bs)), m_hash(hash), m_cipher(cipher) { if(2*left_size() + 1 > m_block_size) throw Invalid_Argument(name() + ": Chosen block size is too small"); if(!m_cipher->valid_keylength(left_size())) throw Invalid_Argument(name() + ": This stream/hash combo is invalid"); } } /* * Mlock Allocator * (C) 2012,2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void* mlock_allocator::allocate(size_t num_elems, size_t elem_size) { if(!m_pool) return nullptr; const size_t n = num_elems * elem_size; if(n / elem_size != num_elems) return nullptr; // overflow! return m_pool->allocate(n); } bool mlock_allocator::deallocate(void* p, size_t num_elems, size_t elem_size) noexcept { if(!m_pool) return false; size_t n = num_elems * elem_size; /* We return nullptr in allocate if there was an overflow, so if an overflow occurs here we know the pointer was not allocated by this pool. */ if(n / elem_size != num_elems) return false; return m_pool->deallocate(p, n); } mlock_allocator::mlock_allocator() { const size_t mem_to_lock = OS::get_memory_locking_limit(); const size_t page_size = OS::system_page_size(); if(mem_to_lock > 0 && mem_to_lock % page_size == 0) { m_locked_pages = OS::allocate_locked_pages(mem_to_lock / page_size); if(m_locked_pages.size() > 0) { m_pool.reset(new Memory_Pool(m_locked_pages, page_size)); } } } mlock_allocator::~mlock_allocator() { if(m_pool) { m_pool.reset(); // OS::free_locked_pages scrubs the memory before free OS::free_locked_pages(m_locked_pages); } } mlock_allocator& mlock_allocator::instance() { static mlock_allocator mlock; return mlock; } } /* * Message Authentication Code base class * (C) 1999-2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_CBC_MAC) #endif #if defined(BOTAN_HAS_CMAC) #endif #if defined(BOTAN_HAS_GMAC) #endif #if defined(BOTAN_HAS_HMAC) #endif #if defined(BOTAN_HAS_POLY1305) #endif #if defined(BOTAN_HAS_SIPHASH) #endif #if defined(BOTAN_HAS_ANSI_X919_MAC) #endif namespace Botan { std::unique_ptr MessageAuthenticationCode::create(const std::string& algo_spec, const std::string& provider) { const SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_GMAC) if(req.algo_name() == "GMAC" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { if(auto bc = BlockCipher::create(req.arg(0))) return std::unique_ptr(new GMAC(bc.release())); } } #endif #if defined(BOTAN_HAS_HMAC) if(req.algo_name() == "HMAC" && req.arg_count() == 1) { // TODO OpenSSL if(provider.empty() || provider == "base") { if(auto h = HashFunction::create(req.arg(0))) return std::unique_ptr(new HMAC(h.release())); } } #endif #if defined(BOTAN_HAS_POLY1305) if(req.algo_name() == "Poly1305" && req.arg_count() == 0) { if(provider.empty() || provider == "base") return std::unique_ptr(new Poly1305); } #endif #if defined(BOTAN_HAS_SIPHASH) if(req.algo_name() == "SipHash") { if(provider.empty() || provider == "base") { return std::unique_ptr( new SipHash(req.arg_as_integer(0, 2), req.arg_as_integer(1, 4))); } } #endif #if defined(BOTAN_HAS_CMAC) if((req.algo_name() == "CMAC" || req.algo_name() == "OMAC") && req.arg_count() == 1) { // TODO: OpenSSL CMAC if(provider.empty() || provider == "base") { if(auto bc = BlockCipher::create(req.arg(0))) return std::unique_ptr(new CMAC(bc.release())); } } #endif #if defined(BOTAN_HAS_CBC_MAC) if(req.algo_name() == "CBC-MAC" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { if(auto bc = BlockCipher::create(req.arg(0))) return std::unique_ptr(new CBC_MAC(bc.release())); } } #endif #if defined(BOTAN_HAS_ANSI_X919_MAC) if(req.algo_name() == "X9.19-MAC") { if(provider.empty() || provider == "base") { return std::unique_ptr(new ANSI_X919_MAC); } } #endif BOTAN_UNUSED(req); BOTAN_UNUSED(provider); return nullptr; } std::vector MessageAuthenticationCode::providers(const std::string& algo_spec) { return probe_providers_of(algo_spec, {"base", "openssl"}); } //static std::unique_ptr MessageAuthenticationCode::create_or_throw(const std::string& algo, const std::string& provider) { if(auto mac = MessageAuthenticationCode::create(algo, provider)) { return mac; } throw Lookup_Error("MAC", algo, provider); } void MessageAuthenticationCode::start_msg(const uint8_t nonce[], size_t nonce_len) { BOTAN_UNUSED(nonce); if(nonce_len > 0) throw Invalid_IV_Length(name(), nonce_len); } /* * Default (deterministic) MAC verification operation */ bool MessageAuthenticationCode::verify_mac(const uint8_t mac[], size_t length) { secure_vector our_mac = final(); if(our_mac.size() != length) return false; return constant_time_compare(our_mac.data(), mac, length); } } /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) * */ namespace Botan { namespace { class binary_matrix final { public: binary_matrix(size_t m_rown, size_t m_coln); void row_xor(size_t a, size_t b); secure_vector row_reduced_echelon_form(); /** * return the coefficient out of F_2 */ uint32_t coef(size_t i, size_t j) { return (m_elem[(i) * m_rwdcnt + (j) / 32] >> (j % 32)) & 1; } void set_coef_to_one(size_t i, size_t j) { m_elem[(i) * m_rwdcnt + (j) / 32] |= (static_cast(1) << ((j) % 32)) ; } void toggle_coeff(size_t i, size_t j) { m_elem[(i) * m_rwdcnt + (j) / 32] ^= (static_cast(1) << ((j) % 32)) ; } size_t rows() const { return m_rown; } size_t columns() const { return m_coln; } private: size_t m_rown; // number of rows. size_t m_coln; // number of columns. size_t m_rwdcnt; // number of words in a row public: // TODO this should be private std::vector m_elem; }; binary_matrix::binary_matrix(size_t rown, size_t coln) { m_coln = coln; m_rown = rown; m_rwdcnt = 1 + ((m_coln - 1) / 32); m_elem = std::vector(m_rown * m_rwdcnt); } void binary_matrix::row_xor(size_t a, size_t b) { for(size_t i = 0; i != m_rwdcnt; i++) { m_elem[a*m_rwdcnt+i] ^= m_elem[b*m_rwdcnt+i]; } } //the matrix is reduced from LSB...(from right) secure_vector binary_matrix::row_reduced_echelon_form() { secure_vector perm(m_coln); for(size_t i = 0; i != m_coln; i++) { perm[i] = i; // initialize permutation. } uint32_t failcnt = 0; size_t max = m_coln - 1; for(size_t i = 0; i != m_rown; i++, max--) { bool found_row = false; for(size_t j = i; !found_row && j != m_rown; j++) { if(coef(j, max)) { if(i != j) //not needed as ith row is 0 and jth row is 1. { row_xor(i, j);//xor to the row.(swap)? } found_row = true; } } //if no row with a 1 found then swap last column and the column with no 1 down. if(!found_row) { perm[m_coln - m_rown - 1 - failcnt] = static_cast(max); failcnt++; if(!max) { perm.resize(0); } i--; } else { perm[i+m_coln - m_rown] = max; for(size_t j=i+1;j& L, RandomNumberGenerator& rng) { for(size_t i = 0; i != L.size(); ++i) { gf2m rnd = random_gf2m(rng); // no rejection sampling, but for useful code-based parameters with n <= 13 this seem tolerable std::swap(L[i], L[rnd % L.size()]); } } std::unique_ptr generate_R(std::vector &L, polyn_gf2m* g, std::shared_ptr sp_field, size_t code_length, size_t t) { //L- Support //t- Number of errors //n- Length of the Goppa code //m- The extension degree of the GF //g- The generator polynomial. const size_t r = t * sp_field->get_extension_degree(); binary_matrix H(r, code_length); for(size_t i = 0; i != code_length; i++) { gf2m x = g->eval(lex_to_gray(L[i]));//evaluate the polynomial at the point L[i]. x = sp_field->gf_inv(x); gf2m y = x; for(size_t j=0;jget_extension_degree();k++) { if(y & (1<get_extension_degree()+ k,i); } } y = sp_field->gf_mul(y,lex_to_gray(L[i])); } }//The H matrix is fed. secure_vector perm = H.row_reduced_echelon_form(); if(perm.size() == 0) { throw Invalid_State("McEliece keygen failed - could not bring matrix to row reduced echelon form"); } std::unique_ptr result(new binary_matrix(code_length-r, r)) ; for(size_t i = 0; i < result->rows(); ++i) { for(size_t j = 0; j < result->columns(); ++j) { if(H.coef(j, perm[i])) { result->toggle_coeff(i,j); } } } std::vector Laux(code_length); for(size_t i = 0; i < code_length; ++i) { Laux[i] = L[perm[i]]; } for(size_t i = 0; i < code_length; ++i) { L[i] = Laux[i]; } return result; } } McEliece_PrivateKey generate_mceliece_key(RandomNumberGenerator & rng, size_t ext_deg, size_t code_length, size_t t) { const size_t codimension = t * ext_deg; if(code_length <= codimension) { throw Invalid_Argument("invalid McEliece parameters"); } std::shared_ptr sp_field(new GF2m_Field(ext_deg)); //pick the support......... std::vector L(code_length); for(size_t i = 0; i != L.size(); i++) { L[i] = static_cast(i); } randomize_support(L, rng); polyn_gf2m g(sp_field); // create as zero bool success = false; std::unique_ptr R; do { // create a random irreducible polynomial g = polyn_gf2m(t, rng, sp_field); try { R = generate_R(L, &g, sp_field, code_length, t); success = true; } catch(const Invalid_State &) { } } while (!success); std::vector sqrtmod = polyn_gf2m::sqrt_mod_init( g); std::vector F = syndrome_init(g, L, static_cast(code_length)); // Each F[i] is the (precomputed) syndrome of the error vector with // a single '1' in i-th position. // We do not store the F[i] as polynomials of degree t , but // as binary vectors of length ext_deg * t (this will // speed up the syndrome computation) // std::vector H(bit_size_to_32bit_size(codimension) * code_length); uint32_t* sk = H.data(); for(size_t i = 0; i < code_length; ++i) { for(size_t l = 0; l < t; ++l) { const size_t k = (l * ext_deg) / 32; const uint8_t j = (l * ext_deg) % 32; sk[k] ^= static_cast(F[i].get_coef(l)) << j; if(j + ext_deg > 32) { sk[k + 1] ^= F[i].get_coef(l) >> (32 - j); } } sk += bit_size_to_32bit_size(codimension); } // We need the support L for decoding (decryption). In fact the // inverse is needed std::vector Linv(code_length) ; for(size_t i = 0; i != Linv.size(); ++i) { Linv[L[i]] = static_cast(i); } std::vector pubmat(R->m_elem.size() * 4); for(size_t i = 0; i < R->m_elem.size(); i++) { store_le(R->m_elem[i], &pubmat[i*4]); } return McEliece_PrivateKey(g, H, sqrtmod, Linv, pubmat); } } /* * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * * Botan is released under the Simplified BSD License (see license.txt) * */ namespace Botan { namespace { void patch_root_array(gf2m res_root_arr[], size_t res_root_arr_len, size_t root_pos) { volatile gf2m patch_elem = 0x01; volatile gf2m cond_mask = (root_pos == res_root_arr_len); cond_mask = expand_mask_16bit(cond_mask); cond_mask = ~cond_mask; /* now cond = 1 if not enough roots */ patch_elem &= cond_mask; for(size_t i = 0; i < res_root_arr_len; i++) { gf2m masked_patch_elem = (patch_elem++) & cond_mask; res_root_arr[i] ^= masked_patch_elem++; } } class gf2m_decomp_rootfind_state { public: gf2m_decomp_rootfind_state(const polyn_gf2m & p_polyn, size_t code_length); void calc_LiK(const polyn_gf2m & sigma); gf2m calc_Fxj_j_neq_0( const polyn_gf2m & sigma, gf2m j_gray); void calc_next_Aij(); void calc_Ai_zero(const polyn_gf2m & sigma); secure_vector find_roots(const polyn_gf2m & sigma); private: size_t m_code_length; secure_vector m_Lik; // size is outer_summands * m secure_vector m_Aij; // ... uint32_t m_outer_summands; gf2m m_j; gf2m m_j_gray; gf2m m_sigma_3_l; gf2m m_sigma_3_neq_0_mask; }; /* * !! Attention: assumes gf2m is 16bit !! */ #if 0 gf2m brootf_decomp_gray_to_lex(gf2m gray) { static_assert(sizeof(gf2m) == 2, "Expected size"); gf2m result = gray ^ (gray>>8); result ^= (result >> 4); result ^= (result >> 2); result ^= (result >> 1); return result; } #endif /** * calculates ceil((t-4)/5) = outer_summands - 1 */ uint32_t brootf_decomp_calc_sum_limit(uint32_t t) { uint32_t result; if(t < 4) { return 0; } result = t - 4; result += 4; result /= 5; return result; } gf2m_decomp_rootfind_state::gf2m_decomp_rootfind_state(const polyn_gf2m & polyn, size_t code_length) : m_code_length(code_length), m_j(0), m_j_gray(0) { gf2m coeff_3; gf2m coeff_head; std::shared_ptr sp_field = polyn.get_sp_field(); int deg_sigma = polyn.get_degree(); if(deg_sigma <= 3) { throw Internal_Error("Unexpected degree in gf2m_decomp_rootfind_state"); } coeff_3 = polyn.get_coef( 3); coeff_head = polyn.get_coef( deg_sigma); /* dummy value for SCA CM */ if(coeff_3 != 0) { this->m_sigma_3_l = sp_field->gf_l_from_n(coeff_3); this->m_sigma_3_neq_0_mask = 0xFFFF; } else { // dummy value needed for timing countermeasure this->m_sigma_3_l = sp_field->gf_l_from_n(coeff_head); this->m_sigma_3_neq_0_mask = 0 ; } this->m_outer_summands = 1 + brootf_decomp_calc_sum_limit(deg_sigma); this->m_Lik.resize(this->m_outer_summands * sp_field->get_extension_degree()); this->m_Aij.resize(this->m_outer_summands); } void gf2m_decomp_rootfind_state::calc_Ai_zero(const polyn_gf2m & sigma) { uint32_t i; /* * this function assumes this the first gray code element is zero */ for(i = 0; i < this->m_outer_summands; i++) { this->m_Aij[i] = sigma.get_coef(5*i); } this->m_j = 0; this->m_j_gray = 0; } void gf2m_decomp_rootfind_state::calc_next_Aij() { /* * upon function entry, we have in the state j, Aij. * first thing, we declare Aij Aij_minusone and increase j. * Case j=0 upon function entry also included, then Aij contains A_{i,j=0}. */ uint32_t i; gf2m diff, new_j_gray; uint32_t Lik_pos_base; this->m_j++; new_j_gray = lex_to_gray(this->m_j); if(this->m_j & 1) /* half of the times */ { Lik_pos_base = 0; } else if(this->m_j & 2) /* one quarter of the times */ { Lik_pos_base = this->m_outer_summands; } else if( this->m_j & 4) /* one eighth of the times */ { Lik_pos_base = this->m_outer_summands * 2; } else if( this->m_j & 8) /* one sixteenth of the times */ { Lik_pos_base = this->m_outer_summands * 3; } else if( this->m_j & 16) /* ... */ { Lik_pos_base = this->m_outer_summands * 4; } else { gf2m delta_offs = 5; diff = this->m_j_gray ^ new_j_gray; while(((static_cast(1) << delta_offs) & diff) == 0) { delta_offs++; } Lik_pos_base = delta_offs * this->m_outer_summands; } this->m_j_gray = new_j_gray; i = 0; for(; i < this->m_outer_summands; i++) { this->m_Aij[i] ^= this->m_Lik[Lik_pos_base + i]; } } void gf2m_decomp_rootfind_state::calc_LiK(const polyn_gf2m & sigma) { std::shared_ptr sp_field = sigma.get_sp_field(); uint32_t i, k, d; d = sigma.get_degree(); for(k = 0; k < sp_field->get_extension_degree(); k++) { uint32_t Lik_pos_base = k * this->m_outer_summands; gf2m alpha_l_k_tt2_ttj[4]; alpha_l_k_tt2_ttj[0] = sp_field->gf_l_from_n(static_cast(1) << k); alpha_l_k_tt2_ttj[1] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[0], alpha_l_k_tt2_ttj[0]); alpha_l_k_tt2_ttj[2] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[1],alpha_l_k_tt2_ttj[1] ); alpha_l_k_tt2_ttj[3] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[2], alpha_l_k_tt2_ttj[2]); for(i = 0; i < this->m_outer_summands; i++) { uint32_t j; uint32_t five_i = 5*i; uint32_t Lik_pos = Lik_pos_base + i; this->m_Lik[Lik_pos] = 0; for(j = 0; j <= 3; j++) { gf2m f, x; uint32_t f_ind = five_i + (static_cast(1) << j); if(f_ind > d) { break; } f = sigma.get_coef( f_ind); x = sp_field->gf_mul_zrz(alpha_l_k_tt2_ttj[j], f); this->m_Lik[Lik_pos] ^= x; } } } } gf2m gf2m_decomp_rootfind_state::calc_Fxj_j_neq_0( const polyn_gf2m & sigma, gf2m j_gray) { //needs the A_{ij} to compute F(x)_j gf2m sum = 0; uint32_t i; std::shared_ptr sp_field = sigma.get_sp_field(); const gf2m jl_gray = sp_field->gf_l_from_n(j_gray); gf2m xl_j_tt_5 = sp_field->gf_square_rr(jl_gray); gf2m xl_gray_tt_3 = sp_field->gf_mul_rrr(xl_j_tt_5, jl_gray); xl_j_tt_5 = sp_field->gf_mul_rrr(xl_j_tt_5, xl_gray_tt_3); sum = sp_field->gf_mul_nrr(xl_gray_tt_3, this->m_sigma_3_l); sum &= this->m_sigma_3_neq_0_mask; /* here, we rely on compiler to be unable to optimize * for the state->sigma_3_neq_0_mask value */ /* treat i = 0 special: */ sum ^= this->m_Aij[0]; /* treat i = 1 special also */ if(this->m_outer_summands > 1) { gf2m x; x = sp_field->gf_mul_zrz(xl_j_tt_5, this->m_Aij[1]); /* x_j^{5i} A_i^j */ sum ^= x; } gf2m xl_j_tt_5i = xl_j_tt_5; for(i = 2; i < this->m_outer_summands; i++) { gf2m x; xl_j_tt_5i = sp_field->gf_mul_rrr(xl_j_tt_5i, xl_j_tt_5); // now x_j_tt_5i lives up to its name x = sp_field->gf_mul_zrz(xl_j_tt_5i, this->m_Aij[i]); /* x_j^{5i} A_i^(j) */ sum ^= x; } return sum; } secure_vector gf2m_decomp_rootfind_state::find_roots(const polyn_gf2m & sigma) { const int sigma_degree = sigma.get_degree(); BOTAN_ASSERT(sigma_degree > 0, "Valid sigma"); secure_vector result(sigma_degree); uint32_t root_pos = 0; this->calc_Ai_zero(sigma); this->calc_LiK(sigma); for(;;) { gf2m eval_result; if(this->m_j_gray == 0) { eval_result = sigma.get_coef(0); } else { eval_result = this->calc_Fxj_j_neq_0(sigma, this->m_j_gray); } if(eval_result == 0) { result[root_pos] = this->m_j_gray; root_pos++; } if(this->m_j + static_cast(1) == m_code_length) { break; } this->calc_next_Aij(); } // side channel / fault attack countermeasure: patch_root_array(result.data(), result.size(), root_pos); return result; } } // end anonymous namespace secure_vector find_roots_gf2m_decomp(const polyn_gf2m & polyn, size_t code_length) { gf2m_decomp_rootfind_state state(polyn, code_length); return state.find_roots(polyn); } } // end namespace Botan /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { #define MAX_EXT_DEG 16 namespace { gf2m prim_poly[MAX_EXT_DEG + 1] = { 01, /* extension degree 0 (!) never used */ 03, /* extension degree 1 (!) never used */ 07, /* extension degree 2 */ 013, /* extension degree 3 */ 023, /* extension degree 4 */ 045, /* extension degree 5 */ 0103, /* extension degree 6 */ 0203, /* extension degree 7 */ 0435, /* extension degree 8 */ 01041, /* extension degree 9 */ 02011, /* extension degree 10 */ 04005, /* extension degree 11 */ 010123, /* extension degree 12 */ 020033, /* extension degree 13 */ 042103, /* extension degree 14 */ 0100003, /* extension degree 15 */ }; std::vector gf_exp_table(size_t deg, gf2m prime_poly) { // construct the table gf_exp[i]=alpha^i std::vector tab((static_cast(1) << deg) + 1); tab[0] = 1; for(size_t i = 1; i < tab.size(); ++i) { const gf2m overflow = tab[i-1] >> (deg - 1); tab[i] = (tab[i-1] << 1) ^ (overflow * prime_poly); } return tab; } const std::vector& exp_table(size_t deg) { static std::vector tabs[MAX_EXT_DEG + 1]; if(deg < 2 || deg > MAX_EXT_DEG) throw Invalid_Argument("GF2m_Field does not support degree " + std::to_string(deg)); if(tabs[deg].empty()) tabs[deg] = gf_exp_table(deg, prim_poly[deg]); return tabs[deg]; } std::vector gf_log_table(size_t deg, const std::vector& exp) { std::vector tab(static_cast(1) << deg); tab[0] = static_cast((static_cast(1) << deg) - 1); // log of 0 is the order by convention for(size_t i = 0; i < tab.size(); ++i) { tab[exp[i]] = static_cast(i); } return tab; } const std::vector& log_table(size_t deg) { static std::vector tabs[MAX_EXT_DEG + 1]; if(deg < 2 || deg > MAX_EXT_DEG) throw Invalid_Argument("GF2m_Field does not support degree " + std::to_string(deg)); if(tabs[deg].empty()) tabs[deg] = gf_log_table(deg, exp_table(deg)); return tabs[deg]; } } uint32_t encode_gf2m(gf2m to_enc, uint8_t* mem) { mem[0] = to_enc >> 8; mem[1] = to_enc & 0xFF; return sizeof(to_enc); } gf2m decode_gf2m(const uint8_t* mem) { gf2m result; result = mem[0] << 8; result |= mem[1]; return result; } GF2m_Field::GF2m_Field(size_t extdeg) : m_gf_extension_degree(extdeg), m_gf_multiplicative_order((1 << extdeg) - 1), m_gf_log_table(log_table(m_gf_extension_degree)), m_gf_exp_table(exp_table(m_gf_extension_degree)) { } gf2m GF2m_Field::gf_div(gf2m x, gf2m y) const { const int32_t sub_res = static_cast(gf_log(x) - static_cast(gf_log(y))); const gf2m modq_res = _gf_modq_1(sub_res); const int32_t div_res = static_cast(x) ? static_cast(gf_exp(modq_res)) : 0; return static_cast(div_res); } } /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * * Botan is released under the Simplified BSD License (see license.txt) * */ namespace Botan { namespace { void matrix_arr_mul(std::vector matrix, size_t numo_rows, size_t words_per_row, const uint8_t input_vec[], uint32_t output_vec[], size_t output_vec_len) { for(size_t j = 0; j < numo_rows; j++) { if((input_vec[j / 8] >> (j % 8)) & 1) { for(size_t i = 0; i < output_vec_len; i++) { output_vec[i] ^= matrix[j * (words_per_row) + i]; } } } } /** * returns the error vector to the syndrome */ secure_vector goppa_decode(const polyn_gf2m & syndrom_polyn, const polyn_gf2m & g, const std::vector & sqrtmod, const std::vector & Linv) { const size_t code_length = Linv.size(); gf2m a; uint32_t t = g.get_degree(); std::shared_ptr sp_field = g.get_sp_field(); std::pair h_aux = polyn_gf2m::eea_with_coefficients( syndrom_polyn, g, 1); polyn_gf2m & h = h_aux.first; polyn_gf2m & aux = h_aux.second; a = sp_field->gf_inv(aux.get_coef(0)); gf2m log_a = sp_field->gf_log(a); for(int i = 0; i <= h.get_degree(); ++i) { h.set_coef(i,sp_field->gf_mul_zrz(log_a,h.get_coef(i))); } // compute h(z) += z h.add_to_coef( 1, 1); // compute S square root of h (using sqrtmod) polyn_gf2m S(t - 1, g.get_sp_field()); for(uint32_t i=0;igf_sqrt(h.get_coef(i)); if(i & 1) { for(uint32_t j=0;jgf_mul(a, sqrtmod[i/2].get_coef(j))); } } else { S.add_to_coef( i/2, a); } } /* end for loop (i) */ S.get_degree(); std::pair v_u = polyn_gf2m::eea_with_coefficients(S, g, t/2+1); polyn_gf2m & u = v_u.second; polyn_gf2m & v = v_u.first; // sigma = u^2+z*v^2 polyn_gf2m sigma ( t , g.get_sp_field()); const int u_deg = u.get_degree(); BOTAN_ASSERT(u_deg >= 0, "Valid degree"); for(int i = 0; i <= u_deg; ++i) { sigma.set_coef(2*i, sp_field->gf_square(u.get_coef(i))); } const int v_deg = v.get_degree(); BOTAN_ASSERT(v_deg >= 0, "Valid degree"); for(int i = 0; i <= v_deg; ++i) { sigma.set_coef(2*i+1, sp_field->gf_square(v.get_coef(i))); } secure_vector res = find_roots_gf2m_decomp(sigma, code_length); size_t d = res.size(); secure_vector result(d); for(uint32_t i = 0; i < d; ++i) { gf2m current = res[i]; gf2m tmp; tmp = gray_to_lex(current); /// XXX double assignment, possible bug? if(tmp >= code_length) /* invalid root */ { result[i] = static_cast(i); } result[i] = Linv[tmp]; } return result; } } void mceliece_decrypt(secure_vector& plaintext_out, secure_vector& error_mask_out, const secure_vector& ciphertext, const McEliece_PrivateKey& key) { mceliece_decrypt(plaintext_out, error_mask_out, ciphertext.data(), ciphertext.size(), key); } void mceliece_decrypt( secure_vector& plaintext, secure_vector & error_mask, const uint8_t ciphertext[], size_t ciphertext_len, const McEliece_PrivateKey & key) { secure_vector error_pos; plaintext = mceliece_decrypt(error_pos, ciphertext, ciphertext_len, key); const size_t code_length = key.get_code_length(); secure_vector result((code_length+7)/8); for(auto&& pos : error_pos) { if(pos > code_length) { throw Invalid_Argument("error position larger than code size"); } result[pos / 8] |= (1 << (pos % 8)); } error_mask = result; } /** * @p p_err_pos_len must point to the available length of @p error_pos on input, the * function will set it to the actual number of errors returned in the @p error_pos * array */ secure_vector mceliece_decrypt( secure_vector & error_pos, const uint8_t *ciphertext, size_t ciphertext_len, const McEliece_PrivateKey & key) { const size_t dimension = key.get_dimension(); const size_t codimension = key.get_codimension(); const uint32_t t = key.get_goppa_polyn().get_degree(); polyn_gf2m syndrome_polyn(key.get_goppa_polyn().get_sp_field()); // init as zero polyn const unsigned unused_pt_bits = dimension % 8; const uint8_t unused_pt_bits_mask = (1 << unused_pt_bits) - 1; if(ciphertext_len != (key.get_code_length()+7)/8) { throw Invalid_Argument("wrong size of McEliece ciphertext"); } const size_t cleartext_len = (key.get_message_word_bit_length()+7)/8; if(cleartext_len != bit_size_to_byte_size(dimension)) { throw Invalid_Argument("mce-decryption: wrong length of cleartext buffer"); } secure_vector syndrome_vec(bit_size_to_32bit_size(codimension)); matrix_arr_mul(key.get_H_coeffs(), key.get_code_length(), bit_size_to_32bit_size(codimension), ciphertext, syndrome_vec.data(), syndrome_vec.size()); secure_vector syndrome_byte_vec(bit_size_to_byte_size(codimension)); const size_t syndrome_byte_vec_size = syndrome_byte_vec.size(); for(size_t i = 0; i < syndrome_byte_vec_size; i++) { syndrome_byte_vec[i] = static_cast(syndrome_vec[i/4] >> (8 * (i % 4))); } syndrome_polyn = polyn_gf2m(t-1, syndrome_byte_vec.data(), bit_size_to_byte_size(codimension), key.get_goppa_polyn().get_sp_field()); syndrome_polyn.get_degree(); error_pos = goppa_decode(syndrome_polyn, key.get_goppa_polyn(), key.get_sqrtmod(), key.get_Linv()); const size_t nb_err = error_pos.size(); secure_vector cleartext(cleartext_len); copy_mem(cleartext.data(), ciphertext, cleartext_len); for(size_t i = 0; i < nb_err; i++) { gf2m current = error_pos[i]; if(current >= cleartext_len * 8) { // an invalid position, this shouldn't happen continue; } cleartext[current / 8] ^= (1 << (current % 8)); } if(unused_pt_bits) { cleartext[cleartext_len - 1] &= unused_pt_bits_mask; } return cleartext; } } /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * (C) 2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) * */ #include namespace Botan { namespace { double binomial(size_t n, size_t k) { double x = 1; for(size_t i = 0; i != k; ++i) { x *= n - i; x /= k -i; } return x; } double log_binomial(size_t n, size_t k) { double x = 0; for(size_t i = 0; i != k; ++i) { x += std::log(n - i); x -= std::log(k - i); } return x / std::log(2); } double nb_iter(size_t n, size_t k, size_t w, size_t p, size_t l) { double x = 2 * log_binomial(k / 2, p); x += log_binomial(n - k - l, w - 2 * p); x = log_binomial(n, w) - x; return x; } double cout_iter(size_t n, size_t k, size_t p, size_t l) { double x = binomial(k / 2, p); const size_t i = static_cast(std::log(x) / std::log(2)); double res = 2 * p * (n - k - l) * std::ldexp(x * x, -static_cast(l)); // x <- binomial(k/2,p)*2*(2*l+log[2](binomial(k/2,p))) x *= 2 * (2 * l + i); // res <- k*(n-k)/2 + // binomial(k/2,p)*2*(2*l+log[2](binomial(k/2,p))) + // 2*p*(n-k-l)*binomial(k/2,p)^2/2^l res += x + k * ((n - k) / 2.0); return std::log(res) / std::log(2); // convert to bits } double cout_total(size_t n, size_t k, size_t w, size_t p, size_t l) { return nb_iter(n, k, w, p, l) + cout_iter(n, k, p, l); } double best_wf(size_t n, size_t k, size_t w, size_t p) { if(p >= k / 2) return -1; double min = cout_total(n, k, w, p, 0); for(size_t l = 1; l < n - k; ++l) { const double lwf = cout_total(n, k, w, p, l); if(lwf < min) min = lwf; else break; } return min; } } size_t mceliece_work_factor(size_t n, size_t t) { const size_t k = n - ceil_log2(n) * t; double min = cout_total(n, k, t, 0, 0); // correspond a p=1 for(size_t p = 0; p != t / 2; ++p) { double lwf = best_wf(n, k + 1, t, p); if(lwf < 0) break; min = std::min(min, lwf); } return static_cast(min); } } /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * * Botan is released under the Simplified BSD License (see license.txt) * */ namespace Botan { namespace { secure_vector concat_vectors(const secure_vector& a, const secure_vector& b, size_t dimension, size_t codimension) { secure_vector x(bit_size_to_byte_size(dimension) + bit_size_to_byte_size(codimension)); const size_t final_bits = dimension % 8; if(final_bits == 0) { const size_t dim_bytes = bit_size_to_byte_size(dimension); copy_mem(&x[0], a.data(), dim_bytes); copy_mem(&x[dim_bytes], b.data(), bit_size_to_byte_size(codimension)); } else { copy_mem(&x[0], a.data(), (dimension / 8)); size_t l = dimension / 8; x[l] = static_cast(a[l] & ((1 << final_bits) - 1)); for(size_t k = 0; k < codimension / 8; ++k) { x[l] ^= static_cast(b[k] << final_bits); ++l; x[l] = static_cast(b[k] >> (8 - final_bits)); } x[l] ^= static_cast(b[codimension/8] << final_bits); } return x; } secure_vector mult_by_pubkey(const secure_vector& cleartext, std::vector const& public_matrix, size_t code_length, size_t t) { const size_t ext_deg = ceil_log2(code_length); const size_t codimension = ext_deg * t; const size_t dimension = code_length - codimension; secure_vector cR(bit_size_to_32bit_size(codimension) * sizeof(uint32_t)); const uint8_t* pt = public_matrix.data(); for(size_t i = 0; i < dimension / 8; ++i) { for(size_t j = 0; j < 8; ++j) { if(cleartext[i] & (1 << j)) { xor_buf(cR.data(), pt, cR.size()); } pt += cR.size(); } } for(size_t i = 0; i < dimension % 8 ; ++i) { if(cleartext[dimension/8] & (1 << i)) { xor_buf(cR.data(), pt, cR.size()); } pt += cR.size(); } secure_vector ciphertext = concat_vectors(cleartext, cR, dimension, codimension); ciphertext.resize((code_length+7)/8); return ciphertext; } secure_vector create_random_error_vector(size_t code_length, size_t error_weight, RandomNumberGenerator& rng) { secure_vector result((code_length+7)/8); size_t bits_set = 0; while(bits_set < error_weight) { gf2m x = random_code_element(static_cast(code_length), rng); const size_t byte_pos = x / 8; const size_t bit_pos = x % 8; const uint8_t mask = (1 << bit_pos); if(result[byte_pos] & mask) continue; // already set this bit result[byte_pos] |= mask; bits_set++; } return result; } } void mceliece_encrypt(secure_vector& ciphertext_out, secure_vector& error_mask_out, const secure_vector& plaintext, const McEliece_PublicKey& key, RandomNumberGenerator& rng) { const uint16_t code_length = static_cast(key.get_code_length()); secure_vector error_mask = create_random_error_vector(code_length, key.get_t(), rng); secure_vector ciphertext = mult_by_pubkey(plaintext, key.get_public_matrix(), key.get_code_length(), key.get_t()); ciphertext ^= error_mask; ciphertext_out.swap(ciphertext); error_mask_out.swap(error_mask); } } /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) * */ namespace Botan { McEliece_PrivateKey::McEliece_PrivateKey(polyn_gf2m const& goppa_polyn, std::vector const& parity_check_matrix_coeffs, std::vector const& square_root_matrix, std::vector const& inverse_support, std::vector const& public_matrix) : McEliece_PublicKey(public_matrix, goppa_polyn.get_degree(), inverse_support.size()), m_g{goppa_polyn}, m_sqrtmod(square_root_matrix), m_Linv(inverse_support), m_coeffs(parity_check_matrix_coeffs), m_codimension(static_cast(ceil_log2(inverse_support.size())) * goppa_polyn.get_degree()), m_dimension(inverse_support.size() - m_codimension) { } McEliece_PrivateKey::McEliece_PrivateKey(RandomNumberGenerator& rng, size_t code_length, size_t t) { uint32_t ext_deg = ceil_log2(code_length); *this = generate_mceliece_key(rng, ext_deg, code_length, t); } McEliece_PrivateKey::~McEliece_PrivateKey() = default; const polyn_gf2m& McEliece_PrivateKey::get_goppa_polyn() const { return m_g[0]; } size_t McEliece_PublicKey::get_message_word_bit_length() const { size_t codimension = ceil_log2(m_code_length) * m_t; return m_code_length - codimension; } secure_vector McEliece_PublicKey::random_plaintext_element(RandomNumberGenerator& rng) const { const size_t bits = get_message_word_bit_length(); secure_vector plaintext((bits+7)/8); rng.randomize(plaintext.data(), plaintext.size()); // unset unused bits in the last plaintext byte if(uint32_t used = bits % 8) { const uint8_t mask = (1 << used) - 1; plaintext[plaintext.size() - 1] &= mask; } return plaintext; } AlgorithmIdentifier McEliece_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); } std::vector McEliece_PublicKey::public_key_bits() const { std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .start_cons(SEQUENCE) .encode(static_cast(get_code_length())) .encode(static_cast(get_t())) .end_cons() .encode(m_public_matrix, OCTET_STRING) .end_cons(); return output; } size_t McEliece_PublicKey::key_length() const { return m_code_length; } size_t McEliece_PublicKey::estimated_strength() const { return mceliece_work_factor(m_code_length, m_t); } McEliece_PublicKey::McEliece_PublicKey(const std::vector& key_bits) { BER_Decoder dec(key_bits); size_t n; size_t t; dec.start_cons(SEQUENCE) .start_cons(SEQUENCE) .decode(n) .decode(t) .end_cons() .decode(m_public_matrix, OCTET_STRING) .end_cons(); m_t = t; m_code_length = n; } secure_vector McEliece_PrivateKey::private_key_bits() const { DER_Encoder enc; enc.start_cons(SEQUENCE) .start_cons(SEQUENCE) .encode(static_cast(get_code_length())) .encode(static_cast(get_t())) .end_cons() .encode(m_public_matrix, OCTET_STRING) .encode(m_g[0].encode(), OCTET_STRING); // g as octet string enc.start_cons(SEQUENCE); for(size_t i = 0; i < m_sqrtmod.size(); i++) { enc.encode(m_sqrtmod[i].encode(), OCTET_STRING); } enc.end_cons(); secure_vector enc_support; for(uint16_t Linv : m_Linv) { enc_support.push_back(get_byte(0, Linv)); enc_support.push_back(get_byte(1, Linv)); } enc.encode(enc_support, OCTET_STRING); secure_vector enc_H; for(uint32_t coef : m_coeffs) { enc_H.push_back(get_byte(0, coef)); enc_H.push_back(get_byte(1, coef)); enc_H.push_back(get_byte(2, coef)); enc_H.push_back(get_byte(3, coef)); } enc.encode(enc_H, OCTET_STRING); enc.end_cons(); return enc.get_contents(); } bool McEliece_PrivateKey::check_key(RandomNumberGenerator& rng, bool) const { const secure_vector plaintext = this->random_plaintext_element(rng); secure_vector ciphertext; secure_vector errors; mceliece_encrypt(ciphertext, errors, plaintext, *this, rng); secure_vector plaintext_out; secure_vector errors_out; mceliece_decrypt(plaintext_out, errors_out, ciphertext, *this); if(errors != errors_out || plaintext != plaintext_out) return false; return true; } McEliece_PrivateKey::McEliece_PrivateKey(const secure_vector& key_bits) { size_t n, t; secure_vector enc_g; BER_Decoder dec_base(key_bits); BER_Decoder dec = dec_base.start_cons(SEQUENCE) .start_cons(SEQUENCE) .decode(n) .decode(t) .end_cons() .decode(m_public_matrix, OCTET_STRING) .decode(enc_g, OCTET_STRING); if(t == 0 || n == 0) throw Decoding_Error("invalid McEliece parameters"); uint32_t ext_deg = ceil_log2(n); m_code_length = n; m_t = t; m_codimension = (ext_deg * t); m_dimension = (n - m_codimension); std::shared_ptr sp_field(new GF2m_Field(ext_deg)); m_g = { polyn_gf2m(enc_g, sp_field) }; if(m_g[0].get_degree() != static_cast(t)) { throw Decoding_Error("degree of decoded Goppa polynomial is incorrect"); } BER_Decoder dec2 = dec.start_cons(SEQUENCE); for(uint32_t i = 0; i < t/2; i++) { secure_vector sqrt_enc; dec2.decode(sqrt_enc, OCTET_STRING); while(sqrt_enc.size() < (t*2)) { // ensure that the length is always t sqrt_enc.push_back(0); sqrt_enc.push_back(0); } if(sqrt_enc.size() != t*2) { throw Decoding_Error("length of square root polynomial entry is too large"); } m_sqrtmod.push_back(polyn_gf2m(sqrt_enc, sp_field)); } secure_vector enc_support; BER_Decoder dec3 = dec2.end_cons() .decode(enc_support, OCTET_STRING); if(enc_support.size() % 2) { throw Decoding_Error("encoded support has odd length"); } if(enc_support.size() / 2 != n) { throw Decoding_Error("encoded support has length different from code length"); } for(uint32_t i = 0; i < n*2; i+=2) { gf2m el = (enc_support[i] << 8) | enc_support[i+1]; m_Linv.push_back(el); } secure_vector enc_H; dec3.decode(enc_H, OCTET_STRING) .end_cons(); if(enc_H.size() % 4) { throw Decoding_Error("encoded parity check matrix has length which is not a multiple of four"); } if(enc_H.size() / 4 != bit_size_to_32bit_size(m_codimension) * m_code_length) { throw Decoding_Error("encoded parity check matrix has wrong length"); } for(uint32_t i = 0; i < enc_H.size(); i+=4) { uint32_t coeff = (enc_H[i] << 24) | (enc_H[i+1] << 16) | (enc_H[i+2] << 8) | enc_H[i+3]; m_coeffs.push_back(coeff); } } bool McEliece_PrivateKey::operator==(const McEliece_PrivateKey & other) const { if(*static_cast(this) != *static_cast(&other)) { return false; } if(m_g != other.m_g) { return false; } if( m_sqrtmod != other.m_sqrtmod) { return false; } if( m_Linv != other.m_Linv) { return false; } if( m_coeffs != other.m_coeffs) { return false; } if(m_codimension != other.m_codimension || m_dimension != other.m_dimension) { return false; } return true; } bool McEliece_PublicKey::operator==(const McEliece_PublicKey& other) const { if(m_public_matrix != other.m_public_matrix) { return false; } if(m_t != other.m_t) { return false; } if( m_code_length != other.m_code_length) { return false; } return true; } namespace { class MCE_KEM_Encryptor final : public PK_Ops::KEM_Encryption_with_KDF { public: MCE_KEM_Encryptor(const McEliece_PublicKey& key, const std::string& kdf) : KEM_Encryption_with_KDF(kdf), m_key(key) {} private: void raw_kem_encrypt(secure_vector& out_encapsulated_key, secure_vector& raw_shared_key, Botan::RandomNumberGenerator& rng) override { secure_vector plaintext = m_key.random_plaintext_element(rng); secure_vector ciphertext, error_mask; mceliece_encrypt(ciphertext, error_mask, plaintext, m_key, rng); raw_shared_key.clear(); raw_shared_key += plaintext; raw_shared_key += error_mask; out_encapsulated_key.swap(ciphertext); } const McEliece_PublicKey& m_key; }; class MCE_KEM_Decryptor final : public PK_Ops::KEM_Decryption_with_KDF { public: MCE_KEM_Decryptor(const McEliece_PrivateKey& key, const std::string& kdf) : KEM_Decryption_with_KDF(kdf), m_key(key) {} private: secure_vector raw_kem_decrypt(const uint8_t encap_key[], size_t len) override { secure_vector plaintext, error_mask; mceliece_decrypt(plaintext, error_mask, encap_key, len, m_key); secure_vector output; output.reserve(plaintext.size() + error_mask.size()); output.insert(output.end(), plaintext.begin(), plaintext.end()); output.insert(output.end(), error_mask.begin(), error_mask.end()); return output; } const McEliece_PrivateKey& m_key; }; } std::unique_ptr McEliece_PublicKey::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new MCE_KEM_Encryptor(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr McEliece_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new MCE_KEM_Decryptor(*this, params)); throw Provider_Not_Found(algo_name(), provider); } } /* * (C) Copyright Projet SECRET, INRIA, Rocquencourt * (C) Bhaskar Biswas and Nicolas Sendrier * * (C) 2014 cryptosource GmbH * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) * */ namespace Botan { namespace { gf2m generate_gf2m_mask(gf2m a) { gf2m result = (a != 0); return ~(result - 1); } /** * number of leading zeros */ unsigned nlz_16bit(uint16_t x) { unsigned n; if(x == 0) return 16; n = 0; if(x <= 0x00FF) {n = n + 8; x = x << 8;} if(x <= 0x0FFF) {n = n + 4; x = x << 4;} if(x <= 0x3FFF) {n = n + 2; x = x << 2;} if(x <= 0x7FFF) {n = n + 1;} return n; } } int polyn_gf2m::calc_degree_secure() const { int i = static_cast(this->coeff.size()) - 1; int result = 0; uint32_t found_mask = 0; uint32_t tracker_mask = 0xffff; for( ; i >= 0; i--) { found_mask = expand_mask_16bit(this->coeff[i]); result |= i & found_mask & tracker_mask; // tracker mask shall become zero once found mask is set // it shall remain zero from then on tracker_mask = tracker_mask & ~found_mask; } const_cast(this)->m_deg = result; return result; } gf2m random_gf2m(RandomNumberGenerator& rng) { uint8_t b[2]; rng.randomize(b, sizeof(b)); return make_uint16(b[1], b[0]); } gf2m random_code_element(uint16_t code_length, RandomNumberGenerator& rng) { if(code_length == 0) { throw Invalid_Argument("random_code_element() was supplied a code length of zero"); } const unsigned nlz = nlz_16bit(code_length-1); const gf2m mask = (1 << (16-nlz)) - 1; gf2m result; do { result = random_gf2m(rng); result &= mask; } while(result >= code_length); // rejection sampling return result; } polyn_gf2m::polyn_gf2m(polyn_gf2m const& other) :m_deg(other.m_deg), coeff(other.coeff), m_sp_field(other.m_sp_field) { } polyn_gf2m::polyn_gf2m(int d, std::shared_ptr sp_field) :m_deg(-1), coeff(d+1), m_sp_field(sp_field) { } std::string polyn_gf2m::to_string() const { int d = get_degree(); std::string result; for(int i = 0; i <= d; i ++) { result += std::to_string(this->coeff[i]); if(i != d) { result += ", "; } } return result; } /** * doesn't save coefficients: */ void polyn_gf2m::realloc(uint32_t new_size) { this->coeff = secure_vector(new_size); } polyn_gf2m::polyn_gf2m(const uint8_t* mem, uint32_t mem_len, std::shared_ptr sp_field) : m_deg(-1), m_sp_field(sp_field) { if(mem_len % sizeof(gf2m)) { throw Decoding_Error("illegal length of memory to decode "); } uint32_t size = (mem_len / sizeof(this->coeff[0])) ; this->coeff = secure_vector(size); this->m_deg = -1; for(uint32_t i = 0; i < size; i++) { this->coeff[i] = decode_gf2m(mem); mem += sizeof(this->coeff[0]); } for(uint32_t i = 0; i < size; i++) { if(this->coeff[i] >= (1 << sp_field->get_extension_degree())) { throw Decoding_Error("error decoding polynomial"); } } this->get_degree(); } polyn_gf2m::polyn_gf2m( std::shared_ptr sp_field) : m_deg(-1), coeff(1), m_sp_field(sp_field) {} polyn_gf2m::polyn_gf2m(int degree, const uint8_t* mem, size_t mem_byte_len, std::shared_ptr sp_field) :m_sp_field(sp_field) { uint32_t j, k, l; gf2m a; uint32_t polyn_size; polyn_size = degree + 1; if(polyn_size * sp_field->get_extension_degree() > 8 * mem_byte_len) { throw Decoding_Error("memory vector for polynomial has wrong size"); } this->coeff = secure_vector(degree+1); gf2m ext_deg = static_cast(this->m_sp_field->get_extension_degree()); for (l = 0; l < polyn_size; l++) { k = (l * ext_deg) / 8; j = (l * ext_deg) % 8; a = mem[k] >> j; if (j + ext_deg > 8) { a ^= mem[k + 1] << (8- j); } if(j + ext_deg > 16) { a ^= mem[k + 2] << (16- j); } a &= ((1 << ext_deg) - 1); (*this).set_coef( l, a); } this->get_degree(); } #if 0 void polyn_gf2m::encode(uint32_t min_numo_coeffs, uint8_t* mem, uint32_t mem_len) const { uint32_t i; uint32_t numo_coeffs, needed_size; this->get_degree(); numo_coeffs = (min_numo_coeffs > static_cast(this->m_deg+1)) ? min_numo_coeffs : this->m_deg+1; needed_size = sizeof(this->coeff[0]) * numo_coeffs; if(mem_len < needed_size) { Invalid_Argument("provided memory too small to encode polynomial"); } for(i = 0; i < numo_coeffs; i++) { gf2m to_enc; if(i >= static_cast(this->m_deg+1)) { /* encode a zero */ to_enc = 0; } else { to_enc = this->coeff[i]; } mem += encode_gf2m(to_enc, mem); } } #endif void polyn_gf2m::set_to_zero() { clear_mem(&this->coeff[0], this->coeff.size()); this->m_deg = -1; } int polyn_gf2m::get_degree() const { int d = static_cast(this->coeff.size()) - 1; while ((d >= 0) && (this->coeff[d] == 0)) --d; const_cast(this)->m_deg = d; return d; } static gf2m eval_aux(const gf2m * /*restrict*/ coeff, gf2m a, int d, std::shared_ptr sp_field) { gf2m b; b = coeff[d--]; for (; d >= 0; --d) if (b != 0) { b = sp_field->gf_mul(b, a) ^ coeff[d]; } else { b = coeff[d]; } return b; } gf2m polyn_gf2m::eval(gf2m a) { return eval_aux(&this->coeff[0], a, this->m_deg, this->m_sp_field); } // p will contain it's remainder modulo g void polyn_gf2m::remainder(polyn_gf2m &p, const polyn_gf2m & g) { int i, j, d; std::shared_ptr m_sp_field = g.m_sp_field; d = p.get_degree() - g.get_degree(); if (d >= 0) { gf2m la = m_sp_field->gf_inv_rn(g.get_lead_coef()); const int p_degree = p.get_degree(); BOTAN_ASSERT(p_degree > 0, "Valid polynomial"); for (i = p_degree; d >= 0; --i, --d) { if (p[i] != 0) { gf2m lb = m_sp_field->gf_mul_rrn(la, p[i]); for (j = 0; j < g.get_degree(); ++j) { p[j+d] ^= m_sp_field->gf_mul_zrz(lb, g[j]); } (*&p).set_coef( i, 0); } } p.set_degree( g.get_degree() - 1); while ((p.get_degree() >= 0) && (p[p.get_degree()] == 0)) p.set_degree( p.get_degree() - 1); } } std::vector polyn_gf2m::sqmod_init(const polyn_gf2m & g) { std::vector sq; const int signed_deg = g.get_degree(); if(signed_deg <= 0) throw Invalid_Argument("cannot compute sqmod for such low degree"); const uint32_t d = static_cast(signed_deg); uint32_t t = g.m_deg; // create t zero polynomials uint32_t i; for (i = 0; i < t; ++i) { sq.push_back(polyn_gf2m(t+1, g.get_sp_field())); } for (i = 0; i < d / 2; ++i) { sq[i].set_degree( 2 * i); (*&sq[i]).set_coef( 2 * i, 1); } for (; i < d; ++i) { clear_mem(&sq[i].coeff[0], 2); copy_mem(&sq[i].coeff[0] + 2, &sq[i - 1].coeff[0], d); sq[i].set_degree( sq[i - 1].get_degree() + 2); polyn_gf2m::remainder(sq[i], g); } return sq; } /*Modulo p square of a certain polynomial g, sq[] contains the square Modulo g of the base canonical polynomials of degree < d, where d is the degree of G. The table sq[] will be calculated by polyn_gf2m_sqmod_init*/ polyn_gf2m polyn_gf2m::sqmod( const std::vector & sq, int d) { int i, j; gf2m la; std::shared_ptr sp_field = this->m_sp_field; polyn_gf2m result(d - 1, sp_field); // terms of low degree for (i = 0; i < d / 2; ++i) { (*&result).set_coef( i * 2, sp_field->gf_square((*this)[i])); } // terms of high degree for (; i < d; ++i) { gf2m lpi = (*this)[i]; if (lpi != 0) { lpi = sp_field->gf_log(lpi); la = sp_field->gf_mul_rrr(lpi, lpi); for (j = 0; j < d; ++j) { result[j] ^= sp_field->gf_mul_zrz(la, sq[i][j]); } } } // Update degre result.set_degree( d - 1); while ((result.get_degree() >= 0) && (result[result.get_degree()] == 0)) result.set_degree( result.get_degree() - 1); return result; } // destructive polyn_gf2m polyn_gf2m::gcd_aux(polyn_gf2m& p1, polyn_gf2m& p2) { if (p2.get_degree() == -1) return p1; else { polyn_gf2m::remainder(p1, p2); return polyn_gf2m::gcd_aux(p2, p1); } } polyn_gf2m polyn_gf2m::gcd(polyn_gf2m const& p1, polyn_gf2m const& p2) { polyn_gf2m a(p1); polyn_gf2m b(p2); if (a.get_degree() < b.get_degree()) { return polyn_gf2m(polyn_gf2m::gcd_aux(b, a)); } else { return polyn_gf2m(polyn_gf2m::gcd_aux(a, b)); } } // Returns the degree of the smallest factor size_t polyn_gf2m::degppf(const polyn_gf2m& g) { polyn_gf2m s(g.get_sp_field()); const size_t ext_deg = g.m_sp_field->get_extension_degree(); const int d = g.get_degree(); std::vector u = polyn_gf2m::sqmod_init(g); polyn_gf2m p(d - 1, g.m_sp_field); p.set_degree(1); (*&p).set_coef(1, 1); size_t result = static_cast(d); for(size_t i = 1; i <= (d / 2) * ext_deg; ++i) { polyn_gf2m r = p.sqmod(u, d); if ((i % ext_deg) == 0) { r[1] ^= 1; r.get_degree(); // The degree may change s = polyn_gf2m::gcd( g, r); if(s.get_degree() > 0) { result = i / ext_deg; break; } r[1] ^= 1; r.get_degree(); // The degree may change } // No need for the exchange s s = p; p = r; r = s; } return result; } void polyn_gf2m::patchup_deg_secure( uint32_t trgt_deg, volatile gf2m patch_elem) { uint32_t i; if(this->coeff.size() < trgt_deg) { return; } for(i = 0; i < this->coeff.size(); i++) { uint32_t equal, equal_mask; this->coeff[i] |= patch_elem; equal = (i == trgt_deg); equal_mask = expand_mask_16bit(equal); patch_elem &= ~equal_mask; } this->calc_degree_secure(); } // We suppose m_deg(g) >= m_deg(p) // v is the problem std::pair polyn_gf2m::eea_with_coefficients( const polyn_gf2m & p, const polyn_gf2m & g, int break_deg) { std::shared_ptr m_sp_field = g.m_sp_field; int i, j, dr, du, delta; gf2m a; polyn_gf2m aux; // initialisation of the local variables // r0 <- g, r1 <- p, u0 <- 0, u1 <- 1 dr = g.get_degree(); BOTAN_ASSERT(dr > 3, "Valid polynomial"); polyn_gf2m r0(dr, g.m_sp_field); polyn_gf2m r1(dr - 1, g.m_sp_field); polyn_gf2m u0(dr - 1, g.m_sp_field); polyn_gf2m u1(dr - 1, g.m_sp_field); r0 = g; r1 = p; u0.set_to_zero(); u1.set_to_zero(); (*&u1).set_coef( 0, 1); u1.set_degree( 0); // invariants: // r1 = u1 * p + v1 * g // r0 = u0 * p + v0 * g // and m_deg(u1) = m_deg(g) - m_deg(r0) // It stops when m_deg (r1) = t) // And therefore m_deg (u1) = m_deg (g) - m_deg (r0) = break_deg) { for (j = delta; j >= 0; --j) { a = m_sp_field->gf_div(r0[dr + j], r1[dr]); if (a != 0) { gf2m la = m_sp_field->gf_log(a); // u0(z) <- u0(z) + a * u1(z) * z^j for (i = 0; i <= du; ++i) { u0[i + j] ^= m_sp_field->gf_mul_zrz(la, u1[i]); } // r0(z) <- r0(z) + a * r1(z) * z^j for (i = 0; i <= dr; ++i) { r0[i + j] ^= m_sp_field->gf_mul_zrz(la, r1[i]); } } } // end loop over j if(break_deg != 1) /* key eq. solving */ { /* [ssms_icisc09] Countermeasure * d_break from paper equals break_deg - 1 * */ volatile gf2m fake_elem = 0x01; volatile gf2m cond1, cond2; int trgt_deg = r1.get_degree() - 1; r0.calc_degree_secure(); u0.calc_degree_secure(); if(!(g.get_degree() % 2)) { /* t even */ cond1 = r0.get_degree() < break_deg - 1; } else { /* t odd */ cond1 = r0.get_degree() < break_deg; cond2 = u0.get_degree() < break_deg - 1; cond1 &= cond2; } /* expand cond1 to a full mask */ gf2m mask = generate_gf2m_mask(cond1); fake_elem &= mask; r0.patchup_deg_secure(trgt_deg, fake_elem); } if(break_deg == 1) /* syndrome inversion */ { volatile gf2m fake_elem = 0x00; volatile uint32_t trgt_deg = 0; r0.calc_degree_secure(); u0.calc_degree_secure(); /** * countermeasure against the low weight attacks for w=4, w=6 and w=8. * Higher values are not covered since for w=8 we already have a * probability for a positive of 1/n^3 from random ciphertexts with the * given weight. For w = 10 it would be 1/n^4 and so on. Thus attacks * based on such high values of w are considered impractical. * * The outer test for the degree of u ( Omega in the paper ) needs not to * be disguised. Each of the three is performed at most once per EEA * (syndrome inversion) execution, the attacker knows this already when * preparing the ciphertext with the given weight. Inside these three * cases however, we must use timing neutral (branch free) operations to * implement the condition detection and the counteractions. * */ if(u0.get_degree() == 4) { uint32_t mask = 0; /** * Condition that the EEA would break now */ int cond_r = r0.get_degree() == 0; /** * Now come the conditions for all odd coefficients of this sigma * candiate. If they are all fulfilled, then we know that we have a low * weight error vector, since the key-equation solving EEA is skipped if * the degree of tau^2 is low (=m_deg(u0)) and all its odd cofficients are * zero (they would cause "full-length" contributions from the square * root computation). */ // Condition for the coefficient to Y to be cancelled out by the // addition of Y before the square root computation: int cond_u1 = m_sp_field->gf_mul(u0.coeff[1], m_sp_field->gf_inv(r0.coeff[0])) == 1; // Condition sigma_3 = 0: int cond_u3 = u0.coeff[3] == 0; // combine the conditions: cond_r &= (cond_u1 & cond_u3); // mask generation: mask = expand_mask_16bit(cond_r); trgt_deg = 2 & mask; fake_elem = 1 & mask; } else if(u0.get_degree() == 6) { uint32_t mask = 0; int cond_r= r0.get_degree() == 0; int cond_u1 = m_sp_field->gf_mul(u0.coeff[1], m_sp_field->gf_inv(r0.coeff[0])) == 1; int cond_u3 = u0.coeff[3] == 0; int cond_u5 = u0.coeff[5] == 0; cond_r &= (cond_u1 & cond_u3 & cond_u5); mask = expand_mask_16bit(cond_r); trgt_deg = 4 & mask; fake_elem = 1 & mask; } else if(u0.get_degree() == 8) { uint32_t mask = 0; int cond_r= r0.get_degree() == 0; int cond_u1 = m_sp_field->gf_mul(u0[1], m_sp_field->gf_inv(r0[0])) == 1; int cond_u3 = u0.coeff[3] == 0; int cond_u5 = u0.coeff[5] == 0; int cond_u7 = u0.coeff[7] == 0; cond_r &= (cond_u1 & cond_u3 & cond_u5 & cond_u7); mask = expand_mask_16bit(cond_r); trgt_deg = 6 & mask; fake_elem = 1 & mask; } r0.patchup_deg_secure(trgt_deg, fake_elem); } // exchange aux = r0; r0 = r1; r1 = aux; aux = u0; u0 = u1; u1 = aux; du = du + delta; delta = 1; while (r1[dr - delta] == 0) { delta++; } dr -= delta; } /* end while loop (dr >= break_deg) */ u1.set_degree( du); r1.set_degree( dr); //return u1 and r1; return std::make_pair(u1,r1); // coefficients u,v } polyn_gf2m::polyn_gf2m(size_t t, RandomNumberGenerator& rng, std::shared_ptr sp_field) :m_deg(static_cast(t)), coeff(t+1), m_sp_field(sp_field) { this->set_coef(t, 1); for(;;) { for(size_t i = 0; i < t; ++i) { this->set_coef(i, random_code_element(sp_field->get_cardinality(), rng)); } const size_t degree = polyn_gf2m::degppf(*this); if(degree >= t) break; } } void polyn_gf2m::poly_shiftmod( const polyn_gf2m & g) { if(g.get_degree() <= 1) { throw Invalid_Argument("shiftmod cannot be called on polynomials of degree 1 or less"); } std::shared_ptr field = g.m_sp_field; int t = g.get_degree(); gf2m a = field->gf_div(this->coeff[t-1], g.coeff[t]); for (int i = t - 1; i > 0; --i) { this->coeff[i] = this->coeff[i - 1] ^ this->m_sp_field->gf_mul(a, g.coeff[i]); } this->coeff[0] = field->gf_mul(a, g.coeff[0]); } std::vector polyn_gf2m::sqrt_mod_init(const polyn_gf2m & g) { uint32_t i, t; uint32_t nb_polyn_sqrt_mat; std::shared_ptr m_sp_field = g.m_sp_field; std::vector result; t = g.get_degree(); nb_polyn_sqrt_mat = t/2; std::vector sq_aux = polyn_gf2m::sqmod_init(g); polyn_gf2m p( t - 1, g.get_sp_field()); p.set_degree( 1); (*&p).set_coef( 1, 1); // q(z) = 0, p(z) = z for (i = 0; i < t * m_sp_field->get_extension_degree() - 1; ++i) { // q(z) <- p(z)^2 mod g(z) polyn_gf2m q = p.sqmod(sq_aux, t); // q(z) <-> p(z) polyn_gf2m aux = q; q = p; p = aux; } // p(z) = z^(2^(tm-1)) mod g(z) = sqrt(z) mod g(z) for (i = 0; i < nb_polyn_sqrt_mat; ++i) { result.push_back(polyn_gf2m(t - 1, g.get_sp_field())); } result[0] = p; result[0].get_degree(); for(i = 1; i < nb_polyn_sqrt_mat; i++) { result[i] = result[i - 1]; result[i].poly_shiftmod(g), result[i].get_degree(); } return result; } std::vector syndrome_init(polyn_gf2m const& generator, std::vector const& support, int n) { int i,j,t; gf2m a; std::shared_ptr m_sp_field = generator.m_sp_field; std::vector result; t = generator.get_degree(); //g(z)=g_t+g_(t-1).z^(t-1)+......+g_1.z+g_0 //f(z)=f_(t-1).z^(t-1)+......+f_1.z+f_0 for(j=0;j=0;i--) { (*&result[j]).set_coef(i, (generator)[i+1] ^ m_sp_field->gf_mul(lex_to_gray(support[j]),result[j][i+1])); } a = ((generator)[0] ^ m_sp_field->gf_mul(lex_to_gray(support[j]),result[j][0])); for(i=0;igf_div(result[j][i],a)); } } return result; } polyn_gf2m::polyn_gf2m(const secure_vector& encoded, std::shared_ptr sp_field ) :m_sp_field(sp_field) { if(encoded.size() % 2) { throw Decoding_Error("encoded polynomial has odd length"); } for(uint32_t i = 0; i < encoded.size(); i += 2) { gf2m el = (encoded[i] << 8) | encoded[i + 1]; coeff.push_back(el); } get_degree(); } secure_vector polyn_gf2m::encode() const { secure_vector result; if(m_deg < 1) { result.push_back(0); result.push_back(0); return result; } uint32_t len = m_deg+1; for(unsigned i = 0; i < len; i++) { // "big endian" encoding of the GF(2^m) elements result.push_back(get_byte(0, coeff[i])); result.push_back(get_byte(1, coeff[i])); } return result; } void polyn_gf2m::swap(polyn_gf2m& other) { std::swap(this->m_deg, other.m_deg); std::swap(this->m_sp_field, other.m_sp_field); std::swap(this->coeff, other.coeff); } bool polyn_gf2m::operator==(const polyn_gf2m & other) const { if(m_deg != other.m_deg || coeff != other.coeff) { return false; } return true; } } /* * McEliece Integrated Encryption System * (C) 2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { secure_vector aead_key(const secure_vector& mk, const AEAD_Mode& aead) { // Fold the key as required for the AEAD mode in use if(aead.valid_keylength(mk.size())) return mk; secure_vector r(aead.key_spec().maximum_keylength()); BOTAN_ASSERT_NOMSG(r.size() > 0); for(size_t i = 0; i != mk.size(); ++i) r[i % r.size()] ^= mk[i]; return r; } } secure_vector mceies_encrypt(const McEliece_PublicKey& pubkey, const uint8_t pt[], size_t pt_len, const uint8_t ad[], size_t ad_len, RandomNumberGenerator& rng, const std::string& algo) { PK_KEM_Encryptor kem_op(pubkey, rng, "KDF1(SHA-512)"); secure_vector mce_ciphertext, mce_key; kem_op.encrypt(mce_ciphertext, mce_key, 64, rng); const size_t mce_code_bytes = (pubkey.get_code_length() + 7) / 8; BOTAN_ASSERT(mce_ciphertext.size() == mce_code_bytes, "Unexpected size"); std::unique_ptr aead = AEAD_Mode::create_or_throw(algo, ENCRYPTION); const size_t nonce_len = aead->default_nonce_length(); aead->set_key(aead_key(mce_key, *aead)); aead->set_associated_data(ad, ad_len); const secure_vector nonce = rng.random_vec(nonce_len); secure_vector msg(mce_ciphertext.size() + nonce.size() + pt_len); copy_mem(msg.data(), mce_ciphertext.data(), mce_ciphertext.size()); copy_mem(msg.data() + mce_ciphertext.size(), nonce.data(), nonce.size()); copy_mem(msg.data() + mce_ciphertext.size() + nonce.size(), pt, pt_len); aead->start(nonce); aead->finish(msg, mce_ciphertext.size() + nonce.size()); return msg; } secure_vector mceies_decrypt(const McEliece_PrivateKey& privkey, const uint8_t ct[], size_t ct_len, const uint8_t ad[], size_t ad_len, const std::string& algo) { try { Null_RNG null_rng; PK_KEM_Decryptor kem_op(privkey, null_rng, "KDF1(SHA-512)"); const size_t mce_code_bytes = (privkey.get_code_length() + 7) / 8; std::unique_ptr aead = AEAD_Mode::create_or_throw(algo, DECRYPTION); const size_t nonce_len = aead->default_nonce_length(); if(ct_len < mce_code_bytes + nonce_len + aead->tag_size()) throw Decoding_Error("Input message too small to be valid"); const secure_vector mce_key = kem_op.decrypt(ct, mce_code_bytes, 64); aead->set_key(aead_key(mce_key, *aead)); aead->set_associated_data(ad, ad_len); secure_vector pt(ct + mce_code_bytes + nonce_len, ct + ct_len); aead->start(&ct[mce_code_bytes], nonce_len); aead->finish(pt, 0); return pt; } catch(Invalid_Authentication_Tag&) { throw; } catch(std::exception& e) { throw Decoding_Error("mce_decrypt failed: " + std::string(e.what())); } } } /* * MD4 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr MD4::copy_state() const { return std::unique_ptr(new MD4(*this)); } namespace { inline void FF4(uint32_t& A, uint32_t& B, uint32_t& C, uint32_t& D, uint32_t M0, uint32_t M1, uint32_t M2, uint32_t M3) { A += (D ^ (B & (C ^ D))) + M0; A = rotl<3>(A); D += (C ^ (A & (B ^ C))) + M1; D = rotl<7>(D); C += (B ^ (D & (A ^ B))) + M2; C = rotl<11>(C); B += (A ^ (C & (D ^ A))) + M3; B = rotl<19>(B); } inline void GG4(uint32_t& A, uint32_t& B, uint32_t& C, uint32_t& D, uint32_t M0, uint32_t M1, uint32_t M2, uint32_t M3) { A += ((B & C) | (D & (B | C))) + M0 + 0x5A827999; A = rotl<3>(A); D += ((A & B) | (C & (A | B))) + M1 + 0x5A827999; D = rotl<5>(D); C += ((D & A) | (B & (D | A))) + M2 + 0x5A827999; C = rotl<9>(C); B += ((C & D) | (A & (C | D))) + M3 + 0x5A827999; B = rotl<13>(B); } inline void HH4(uint32_t& A, uint32_t& B, uint32_t& C, uint32_t& D, uint32_t M0, uint32_t M1, uint32_t M2, uint32_t M3) { A += (B ^ C ^ D) + M0 + 0x6ED9EBA1; A = rotl<3>(A); D += (A ^ B ^ C) + M1 + 0x6ED9EBA1; D = rotl<9>(D); C += (A ^ B ^ D) + M2 + 0x6ED9EBA1; C = rotl<11>(C); B += (A ^ C ^ D) + M3 + 0x6ED9EBA1; B = rotl<15>(B); } } /* * MD4 Compression Function */ void MD4::compress_n(const uint8_t input[], size_t blocks) { uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3]; for(size_t i = 0; i != blocks; ++i) { uint32_t M00 = load_le(input, 0); uint32_t M01 = load_le(input, 1); uint32_t M02 = load_le(input, 2); uint32_t M03 = load_le(input, 3); uint32_t M04 = load_le(input, 4); uint32_t M05 = load_le(input, 5); uint32_t M06 = load_le(input, 6); uint32_t M07 = load_le(input, 7); uint32_t M08 = load_le(input, 8); uint32_t M09 = load_le(input, 9); uint32_t M10 = load_le(input, 10); uint32_t M11 = load_le(input, 11); uint32_t M12 = load_le(input, 12); uint32_t M13 = load_le(input, 13); uint32_t M14 = load_le(input, 14); uint32_t M15 = load_le(input, 15); FF4(A, B, C, D, M00, M01, M02, M03); FF4(A, B, C, D, M04, M05, M06, M07); FF4(A, B, C, D, M08, M09, M10, M11); FF4(A, B, C, D, M12, M13, M14, M15); GG4(A, B, C, D, M00, M04, M08, M12); GG4(A, B, C, D, M01, M05, M09, M13); GG4(A, B, C, D, M02, M06, M10, M14); GG4(A, B, C, D, M03, M07, M11, M15); HH4(A, B, C, D, M00, M08, M04, M12); HH4(A, B, C, D, M02, M10, M06, M14); HH4(A, B, C, D, M01, M09, M05, M13); HH4(A, B, C, D, M03, M11, M07, M15); A = (m_digest[0] += A); B = (m_digest[1] += B); C = (m_digest[2] += C); D = (m_digest[3] += D); input += hash_block_size(); } } /* * Copy out the digest */ void MD4::copy_out(uint8_t output[]) { copy_out_vec_le(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void MD4::clear() { MDx_HashFunction::clear(); m_digest[0] = 0x67452301; m_digest[1] = 0xEFCDAB89; m_digest[2] = 0x98BADCFE; m_digest[3] = 0x10325476; } } /* * MD5 * (C) 1999-2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr MD5::copy_state() const { return std::unique_ptr(new MD5(*this)); } namespace { /* * MD5 FF Function */ template inline void FF(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) { A += (D ^ (B & (C ^ D))) + M; A = rotl(A) + B; } /* * MD5 GG Function */ template inline void GG(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) { A += (C ^ (D & (B ^ C))) + M; A = rotl(A) + B; } /* * MD5 HH Function */ template inline void HH(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) { A += (B ^ C ^ D) + M; A = rotl(A) + B; } /* * MD5 II Function */ template inline void II(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) { A += (C ^ (B | ~D)) + M; A = rotl(A) + B; } } /* * MD5 Compression Function */ void MD5::compress_n(const uint8_t input[], size_t blocks) { uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3]; for(size_t i = 0; i != blocks; ++i) { load_le(m_M.data(), input, m_M.size()); FF< 7>(A,B,C,D,m_M[ 0]+0xD76AA478); FF<12>(D,A,B,C,m_M[ 1]+0xE8C7B756); FF<17>(C,D,A,B,m_M[ 2]+0x242070DB); FF<22>(B,C,D,A,m_M[ 3]+0xC1BDCEEE); FF< 7>(A,B,C,D,m_M[ 4]+0xF57C0FAF); FF<12>(D,A,B,C,m_M[ 5]+0x4787C62A); FF<17>(C,D,A,B,m_M[ 6]+0xA8304613); FF<22>(B,C,D,A,m_M[ 7]+0xFD469501); FF< 7>(A,B,C,D,m_M[ 8]+0x698098D8); FF<12>(D,A,B,C,m_M[ 9]+0x8B44F7AF); FF<17>(C,D,A,B,m_M[10]+0xFFFF5BB1); FF<22>(B,C,D,A,m_M[11]+0x895CD7BE); FF< 7>(A,B,C,D,m_M[12]+0x6B901122); FF<12>(D,A,B,C,m_M[13]+0xFD987193); FF<17>(C,D,A,B,m_M[14]+0xA679438E); FF<22>(B,C,D,A,m_M[15]+0x49B40821); GG< 5>(A,B,C,D,m_M[ 1]+0xF61E2562); GG< 9>(D,A,B,C,m_M[ 6]+0xC040B340); GG<14>(C,D,A,B,m_M[11]+0x265E5A51); GG<20>(B,C,D,A,m_M[ 0]+0xE9B6C7AA); GG< 5>(A,B,C,D,m_M[ 5]+0xD62F105D); GG< 9>(D,A,B,C,m_M[10]+0x02441453); GG<14>(C,D,A,B,m_M[15]+0xD8A1E681); GG<20>(B,C,D,A,m_M[ 4]+0xE7D3FBC8); GG< 5>(A,B,C,D,m_M[ 9]+0x21E1CDE6); GG< 9>(D,A,B,C,m_M[14]+0xC33707D6); GG<14>(C,D,A,B,m_M[ 3]+0xF4D50D87); GG<20>(B,C,D,A,m_M[ 8]+0x455A14ED); GG< 5>(A,B,C,D,m_M[13]+0xA9E3E905); GG< 9>(D,A,B,C,m_M[ 2]+0xFCEFA3F8); GG<14>(C,D,A,B,m_M[ 7]+0x676F02D9); GG<20>(B,C,D,A,m_M[12]+0x8D2A4C8A); HH< 4>(A,B,C,D,m_M[ 5]+0xFFFA3942); HH<11>(D,A,B,C,m_M[ 8]+0x8771F681); HH<16>(C,D,A,B,m_M[11]+0x6D9D6122); HH<23>(B,C,D,A,m_M[14]+0xFDE5380C); HH< 4>(A,B,C,D,m_M[ 1]+0xA4BEEA44); HH<11>(D,A,B,C,m_M[ 4]+0x4BDECFA9); HH<16>(C,D,A,B,m_M[ 7]+0xF6BB4B60); HH<23>(B,C,D,A,m_M[10]+0xBEBFBC70); HH< 4>(A,B,C,D,m_M[13]+0x289B7EC6); HH<11>(D,A,B,C,m_M[ 0]+0xEAA127FA); HH<16>(C,D,A,B,m_M[ 3]+0xD4EF3085); HH<23>(B,C,D,A,m_M[ 6]+0x04881D05); HH< 4>(A,B,C,D,m_M[ 9]+0xD9D4D039); HH<11>(D,A,B,C,m_M[12]+0xE6DB99E5); HH<16>(C,D,A,B,m_M[15]+0x1FA27CF8); HH<23>(B,C,D,A,m_M[ 2]+0xC4AC5665); II< 6>(A,B,C,D,m_M[ 0]+0xF4292244); II<10>(D,A,B,C,m_M[ 7]+0x432AFF97); II<15>(C,D,A,B,m_M[14]+0xAB9423A7); II<21>(B,C,D,A,m_M[ 5]+0xFC93A039); II< 6>(A,B,C,D,m_M[12]+0x655B59C3); II<10>(D,A,B,C,m_M[ 3]+0x8F0CCC92); II<15>(C,D,A,B,m_M[10]+0xFFEFF47D); II<21>(B,C,D,A,m_M[ 1]+0x85845DD1); II< 6>(A,B,C,D,m_M[ 8]+0x6FA87E4F); II<10>(D,A,B,C,m_M[15]+0xFE2CE6E0); II<15>(C,D,A,B,m_M[ 6]+0xA3014314); II<21>(B,C,D,A,m_M[13]+0x4E0811A1); II< 6>(A,B,C,D,m_M[ 4]+0xF7537E82); II<10>(D,A,B,C,m_M[11]+0xBD3AF235); II<15>(C,D,A,B,m_M[ 2]+0x2AD7D2BB); II<21>(B,C,D,A,m_M[ 9]+0xEB86D391); A = (m_digest[0] += A); B = (m_digest[1] += B); C = (m_digest[2] += C); D = (m_digest[3] += D); input += hash_block_size(); } } /* * Copy out the digest */ void MD5::copy_out(uint8_t output[]) { copy_out_vec_le(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void MD5::clear() { MDx_HashFunction::clear(); zeroise(m_M); m_digest[0] = 0x67452301; m_digest[1] = 0xEFCDAB89; m_digest[2] = 0x98BADCFE; m_digest[3] = 0x10325476; } } /* * Merkle-Damgard Hash Function * (C) 1999-2008,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * MDx_HashFunction Constructor */ MDx_HashFunction::MDx_HashFunction(size_t block_len, bool byte_big_endian, bool bit_big_endian, uint8_t cnt_size) : m_pad_char(bit_big_endian == true ? 0x80 : 0x01), m_counter_size(cnt_size), m_block_bits(ceil_log2(block_len)), m_count_big_endian(byte_big_endian), m_count(0), m_buffer(block_len), m_position(0) { if(!is_power_of_2(block_len)) throw Invalid_Argument("MDx_HashFunction block length must be a power of 2"); if(m_block_bits < 3 || m_block_bits > 16) throw Invalid_Argument("MDx_HashFunction block size too large or too small"); if(m_counter_size < 8 || m_counter_size > block_len) throw Invalid_State("MDx_HashFunction invalid counter length"); } /* * Clear memory of sensitive data */ void MDx_HashFunction::clear() { zeroise(m_buffer); m_count = m_position = 0; } /* * Update the hash */ void MDx_HashFunction::add_data(const uint8_t input[], size_t length) { const size_t block_len = static_cast(1) << m_block_bits; m_count += length; if(m_position) { buffer_insert(m_buffer, m_position, input, length); if(m_position + length >= block_len) { compress_n(m_buffer.data(), 1); input += (block_len - m_position); length -= (block_len - m_position); m_position = 0; } } // Just in case the compiler can't figure out block_len is a power of 2 const size_t full_blocks = length >> m_block_bits; const size_t remaining = length & (block_len - 1); if(full_blocks > 0) { compress_n(input, full_blocks); } buffer_insert(m_buffer, m_position, input + full_blocks * block_len, remaining); m_position += remaining; } /* * Finalize a hash */ void MDx_HashFunction::final_result(uint8_t output[]) { const size_t block_len = static_cast(1) << m_block_bits; clear_mem(&m_buffer[m_position], block_len - m_position); m_buffer[m_position] = m_pad_char; if(m_position >= block_len - m_counter_size) { compress_n(m_buffer.data(), 1); zeroise(m_buffer); } write_count(&m_buffer[block_len - m_counter_size]); compress_n(m_buffer.data(), 1); copy_out(output); clear(); } /* * Write the count bits to the buffer */ void MDx_HashFunction::write_count(uint8_t out[]) { BOTAN_ASSERT_NOMSG(m_counter_size <= output_length()); BOTAN_ASSERT_NOMSG(m_counter_size >= 8); const uint64_t bit_count = m_count * 8; if(m_count_big_endian) store_be(bit_count, out + m_counter_size - 8); else store_le(bit_count, out + m_counter_size - 8); } } /* * (C) 2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) #endif namespace Botan { /* * Memory pool theory of operation * * This allocator is not useful for general purpose but works well within the * context of allocating cryptographic keys. It makes several assumptions which * don't work for implementing malloc but simplify and speed up the implementation: * * - There is some set of pages, which cannot be expanded later. These are pages * which were allocated, mlocked and passed to the Memory_Pool constructor. * * - The allocator is allowed to return null anytime it feels like not servicing * a request, in which case the request will be sent to calloc instead. In * particular, requests which are too small or too large are rejected. * * - Most allocations are powers of 2, the remainder are usually a multiple of 8 * * - Free requests include the size of the allocation, so there is no need to * track this within the pool. * * - Alignment is important to the caller. For this allocator, any allocation of * size N is aligned evenly at N bytes. * * Initially each page is in the free page list. Each page is used for just one * size of allocation, with requests bucketed into a small number of common * sizes. If the allocation would be too big or too small it is rejected by the pool. * * The free list is maintained by a bitmap, one per page/Bucket. Since each * Bucket only maintains objects of a single size, each bit set or clear * indicates the status of one object. * * An allocation walks the list of buckets and asks each in turn if there is * space. If a Bucket does not have any space, it sets a boolean flag m_is_full * so that it does not need to rescan when asked again. The flag is cleared on * first free from that bucket. If no bucket has space, but there are some free * pages left, a free page is claimed as a new Bucket for that size. In this case * it is pushed to the front of the list so it is first in line to service new * requests. * * A deallocation also walks the list of buckets for the size and asks each * Bucket in turn if it recognizes the pointer. When a Bucket becomes empty as a * result of a deallocation, it is recycled back into the free pool. When this * happens, the Buckets page goes to the end of the free list. All pages on the * free list are marked in the MMU as noaccess, so anything touching them will * immediately crash. They are only marked R/W once placed into a new bucket. * Making the free list FIFO maximizes the time between the last free of a bucket * and that page being writable again, maximizing chances of crashing after a * use-after-free. * * Future work * ------------- * * The allocator is protected by a global lock. It would be good to break this * up, since almost all of the work can actually be done in parallel especially * when allocating objects of different sizes (which can't possibly share a * bucket). * * It may be worthwhile to optimize deallocation by storing the Buckets in order * (by pointer value) which would allow binary search to find the owning bucket. * * A useful addition would be to randomize the allocations. Memory_Pool would be * changed to receive also a RandomNumberGenerator& object (presumably the system * RNG, or maybe a ChaCha_RNG seeded with system RNG). Then the bucket to use and * the offset within the bucket would be chosen randomly, instead of using first fit. * * Right now we don't make any provision for threading, so if two threads both * allocate 32 byte values one after the other, the two allocations will likely * share a cache line. Ensuring that distinct threads will (tend to) use distinct * buckets would reduce this. * * Supporting a realloc-style API may be useful. */ namespace { size_t choose_bucket(size_t n) { const size_t MINIMUM_ALLOCATION = 16; const size_t MAXIMUM_ALLOCATION = 256; if(n < MINIMUM_ALLOCATION || n > MAXIMUM_ALLOCATION) return 0; // Need to tune these const size_t buckets[] = { 16, 24, 32, 48, 64, 80, 96, 112, 128, 160, 192, 256, 0, }; for(size_t i = 0; buckets[i]; ++i) { if(n <= buckets[i]) { return buckets[i]; } } return 0; } inline bool ptr_in_pool(const void* pool_ptr, size_t poolsize, const void* buf_ptr, size_t bufsize) { const uintptr_t pool = reinterpret_cast(pool_ptr); const uintptr_t buf = reinterpret_cast(buf_ptr); return (buf >= pool) && (buf + bufsize <= pool + poolsize); } // return index of first set bit template size_t find_set_bit(T b) { size_t s = 8*sizeof(T) / 2; size_t bit = 0; // In this context we don't need to be const-time while(s > 0) { const T mask = (static_cast(1) << s) - 1; if((b & mask) == 0) { bit += s; b >>= s; } s /= 2; } return bit; } class BitMap final { public: BitMap(size_t bits) : m_len(bits) { m_bits.resize((bits + BITMASK_BITS - 1) / BITMASK_BITS); m_main_mask = static_cast(~0); m_last_mask = m_main_mask; if(bits % BITMASK_BITS != 0) m_last_mask = (static_cast(1) << (bits % BITMASK_BITS)) - 1; } bool find_free(size_t* bit); void free(size_t bit) { BOTAN_ASSERT_NOMSG(bit <= m_len); const size_t w = bit / BITMASK_BITS; BOTAN_ASSERT_NOMSG(w < m_bits.size()); const bitmask_type mask = static_cast(1) << (bit % BITMASK_BITS); m_bits[w] = m_bits[w] & (~mask); } bool empty() const { for(size_t i = 0; i != m_bits.size(); ++i) { if(m_bits[i] != 0) { return false; } } return true; } private: #if defined(BOTAN_ENABLE_DEBUG_ASSERTS) typedef uint8_t bitmask_type; enum { BITMASK_BITS = 8 }; #else typedef word bitmask_type; enum { BITMASK_BITS = BOTAN_MP_WORD_BITS }; #endif size_t m_len; bitmask_type m_main_mask; bitmask_type m_last_mask; std::vector m_bits; }; bool BitMap::find_free(size_t* bit) { for(size_t i = 0; i != m_bits.size(); ++i) { const bitmask_type mask = (i == m_bits.size() - 1) ? m_last_mask : m_main_mask; if((m_bits[i] & mask) != mask) { size_t free_bit = find_set_bit(~m_bits[i]); const bitmask_type bmask = static_cast(1) << (free_bit % BITMASK_BITS); BOTAN_ASSERT_NOMSG((m_bits[i] & bmask) == 0); m_bits[i] |= bmask; *bit = BITMASK_BITS*i + free_bit; return true; } } return false; } } class Bucket final { public: Bucket(uint8_t* mem, size_t mem_size, size_t item_size) : m_item_size(item_size), m_page_size(mem_size), m_range(mem), m_bitmap(mem_size / item_size), m_is_full(false) { } uint8_t* alloc() { if(m_is_full) { // I know I am full return nullptr; } size_t offset; if(!m_bitmap.find_free(&offset)) { // I just found out I am full m_is_full = true; return nullptr; } BOTAN_ASSERT(offset * m_item_size < m_page_size, "Offset is in range"); return m_range + m_item_size*offset; } bool free(void* p) { if(!in_this_bucket(p)) return false; /* Zero also any trailing bytes, which should not have been written to, but maybe the user was bad and wrote past the end. */ std::memset(p, 0, m_item_size); const size_t offset = (reinterpret_cast(p) - reinterpret_cast(m_range)) / m_item_size; m_bitmap.free(offset); m_is_full = false; return true; } bool in_this_bucket(void* p) const { return ptr_in_pool(m_range, m_page_size, p, m_item_size); } bool empty() const { return m_bitmap.empty(); } uint8_t* ptr() const { return m_range; } private: size_t m_item_size; size_t m_page_size; uint8_t* m_range; BitMap m_bitmap; bool m_is_full; }; Memory_Pool::Memory_Pool(const std::vector& pages, size_t page_size) : m_page_size(page_size) { m_min_page_ptr = ~static_cast(0); m_max_page_ptr = 0; for(size_t i = 0; i != pages.size(); ++i) { const uintptr_t p = reinterpret_cast(pages[i]); m_min_page_ptr = std::min(p, m_min_page_ptr); m_max_page_ptr = std::max(p, m_max_page_ptr); clear_bytes(pages[i], m_page_size); #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) OS::page_prohibit_access(pages[i]); #endif m_free_pages.push_back(static_cast(pages[i])); } /* Right now this points to the start of the last page, adjust it to instead point to the first byte of the following page */ m_max_page_ptr += page_size; } Memory_Pool::~Memory_Pool() { #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) for(size_t i = 0; i != m_free_pages.size(); ++i) { OS::page_allow_access(m_free_pages[i]); } #endif } void* Memory_Pool::allocate(size_t n) { if(n > m_page_size) return nullptr; const size_t n_bucket = choose_bucket(n); if(n_bucket > 0) { lock_guard_type lock(m_mutex); std::deque& buckets = m_buckets_for[n_bucket]; /* It would be optimal to pick the bucket with the most usage, since a bucket with say 1 item allocated out of it has a high chance of becoming later freed and then the whole page can be recycled. */ for(auto& bucket : buckets) { if(uint8_t* p = bucket.alloc()) return p; // If the bucket is full, maybe move it to the end of the list? // Otoh bucket search should be very fast } if(m_free_pages.size() > 0) { uint8_t* ptr = m_free_pages[0]; m_free_pages.pop_front(); #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) OS::page_allow_access(ptr); #endif buckets.push_front(Bucket(ptr, m_page_size, n_bucket)); void* p = buckets[0].alloc(); BOTAN_ASSERT_NOMSG(p != nullptr); return p; } } // out of room return nullptr; } bool Memory_Pool::deallocate(void* p, size_t len) noexcept { // Do a fast range check first, before taking the lock const uintptr_t p_val = reinterpret_cast(p); if(p_val < m_min_page_ptr || p_val > m_max_page_ptr) return false; const size_t n_bucket = choose_bucket(len); if(n_bucket != 0) { try { lock_guard_type lock(m_mutex); std::deque& buckets = m_buckets_for[n_bucket]; for(size_t i = 0; i != buckets.size(); ++i) { Bucket& bucket = buckets[i]; if(bucket.free(p)) { if(bucket.empty()) { #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) OS::page_prohibit_access(bucket.ptr()); #endif m_free_pages.push_back(bucket.ptr()); if(i != buckets.size() - 1) std::swap(buckets.back(), buckets[i]); buckets.pop_back(); } return true; } } } catch(...) { /* * The only exception throws that can occur in the above code are from * either the STL or BOTAN_ASSERT failures. In either case, such an * error indicates a logic error or data corruption in the memory * allocator such that it is no longer safe to continue executing. * * Since this function is noexcept, simply letting the exception escape * is sufficient for terminate to be called. However in this scenario * it is implementation defined if any stack unwinding is performed. * Since stack unwinding could cause further memory deallocations this * could result in further corruption in this allocator state. To prevent * this, call terminate directly. */ std::terminate(); } } return false; } } /* * MGF1 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void mgf1_mask(HashFunction& hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len) { uint32_t counter = 0; secure_vector buffer(hash.output_length()); while(out_len) { hash.update(in, in_len); hash.update_be(counter); hash.final(buffer.data()); const size_t xored = std::min(buffer.size(), out_len); xor_buf(out, buffer.data(), xored); out += xored; out_len -= xored; ++counter; } } } /* * MISTY1 * (C) 1999-2009 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { alignas(64) static const uint8_t MISTY1_SBOX_S7[128] = { 0x1B, 0x32, 0x33, 0x5A, 0x3B, 0x10, 0x17, 0x54, 0x5B, 0x1A, 0x72, 0x73, 0x6B, 0x2C, 0x66, 0x49, 0x1F, 0x24, 0x13, 0x6C, 0x37, 0x2E, 0x3F, 0x4A, 0x5D, 0x0F, 0x40, 0x56, 0x25, 0x51, 0x1C, 0x04, 0x0B, 0x46, 0x20, 0x0D, 0x7B, 0x35, 0x44, 0x42, 0x2B, 0x1E, 0x41, 0x14, 0x4B, 0x79, 0x15, 0x6F, 0x0E, 0x55, 0x09, 0x36, 0x74, 0x0C, 0x67, 0x53, 0x28, 0x0A, 0x7E, 0x38, 0x02, 0x07, 0x60, 0x29, 0x19, 0x12, 0x65, 0x2F, 0x30, 0x39, 0x08, 0x68, 0x5F, 0x78, 0x2A, 0x4C, 0x64, 0x45, 0x75, 0x3D, 0x59, 0x48, 0x03, 0x57, 0x7C, 0x4F, 0x62, 0x3C, 0x1D, 0x21, 0x5E, 0x27, 0x6A, 0x70, 0x4D, 0x3A, 0x01, 0x6D, 0x6E, 0x63, 0x18, 0x77, 0x23, 0x05, 0x26, 0x76, 0x00, 0x31, 0x2D, 0x7A, 0x7F, 0x61, 0x50, 0x22, 0x11, 0x06, 0x47, 0x16, 0x52, 0x4E, 0x71, 0x3E, 0x69, 0x43, 0x34, 0x5C, 0x58, 0x7D }; alignas(64) static const uint16_t MISTY1_SBOX_S9[512] = { 0x01C3, 0x00CB, 0x0153, 0x019F, 0x01E3, 0x00E9, 0x00FB, 0x0035, 0x0181, 0x00B9, 0x0117, 0x01EB, 0x0133, 0x0009, 0x002D, 0x00D3, 0x00C7, 0x014A, 0x0037, 0x007E, 0x00EB, 0x0164, 0x0193, 0x01D8, 0x00A3, 0x011E, 0x0055, 0x002C, 0x001D, 0x01A2, 0x0163, 0x0118, 0x014B, 0x0152, 0x01D2, 0x000F, 0x002B, 0x0030, 0x013A, 0x00E5, 0x0111, 0x0138, 0x018E, 0x0063, 0x00E3, 0x00C8, 0x01F4, 0x001B, 0x0001, 0x009D, 0x00F8, 0x01A0, 0x016D, 0x01F3, 0x001C, 0x0146, 0x007D, 0x00D1, 0x0082, 0x01EA, 0x0183, 0x012D, 0x00F4, 0x019E, 0x01D3, 0x00DD, 0x01E2, 0x0128, 0x01E0, 0x00EC, 0x0059, 0x0091, 0x0011, 0x012F, 0x0026, 0x00DC, 0x00B0, 0x018C, 0x010F, 0x01F7, 0x00E7, 0x016C, 0x00B6, 0x00F9, 0x00D8, 0x0151, 0x0101, 0x014C, 0x0103, 0x00B8, 0x0154, 0x012B, 0x01AE, 0x0017, 0x0071, 0x000C, 0x0047, 0x0058, 0x007F, 0x01A4, 0x0134, 0x0129, 0x0084, 0x015D, 0x019D, 0x01B2, 0x01A3, 0x0048, 0x007C, 0x0051, 0x01CA, 0x0023, 0x013D, 0x01A7, 0x0165, 0x003B, 0x0042, 0x00DA, 0x0192, 0x00CE, 0x00C1, 0x006B, 0x009F, 0x01F1, 0x012C, 0x0184, 0x00FA, 0x0196, 0x01E1, 0x0169, 0x017D, 0x0031, 0x0180, 0x010A, 0x0094, 0x01DA, 0x0186, 0x013E, 0x011C, 0x0060, 0x0175, 0x01CF, 0x0067, 0x0119, 0x0065, 0x0068, 0x0099, 0x0150, 0x0008, 0x0007, 0x017C, 0x00B7, 0x0024, 0x0019, 0x00DE, 0x0127, 0x00DB, 0x00E4, 0x01A9, 0x0052, 0x0109, 0x0090, 0x019C, 0x01C1, 0x0028, 0x01B3, 0x0135, 0x016A, 0x0176, 0x00DF, 0x01E5, 0x0188, 0x00C5, 0x016E, 0x01DE, 0x01B1, 0x00C3, 0x01DF, 0x0036, 0x00EE, 0x01EE, 0x00F0, 0x0093, 0x0049, 0x009A, 0x01B6, 0x0069, 0x0081, 0x0125, 0x000B, 0x005E, 0x00B4, 0x0149, 0x01C7, 0x0174, 0x003E, 0x013B, 0x01B7, 0x008E, 0x01C6, 0x00AE, 0x0010, 0x0095, 0x01EF, 0x004E, 0x00F2, 0x01FD, 0x0085, 0x00FD, 0x00F6, 0x00A0, 0x016F, 0x0083, 0x008A, 0x0156, 0x009B, 0x013C, 0x0107, 0x0167, 0x0098, 0x01D0, 0x01E9, 0x0003, 0x01FE, 0x00BD, 0x0122, 0x0089, 0x00D2, 0x018F, 0x0012, 0x0033, 0x006A, 0x0142, 0x00ED, 0x0170, 0x011B, 0x00E2, 0x014F, 0x0158, 0x0131, 0x0147, 0x005D, 0x0113, 0x01CD, 0x0079, 0x0161, 0x01A5, 0x0179, 0x009E, 0x01B4, 0x00CC, 0x0022, 0x0132, 0x001A, 0x00E8, 0x0004, 0x0187, 0x01ED, 0x0197, 0x0039, 0x01BF, 0x01D7, 0x0027, 0x018B, 0x00C6, 0x009C, 0x00D0, 0x014E, 0x006C, 0x0034, 0x01F2, 0x006E, 0x00CA, 0x0025, 0x00BA, 0x0191, 0x00FE, 0x0013, 0x0106, 0x002F, 0x01AD, 0x0172, 0x01DB, 0x00C0, 0x010B, 0x01D6, 0x00F5, 0x01EC, 0x010D, 0x0076, 0x0114, 0x01AB, 0x0075, 0x010C, 0x01E4, 0x0159, 0x0054, 0x011F, 0x004B, 0x00C4, 0x01BE, 0x00F7, 0x0029, 0x00A4, 0x000E, 0x01F0, 0x0077, 0x004D, 0x017A, 0x0086, 0x008B, 0x00B3, 0x0171, 0x00BF, 0x010E, 0x0104, 0x0097, 0x015B, 0x0160, 0x0168, 0x00D7, 0x00BB, 0x0066, 0x01CE, 0x00FC, 0x0092, 0x01C5, 0x006F, 0x0016, 0x004A, 0x00A1, 0x0139, 0x00AF, 0x00F1, 0x0190, 0x000A, 0x01AA, 0x0143, 0x017B, 0x0056, 0x018D, 0x0166, 0x00D4, 0x01FB, 0x014D, 0x0194, 0x019A, 0x0087, 0x01F8, 0x0123, 0x00A7, 0x01B8, 0x0141, 0x003C, 0x01F9, 0x0140, 0x002A, 0x0155, 0x011A, 0x01A1, 0x0198, 0x00D5, 0x0126, 0x01AF, 0x0061, 0x012E, 0x0157, 0x01DC, 0x0072, 0x018A, 0x00AA, 0x0096, 0x0115, 0x00EF, 0x0045, 0x007B, 0x008D, 0x0145, 0x0053, 0x005F, 0x0178, 0x00B2, 0x002E, 0x0020, 0x01D5, 0x003F, 0x01C9, 0x01E7, 0x01AC, 0x0044, 0x0038, 0x0014, 0x00B1, 0x016B, 0x00AB, 0x00B5, 0x005A, 0x0182, 0x01C8, 0x01D4, 0x0018, 0x0177, 0x0064, 0x00CF, 0x006D, 0x0100, 0x0199, 0x0130, 0x015A, 0x0005, 0x0120, 0x01BB, 0x01BD, 0x00E0, 0x004F, 0x00D6, 0x013F, 0x01C4, 0x012A, 0x0015, 0x0006, 0x00FF, 0x019B, 0x00A6, 0x0043, 0x0088, 0x0050, 0x015F, 0x01E8, 0x0121, 0x0073, 0x017E, 0x00BC, 0x00C2, 0x00C9, 0x0173, 0x0189, 0x01F5, 0x0074, 0x01CC, 0x01E6, 0x01A8, 0x0195, 0x001F, 0x0041, 0x000D, 0x01BA, 0x0032, 0x003D, 0x01D1, 0x0080, 0x00A8, 0x0057, 0x01B9, 0x0162, 0x0148, 0x00D9, 0x0105, 0x0062, 0x007A, 0x0021, 0x01FF, 0x0112, 0x0108, 0x01C0, 0x00A9, 0x011D, 0x01B0, 0x01A6, 0x00CD, 0x00F3, 0x005C, 0x0102, 0x005B, 0x01D9, 0x0144, 0x01F6, 0x00AD, 0x00A5, 0x003A, 0x01CB, 0x0136, 0x017F, 0x0046, 0x00E1, 0x001E, 0x01DD, 0x00E6, 0x0137, 0x01FA, 0x0185, 0x008C, 0x008F, 0x0040, 0x01B5, 0x00BE, 0x0078, 0x0000, 0x00AC, 0x0110, 0x015E, 0x0124, 0x0002, 0x01BC, 0x00A2, 0x00EA, 0x0070, 0x01FC, 0x0116, 0x015C, 0x004C, 0x01C2 }; /* * MISTY1 FI Function */ uint16_t FI(uint16_t input, uint16_t key7, uint16_t key9) { uint16_t D9 = input >> 7, D7 = input & 0x7F; D9 = MISTY1_SBOX_S9[D9] ^ D7; D7 = (MISTY1_SBOX_S7[D7] ^ key7 ^ D9) & 0x7F; D9 = MISTY1_SBOX_S9[D9 ^ key9] ^ D7; return static_cast(D7 << 9) | D9; } } /* * MISTY1 Encryption */ void MISTY1::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be(in, 0); uint16_t B1 = load_be(in, 1); uint16_t B2 = load_be(in, 2); uint16_t B3 = load_be(in, 3); for(size_t j = 0; j != 12; j += 3) { const uint16_t* RK = &m_EK[8 * j]; B1 ^= B0 & RK[0]; B0 ^= B1 | RK[1]; B3 ^= B2 & RK[2]; B2 ^= B3 | RK[3]; uint16_t T0, T1; T0 = FI(B0 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B1; T1 = FI(B1 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; B2 ^= T1 ^ RK[13]; B3 ^= T0; T0 = FI(B2 ^ RK[14], RK[15], RK[16]) ^ B3; T1 = FI(B3 ^ RK[17], RK[18], RK[19]) ^ T0; T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; B0 ^= T1 ^ RK[23]; B1 ^= T0; } B1 ^= B0 & m_EK[96]; B0 ^= B1 | m_EK[97]; B3 ^= B2 & m_EK[98]; B2 ^= B3 | m_EK[99]; store_be(out, B2, B3, B0, B1); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * MISTY1 Decryption */ void MISTY1::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DK.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be(in, 2); uint16_t B1 = load_be(in, 3); uint16_t B2 = load_be(in, 0); uint16_t B3 = load_be(in, 1); for(size_t j = 0; j != 12; j += 3) { const uint16_t* RK = &m_DK[8 * j]; B2 ^= B3 | RK[0]; B3 ^= B2 & RK[1]; B0 ^= B1 | RK[2]; B1 ^= B0 & RK[3]; uint16_t T0, T1; T0 = FI(B2 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B3; T1 = FI(B3 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; B0 ^= T1 ^ RK[13]; B1 ^= T0; T0 = FI(B0 ^ RK[14], RK[15], RK[16]) ^ B1; T1 = FI(B1 ^ RK[17], RK[18], RK[19]) ^ T0; T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; B2 ^= T1 ^ RK[23]; B3 ^= T0; } B2 ^= B3 | m_DK[96]; B3 ^= B2 & m_DK[97]; B0 ^= B1 | m_DK[98]; B1 ^= B0 & m_DK[99]; store_be(out, B0, B1, B2, B3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * MISTY1 Key Schedule */ void MISTY1::key_schedule(const uint8_t key[], size_t length) { secure_vector KS(32); for(size_t i = 0; i != length / 2; ++i) KS[i] = load_be(key, i); for(size_t i = 0; i != 8; ++i) { KS[i+ 8] = FI(KS[i], KS[(i+1) % 8] >> 9, KS[(i+1) % 8] & 0x1FF); KS[i+16] = KS[i+8] >> 9; KS[i+24] = KS[i+8] & 0x1FF; } /* * Precomputed indexes for the orderings of the subkeys (MISTY1 reuses * values) */ static const uint8_t EK_ORDER[100] = { 0x00, 0x0E, 0x0A, 0x04, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, 0x1B, 0x04, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, 0x1C, 0x05, 0x01, 0x0F, 0x0B, 0x05, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, 0x1D, 0x06, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, 0x1E, 0x07, 0x02, 0x08, 0x0C, 0x06, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, 0x1F, 0x00, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, 0x18, 0x01, 0x03, 0x09, 0x0D, 0x07, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, 0x19, 0x02, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, 0x1A, 0x03, 0x04, 0x0A, 0x0E, 0x00 }; static const uint8_t DK_ORDER[100] = { 0x00, 0x0E, 0x0A, 0x04, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, 0x1A, 0x03, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, 0x19, 0x02, 0x07, 0x0D, 0x09, 0x03, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, 0x18, 0x01, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, 0x1F, 0x00, 0x06, 0x0C, 0x08, 0x02, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, 0x1E, 0x07, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, 0x1D, 0x06, 0x05, 0x0B, 0x0F, 0x01, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, 0x1C, 0x05, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, 0x1B, 0x04, 0x04, 0x0A, 0x0E, 0x00 }; m_EK.resize(100); m_DK.resize(100); for(size_t i = 0; i != 100; ++i) { m_EK[i] = KS[EK_ORDER[i]]; m_DK[i] = KS[DK_ORDER[i]]; } } void MISTY1::clear() { zap(m_EK); zap(m_DK); } } /* * CBC Padding Methods * (C) 1999-2007,2013,2018,2020 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /** * Get a block cipher padding method by name */ BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec) { if(algo_spec == "NoPadding") return new Null_Padding; if(algo_spec == "PKCS7") return new PKCS7_Padding; if(algo_spec == "OneAndZeros") return new OneAndZeros_Padding; if(algo_spec == "X9.23") return new ANSI_X923_Padding; if(algo_spec == "ESP") return new ESP_Padding; return nullptr; } /* * Pad with PKCS #7 Method */ void PKCS7_Padding::add_padding(secure_vector& buffer, size_t last_byte_pos, size_t BS) const { /* Padding format is 01 0202 030303 ... */ BOTAN_DEBUG_ASSERT(last_byte_pos < BS); const uint8_t padding_len = static_cast(BS - last_byte_pos); buffer.resize(buffer.size() + padding_len); CT::poison(&last_byte_pos, 1); CT::poison(buffer.data(), buffer.size()); BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); BOTAN_DEBUG_ASSERT(buffer.size() >= BS); const size_t start_of_last_block = buffer.size() - BS; const size_t end_of_last_block = buffer.size(); const size_t start_of_padding = buffer.size() - padding_len; for(size_t i = start_of_last_block; i != end_of_last_block; ++i) { auto needs_padding = CT::Mask(CT::Mask::is_gte(i, start_of_padding)); buffer[i] = needs_padding.select(padding_len, buffer[i]); } CT::unpoison(buffer.data(), buffer.size()); CT::unpoison(last_byte_pos); } /* * Unpad with PKCS #7 Method */ size_t PKCS7_Padding::unpad(const uint8_t input[], size_t input_length) const { if(!valid_blocksize(input_length)) return input_length; CT::poison(input, input_length); const uint8_t last_byte = input[input_length-1]; /* The input should == the block size so if the last byte exceeds that then the padding is certainly invalid */ auto bad_input = CT::Mask::is_gt(last_byte, input_length); const size_t pad_pos = input_length - last_byte; for(size_t i = 0; i != input_length - 1; ++i) { // Does this byte equal the expected pad byte? const auto pad_eq = CT::Mask::is_equal(input[i], last_byte); // Ignore values that are not part of the padding const auto in_range = CT::Mask::is_gte(i, pad_pos); bad_input |= in_range & (~pad_eq); } CT::unpoison(input, input_length); return bad_input.select_and_unpoison(input_length, pad_pos); } /* * Pad with ANSI X9.23 Method */ void ANSI_X923_Padding::add_padding(secure_vector& buffer, size_t last_byte_pos, size_t BS) const { /* Padding format is 01 0002 000003 ... */ BOTAN_DEBUG_ASSERT(last_byte_pos < BS); const uint8_t padding_len = static_cast(BS - last_byte_pos); buffer.resize(buffer.size() + padding_len); CT::poison(&last_byte_pos, 1); CT::poison(buffer.data(), buffer.size()); BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); BOTAN_DEBUG_ASSERT(buffer.size() >= BS); const size_t start_of_last_block = buffer.size() - BS; const size_t end_of_zero_padding = buffer.size() - 1; const size_t start_of_padding = buffer.size() - padding_len; for(size_t i = start_of_last_block; i != end_of_zero_padding; ++i) { auto needs_padding = CT::Mask(CT::Mask::is_gte(i, start_of_padding)); buffer[i] = needs_padding.select(0, buffer[i]); } buffer[buffer.size()-1] = padding_len; CT::unpoison(buffer.data(), buffer.size()); CT::unpoison(last_byte_pos); } /* * Unpad with ANSI X9.23 Method */ size_t ANSI_X923_Padding::unpad(const uint8_t input[], size_t input_length) const { if(!valid_blocksize(input_length)) return input_length; CT::poison(input, input_length); const size_t last_byte = input[input_length-1]; auto bad_input = CT::Mask::is_gt(last_byte, input_length); const size_t pad_pos = input_length - last_byte; for(size_t i = 0; i != input_length - 1; ++i) { // Ignore values that are not part of the padding const auto in_range = CT::Mask::is_gte(i, pad_pos); const auto pad_is_nonzero = CT::Mask::expand(input[i]); bad_input |= pad_is_nonzero & in_range; } CT::unpoison(input, input_length); return bad_input.select_and_unpoison(input_length, pad_pos); } /* * Pad with One and Zeros Method */ void OneAndZeros_Padding::add_padding(secure_vector& buffer, size_t last_byte_pos, size_t BS) const { /* Padding format is 80 8000 800000 ... */ BOTAN_DEBUG_ASSERT(last_byte_pos < BS); const uint8_t padding_len = static_cast(BS - last_byte_pos); buffer.resize(buffer.size() + padding_len); CT::poison(&last_byte_pos, 1); CT::poison(buffer.data(), buffer.size()); BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); BOTAN_DEBUG_ASSERT(buffer.size() >= BS); const size_t start_of_last_block = buffer.size() - BS; const size_t end_of_last_block = buffer.size(); const size_t start_of_padding = buffer.size() - padding_len; for(size_t i = start_of_last_block; i != end_of_last_block; ++i) { auto needs_80 = CT::Mask(CT::Mask::is_equal(i, start_of_padding)); auto needs_00 = CT::Mask(CT::Mask::is_gt(i, start_of_padding)); buffer[i] = needs_00.select(0x00, needs_80.select(0x80, buffer[i])); } CT::unpoison(buffer.data(), buffer.size()); CT::unpoison(last_byte_pos); } /* * Unpad with One and Zeros Method */ size_t OneAndZeros_Padding::unpad(const uint8_t input[], size_t input_length) const { if(!valid_blocksize(input_length)) return input_length; CT::poison(input, input_length); auto bad_input = CT::Mask::cleared(); auto seen_0x80 = CT::Mask::cleared(); size_t pad_pos = input_length - 1; size_t i = input_length; while(i) { const auto is_0x80 = CT::Mask::is_equal(input[i-1], 0x80); const auto is_zero = CT::Mask::is_zero(input[i-1]); seen_0x80 |= is_0x80; pad_pos -= seen_0x80.if_not_set_return(1); bad_input |= ~seen_0x80 & ~is_zero; i--; } bad_input |= ~seen_0x80; CT::unpoison(input, input_length); return CT::Mask::expand(bad_input).select_and_unpoison(input_length, pad_pos); } /* * Pad with ESP Padding Method */ void ESP_Padding::add_padding(secure_vector& buffer, size_t last_byte_pos, size_t BS) const { /* Padding format is 01 0102 010203 ... */ BOTAN_DEBUG_ASSERT(last_byte_pos < BS); const uint8_t padding_len = static_cast(BS - last_byte_pos); buffer.resize(buffer.size() + padding_len); CT::poison(&last_byte_pos, 1); CT::poison(buffer.data(), buffer.size()); BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); BOTAN_DEBUG_ASSERT(buffer.size() >= BS); const size_t start_of_last_block = buffer.size() - BS; const size_t end_of_last_block = buffer.size(); const size_t start_of_padding = buffer.size() - padding_len; uint8_t pad_ctr = 0x01; for(size_t i = start_of_last_block; i != end_of_last_block; ++i) { auto needs_padding = CT::Mask(CT::Mask::is_gte(i, start_of_padding)); buffer[i] = needs_padding.select(pad_ctr, buffer[i]); pad_ctr = needs_padding.select(pad_ctr + 1, pad_ctr); } CT::unpoison(buffer.data(), buffer.size()); CT::unpoison(last_byte_pos); } /* * Unpad with ESP Padding Method */ size_t ESP_Padding::unpad(const uint8_t input[], size_t input_length) const { if(!valid_blocksize(input_length)) return input_length; CT::poison(input, input_length); const uint8_t input_length_8 = static_cast(input_length); const uint8_t last_byte = input[input_length-1]; auto bad_input = CT::Mask::is_zero(last_byte) | CT::Mask::is_gt(last_byte, input_length_8); const uint8_t pad_pos = input_length_8 - last_byte; size_t i = input_length_8 - 1; while(i) { const auto in_range = CT::Mask::is_gt(i, pad_pos); const auto incrementing = CT::Mask::is_equal(input[i-1], input[i]-1); bad_input |= CT::Mask(in_range) & ~incrementing; --i; } CT::unpoison(input, input_length); return bad_input.select_and_unpoison(input_length_8, pad_pos); } } /* * Cipher Modes * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_BLOCK_CIPHER) #endif #if defined(BOTAN_HAS_AEAD_MODES) #endif #if defined(BOTAN_HAS_MODE_CBC) #endif #if defined(BOTAN_HAS_MODE_CFB) #endif #if defined(BOTAN_HAS_MODE_XTS) #endif #if defined(BOTAN_HAS_OPENSSL) #endif #if defined(BOTAN_HAS_COMMONCRYPTO) #endif namespace Botan { std::unique_ptr Cipher_Mode::create_or_throw(const std::string& algo, Cipher_Dir direction, const std::string& provider) { if(auto mode = Cipher_Mode::create(algo, direction, provider)) return mode; throw Lookup_Error("Cipher mode", algo, provider); } std::unique_ptr Cipher_Mode::create(const std::string& algo, Cipher_Dir direction, const std::string& provider) { #if defined(BOTAN_HAS_COMMONCRYPTO) if(provider.empty() || provider == "commoncrypto") { std::unique_ptr commoncrypto_cipher(make_commoncrypto_cipher_mode(algo, direction)); if(commoncrypto_cipher) return commoncrypto_cipher; if(!provider.empty()) return std::unique_ptr(); } #endif #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { std::unique_ptr openssl_cipher(make_openssl_cipher_mode(algo, direction)); if(openssl_cipher) return openssl_cipher; if(!provider.empty()) return std::unique_ptr(); } #endif #if defined(BOTAN_HAS_STREAM_CIPHER) if(auto sc = StreamCipher::create(algo)) { return std::unique_ptr(new Stream_Cipher_Mode(sc.release())); } #endif #if defined(BOTAN_HAS_AEAD_MODES) if(auto aead = AEAD_Mode::create(algo, direction)) { return std::unique_ptr(aead.release()); } #endif if(algo.find('/') != std::string::npos) { const std::vector algo_parts = split_on(algo, '/'); const std::string cipher_name = algo_parts[0]; const std::vector mode_info = parse_algorithm_name(algo_parts[1]); if(mode_info.empty()) return std::unique_ptr(); std::ostringstream alg_args; alg_args << '(' << cipher_name; for(size_t i = 1; i < mode_info.size(); ++i) alg_args << ',' << mode_info[i]; for(size_t i = 2; i < algo_parts.size(); ++i) alg_args << ',' << algo_parts[i]; alg_args << ')'; const std::string mode_name = mode_info[0] + alg_args.str(); return Cipher_Mode::create(mode_name, direction, provider); } #if defined(BOTAN_HAS_BLOCK_CIPHER) SCAN_Name spec(algo); if(spec.arg_count() == 0) { return std::unique_ptr(); } std::unique_ptr bc(BlockCipher::create(spec.arg(0), provider)); if(!bc) { return std::unique_ptr(); } #if defined(BOTAN_HAS_MODE_CBC) if(spec.algo_name() == "CBC") { const std::string padding = spec.arg(1, "PKCS7"); if(padding == "CTS") { if(direction == ENCRYPTION) return std::unique_ptr(new CTS_Encryption(bc.release())); else return std::unique_ptr(new CTS_Decryption(bc.release())); } else { std::unique_ptr pad(get_bc_pad(padding)); if(pad) { if(direction == ENCRYPTION) return std::unique_ptr(new CBC_Encryption(bc.release(), pad.release())); else return std::unique_ptr(new CBC_Decryption(bc.release(), pad.release())); } } } #endif #if defined(BOTAN_HAS_MODE_XTS) if(spec.algo_name() == "XTS") { if(direction == ENCRYPTION) return std::unique_ptr(new XTS_Encryption(bc.release())); else return std::unique_ptr(new XTS_Decryption(bc.release())); } #endif #if defined(BOTAN_HAS_MODE_CFB) if(spec.algo_name() == "CFB") { const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size()); if(direction == ENCRYPTION) return std::unique_ptr(new CFB_Encryption(bc.release(), feedback_bits)); else return std::unique_ptr(new CFB_Decryption(bc.release(), feedback_bits)); } #endif #endif return std::unique_ptr(); } //static std::vector Cipher_Mode::providers(const std::string& algo_spec) { const std::vector& possible = { "base", "openssl", "commoncrypto" }; std::vector providers; for(auto&& prov : possible) { std::unique_ptr mode = Cipher_Mode::create(algo_spec, ENCRYPTION, prov); if(mode) { providers.push_back(prov); // available } } return providers; } } /* * Comba Multiplication and Squaring * * This file was automatically generated by ./src/scripts/comba.py on 2018-05-08 * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Comba 4x4 Squaring */ void bigint_comba_sqr4(word z[8], const word x[4]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); z[ 0] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); z[ 1] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); z[ 2] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); z[ 3] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); z[ 4] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); z[ 5] = w2; w2 = 0; word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); z[ 6] = w0; z[ 7] = w1; } /* * Comba 4x4 Multiplication */ void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); z[ 0] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); z[ 1] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); z[ 2] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); z[ 3] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); z[ 4] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); z[ 5] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); z[ 6] = w0; z[ 7] = w1; } /* * Comba 6x6 Squaring */ void bigint_comba_sqr6(word z[12], const word x[6]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); z[ 0] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); z[ 1] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); z[ 2] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); z[ 3] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); z[ 4] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); z[ 5] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); z[ 6] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); z[ 7] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); z[ 8] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); z[ 9] = w0; w0 = 0; word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); z[10] = w1; z[11] = w2; } /* * Comba 6x6 Multiplication */ void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); z[ 0] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); z[ 1] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); z[ 2] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); z[ 3] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); z[ 4] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); z[ 5] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); z[ 6] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); z[ 7] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); z[ 8] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); z[ 9] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); z[10] = w1; z[11] = w2; } /* * Comba 8x8 Squaring */ void bigint_comba_sqr8(word z[16], const word x[8]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); z[ 0] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); z[ 1] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); z[ 2] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); z[ 3] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); z[ 4] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); z[ 5] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); z[ 6] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); z[ 7] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); z[ 8] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); z[ 9] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); z[10] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); z[11] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); z[12] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); z[13] = w1; w1 = 0; word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); z[14] = w2; z[15] = w0; } /* * Comba 8x8 Multiplication */ void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); z[ 0] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); z[ 1] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); z[ 2] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); z[ 3] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); z[ 4] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); z[ 5] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); z[ 6] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); z[ 7] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); z[ 8] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); z[ 9] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); z[10] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); z[11] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); z[12] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); z[13] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); z[14] = w2; z[15] = w0; } /* * Comba 9x9 Squaring */ void bigint_comba_sqr9(word z[18], const word x[9]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); z[ 0] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); z[ 1] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); z[ 2] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); z[ 3] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); z[ 4] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); z[ 5] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); z[ 6] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); z[ 7] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); z[ 8] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); z[ 9] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); z[10] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); z[11] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); z[12] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); z[13] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); z[14] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); z[15] = w0; w0 = 0; word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); z[16] = w1; z[17] = w2; } /* * Comba 9x9 Multiplication */ void bigint_comba_mul9(word z[18], const word x[9], const word y[9]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); z[ 0] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); z[ 1] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); z[ 2] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); z[ 3] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); z[ 4] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); z[ 5] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); z[ 6] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); z[ 7] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); z[ 8] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); z[ 9] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); z[10] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); z[11] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); z[12] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); z[13] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); z[14] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); z[15] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); z[16] = w1; z[17] = w2; } /* * Comba 16x16 Squaring */ void bigint_comba_sqr16(word z[32], const word x[16]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); z[ 0] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); z[ 1] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); z[ 2] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); z[ 3] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); z[ 4] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); z[ 5] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); z[ 6] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); z[ 7] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); z[ 8] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); z[ 9] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); z[10] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); z[11] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); z[12] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); z[13] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); z[14] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); z[15] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); z[16] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); z[17] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); word3_muladd (&w2, &w1, &w0, x[ 9], x[ 9]); z[18] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); z[19] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); word3_muladd (&w1, &w0, &w2, x[10], x[10]); z[20] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); z[21] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); word3_muladd (&w0, &w2, &w1, x[11], x[11]); z[22] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); z[23] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); word3_muladd (&w2, &w1, &w0, x[12], x[12]); z[24] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); z[25] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); word3_muladd (&w1, &w0, &w2, x[13], x[13]); z[26] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); z[27] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); word3_muladd (&w0, &w2, &w1, x[14], x[14]); z[28] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); z[29] = w2; w2 = 0; word3_muladd (&w2, &w1, &w0, x[15], x[15]); z[30] = w0; z[31] = w1; } /* * Comba 16x16 Multiplication */ void bigint_comba_mul16(word z[32], const word x[16], const word y[16]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); z[ 0] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); z[ 1] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); z[ 2] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); z[ 3] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); z[ 4] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); z[ 5] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); z[ 6] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); z[ 7] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); z[ 8] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); z[ 9] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); z[10] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); z[11] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); z[12] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); z[13] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); z[14] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); z[15] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); z[16] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); z[17] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); z[18] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); z[19] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); word3_muladd(&w1, &w0, &w2, x[10], y[10]); word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); z[20] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); word3_muladd(&w2, &w1, &w0, x[10], y[11]); word3_muladd(&w2, &w1, &w0, x[11], y[10]); word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); z[21] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); word3_muladd(&w0, &w2, &w1, x[10], y[12]); word3_muladd(&w0, &w2, &w1, x[11], y[11]); word3_muladd(&w0, &w2, &w1, x[12], y[10]); word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); z[22] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); word3_muladd(&w1, &w0, &w2, x[10], y[13]); word3_muladd(&w1, &w0, &w2, x[11], y[12]); word3_muladd(&w1, &w0, &w2, x[12], y[11]); word3_muladd(&w1, &w0, &w2, x[13], y[10]); word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); z[23] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); word3_muladd(&w2, &w1, &w0, x[10], y[14]); word3_muladd(&w2, &w1, &w0, x[11], y[13]); word3_muladd(&w2, &w1, &w0, x[12], y[12]); word3_muladd(&w2, &w1, &w0, x[13], y[11]); word3_muladd(&w2, &w1, &w0, x[14], y[10]); word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); z[24] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[10], y[15]); word3_muladd(&w0, &w2, &w1, x[11], y[14]); word3_muladd(&w0, &w2, &w1, x[12], y[13]); word3_muladd(&w0, &w2, &w1, x[13], y[12]); word3_muladd(&w0, &w2, &w1, x[14], y[11]); word3_muladd(&w0, &w2, &w1, x[15], y[10]); z[25] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[11], y[15]); word3_muladd(&w1, &w0, &w2, x[12], y[14]); word3_muladd(&w1, &w0, &w2, x[13], y[13]); word3_muladd(&w1, &w0, &w2, x[14], y[12]); word3_muladd(&w1, &w0, &w2, x[15], y[11]); z[26] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[12], y[15]); word3_muladd(&w2, &w1, &w0, x[13], y[14]); word3_muladd(&w2, &w1, &w0, x[14], y[13]); word3_muladd(&w2, &w1, &w0, x[15], y[12]); z[27] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[13], y[15]); word3_muladd(&w0, &w2, &w1, x[14], y[14]); word3_muladd(&w0, &w2, &w1, x[15], y[13]); z[28] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[14], y[15]); word3_muladd(&w1, &w0, &w2, x[15], y[14]); z[29] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[15], y[15]); z[30] = w0; z[31] = w1; } /* * Comba 24x24 Squaring */ void bigint_comba_sqr24(word z[48], const word x[24]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); z[ 0] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); z[ 1] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); z[ 2] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); z[ 3] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); z[ 4] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); z[ 5] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); z[ 6] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); z[ 7] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); z[ 8] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); z[ 9] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); z[10] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); z[11] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); z[12] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); z[13] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); z[14] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); z[15] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[16]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); z[16] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[17]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[16]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); z[17] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[18]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[17]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[16]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); word3_muladd (&w2, &w1, &w0, x[ 9], x[ 9]); z[18] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[19]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[18]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[17]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[16]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); z[19] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[20]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[19]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[18]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[17]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[16]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); word3_muladd (&w1, &w0, &w2, x[10], x[10]); z[20] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 0], x[21]); word3_muladd_2(&w2, &w1, &w0, x[ 1], x[20]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[19]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[18]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[17]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[16]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); z[21] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 0], x[22]); word3_muladd_2(&w0, &w2, &w1, x[ 1], x[21]); word3_muladd_2(&w0, &w2, &w1, x[ 2], x[20]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[19]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[18]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[17]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[16]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); word3_muladd (&w0, &w2, &w1, x[11], x[11]); z[22] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 0], x[23]); word3_muladd_2(&w1, &w0, &w2, x[ 1], x[22]); word3_muladd_2(&w1, &w0, &w2, x[ 2], x[21]); word3_muladd_2(&w1, &w0, &w2, x[ 3], x[20]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[19]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[18]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[17]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[16]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); z[23] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 1], x[23]); word3_muladd_2(&w2, &w1, &w0, x[ 2], x[22]); word3_muladd_2(&w2, &w1, &w0, x[ 3], x[21]); word3_muladd_2(&w2, &w1, &w0, x[ 4], x[20]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[19]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[18]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[17]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[16]); word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); word3_muladd (&w2, &w1, &w0, x[12], x[12]); z[24] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 2], x[23]); word3_muladd_2(&w0, &w2, &w1, x[ 3], x[22]); word3_muladd_2(&w0, &w2, &w1, x[ 4], x[21]); word3_muladd_2(&w0, &w2, &w1, x[ 5], x[20]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[19]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[18]); word3_muladd_2(&w0, &w2, &w1, x[ 8], x[17]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[16]); word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); z[25] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 3], x[23]); word3_muladd_2(&w1, &w0, &w2, x[ 4], x[22]); word3_muladd_2(&w1, &w0, &w2, x[ 5], x[21]); word3_muladd_2(&w1, &w0, &w2, x[ 6], x[20]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[19]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[18]); word3_muladd_2(&w1, &w0, &w2, x[ 9], x[17]); word3_muladd_2(&w1, &w0, &w2, x[10], x[16]); word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); word3_muladd (&w1, &w0, &w2, x[13], x[13]); z[26] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 4], x[23]); word3_muladd_2(&w2, &w1, &w0, x[ 5], x[22]); word3_muladd_2(&w2, &w1, &w0, x[ 6], x[21]); word3_muladd_2(&w2, &w1, &w0, x[ 7], x[20]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[19]); word3_muladd_2(&w2, &w1, &w0, x[ 9], x[18]); word3_muladd_2(&w2, &w1, &w0, x[10], x[17]); word3_muladd_2(&w2, &w1, &w0, x[11], x[16]); word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); z[27] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 5], x[23]); word3_muladd_2(&w0, &w2, &w1, x[ 6], x[22]); word3_muladd_2(&w0, &w2, &w1, x[ 7], x[21]); word3_muladd_2(&w0, &w2, &w1, x[ 8], x[20]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[19]); word3_muladd_2(&w0, &w2, &w1, x[10], x[18]); word3_muladd_2(&w0, &w2, &w1, x[11], x[17]); word3_muladd_2(&w0, &w2, &w1, x[12], x[16]); word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); word3_muladd (&w0, &w2, &w1, x[14], x[14]); z[28] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 6], x[23]); word3_muladd_2(&w1, &w0, &w2, x[ 7], x[22]); word3_muladd_2(&w1, &w0, &w2, x[ 8], x[21]); word3_muladd_2(&w1, &w0, &w2, x[ 9], x[20]); word3_muladd_2(&w1, &w0, &w2, x[10], x[19]); word3_muladd_2(&w1, &w0, &w2, x[11], x[18]); word3_muladd_2(&w1, &w0, &w2, x[12], x[17]); word3_muladd_2(&w1, &w0, &w2, x[13], x[16]); word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); z[29] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[ 7], x[23]); word3_muladd_2(&w2, &w1, &w0, x[ 8], x[22]); word3_muladd_2(&w2, &w1, &w0, x[ 9], x[21]); word3_muladd_2(&w2, &w1, &w0, x[10], x[20]); word3_muladd_2(&w2, &w1, &w0, x[11], x[19]); word3_muladd_2(&w2, &w1, &w0, x[12], x[18]); word3_muladd_2(&w2, &w1, &w0, x[13], x[17]); word3_muladd_2(&w2, &w1, &w0, x[14], x[16]); word3_muladd (&w2, &w1, &w0, x[15], x[15]); z[30] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[ 8], x[23]); word3_muladd_2(&w0, &w2, &w1, x[ 9], x[22]); word3_muladd_2(&w0, &w2, &w1, x[10], x[21]); word3_muladd_2(&w0, &w2, &w1, x[11], x[20]); word3_muladd_2(&w0, &w2, &w1, x[12], x[19]); word3_muladd_2(&w0, &w2, &w1, x[13], x[18]); word3_muladd_2(&w0, &w2, &w1, x[14], x[17]); word3_muladd_2(&w0, &w2, &w1, x[15], x[16]); z[31] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[ 9], x[23]); word3_muladd_2(&w1, &w0, &w2, x[10], x[22]); word3_muladd_2(&w1, &w0, &w2, x[11], x[21]); word3_muladd_2(&w1, &w0, &w2, x[12], x[20]); word3_muladd_2(&w1, &w0, &w2, x[13], x[19]); word3_muladd_2(&w1, &w0, &w2, x[14], x[18]); word3_muladd_2(&w1, &w0, &w2, x[15], x[17]); word3_muladd (&w1, &w0, &w2, x[16], x[16]); z[32] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[10], x[23]); word3_muladd_2(&w2, &w1, &w0, x[11], x[22]); word3_muladd_2(&w2, &w1, &w0, x[12], x[21]); word3_muladd_2(&w2, &w1, &w0, x[13], x[20]); word3_muladd_2(&w2, &w1, &w0, x[14], x[19]); word3_muladd_2(&w2, &w1, &w0, x[15], x[18]); word3_muladd_2(&w2, &w1, &w0, x[16], x[17]); z[33] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[11], x[23]); word3_muladd_2(&w0, &w2, &w1, x[12], x[22]); word3_muladd_2(&w0, &w2, &w1, x[13], x[21]); word3_muladd_2(&w0, &w2, &w1, x[14], x[20]); word3_muladd_2(&w0, &w2, &w1, x[15], x[19]); word3_muladd_2(&w0, &w2, &w1, x[16], x[18]); word3_muladd (&w0, &w2, &w1, x[17], x[17]); z[34] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[12], x[23]); word3_muladd_2(&w1, &w0, &w2, x[13], x[22]); word3_muladd_2(&w1, &w0, &w2, x[14], x[21]); word3_muladd_2(&w1, &w0, &w2, x[15], x[20]); word3_muladd_2(&w1, &w0, &w2, x[16], x[19]); word3_muladd_2(&w1, &w0, &w2, x[17], x[18]); z[35] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[13], x[23]); word3_muladd_2(&w2, &w1, &w0, x[14], x[22]); word3_muladd_2(&w2, &w1, &w0, x[15], x[21]); word3_muladd_2(&w2, &w1, &w0, x[16], x[20]); word3_muladd_2(&w2, &w1, &w0, x[17], x[19]); word3_muladd (&w2, &w1, &w0, x[18], x[18]); z[36] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[14], x[23]); word3_muladd_2(&w0, &w2, &w1, x[15], x[22]); word3_muladd_2(&w0, &w2, &w1, x[16], x[21]); word3_muladd_2(&w0, &w2, &w1, x[17], x[20]); word3_muladd_2(&w0, &w2, &w1, x[18], x[19]); z[37] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[15], x[23]); word3_muladd_2(&w1, &w0, &w2, x[16], x[22]); word3_muladd_2(&w1, &w0, &w2, x[17], x[21]); word3_muladd_2(&w1, &w0, &w2, x[18], x[20]); word3_muladd (&w1, &w0, &w2, x[19], x[19]); z[38] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[16], x[23]); word3_muladd_2(&w2, &w1, &w0, x[17], x[22]); word3_muladd_2(&w2, &w1, &w0, x[18], x[21]); word3_muladd_2(&w2, &w1, &w0, x[19], x[20]); z[39] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[17], x[23]); word3_muladd_2(&w0, &w2, &w1, x[18], x[22]); word3_muladd_2(&w0, &w2, &w1, x[19], x[21]); word3_muladd (&w0, &w2, &w1, x[20], x[20]); z[40] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[18], x[23]); word3_muladd_2(&w1, &w0, &w2, x[19], x[22]); word3_muladd_2(&w1, &w0, &w2, x[20], x[21]); z[41] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[19], x[23]); word3_muladd_2(&w2, &w1, &w0, x[20], x[22]); word3_muladd (&w2, &w1, &w0, x[21], x[21]); z[42] = w0; w0 = 0; word3_muladd_2(&w0, &w2, &w1, x[20], x[23]); word3_muladd_2(&w0, &w2, &w1, x[21], x[22]); z[43] = w1; w1 = 0; word3_muladd_2(&w1, &w0, &w2, x[21], x[23]); word3_muladd (&w1, &w0, &w2, x[22], x[22]); z[44] = w2; w2 = 0; word3_muladd_2(&w2, &w1, &w0, x[22], x[23]); z[45] = w0; w0 = 0; word3_muladd (&w0, &w2, &w1, x[23], x[23]); z[46] = w1; z[47] = w2; } /* * Comba 24x24 Multiplication */ void bigint_comba_mul24(word z[48], const word x[24], const word y[24]) { word w2 = 0, w1 = 0, w0 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); z[ 0] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); z[ 1] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); z[ 2] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); z[ 3] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); z[ 4] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); z[ 5] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); z[ 6] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); z[ 7] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); z[ 8] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); z[ 9] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); z[10] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); z[11] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); z[12] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); z[13] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); z[14] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); z[15] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[16]); word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); word3_muladd(&w0, &w2, &w1, x[16], y[ 0]); z[16] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[17]); word3_muladd(&w1, &w0, &w2, x[ 1], y[16]); word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); word3_muladd(&w1, &w0, &w2, x[16], y[ 1]); word3_muladd(&w1, &w0, &w2, x[17], y[ 0]); z[17] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[18]); word3_muladd(&w2, &w1, &w0, x[ 1], y[17]); word3_muladd(&w2, &w1, &w0, x[ 2], y[16]); word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); word3_muladd(&w2, &w1, &w0, x[16], y[ 2]); word3_muladd(&w2, &w1, &w0, x[17], y[ 1]); word3_muladd(&w2, &w1, &w0, x[18], y[ 0]); z[18] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[19]); word3_muladd(&w0, &w2, &w1, x[ 1], y[18]); word3_muladd(&w0, &w2, &w1, x[ 2], y[17]); word3_muladd(&w0, &w2, &w1, x[ 3], y[16]); word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); word3_muladd(&w0, &w2, &w1, x[16], y[ 3]); word3_muladd(&w0, &w2, &w1, x[17], y[ 2]); word3_muladd(&w0, &w2, &w1, x[18], y[ 1]); word3_muladd(&w0, &w2, &w1, x[19], y[ 0]); z[19] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[20]); word3_muladd(&w1, &w0, &w2, x[ 1], y[19]); word3_muladd(&w1, &w0, &w2, x[ 2], y[18]); word3_muladd(&w1, &w0, &w2, x[ 3], y[17]); word3_muladd(&w1, &w0, &w2, x[ 4], y[16]); word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); word3_muladd(&w1, &w0, &w2, x[10], y[10]); word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); word3_muladd(&w1, &w0, &w2, x[16], y[ 4]); word3_muladd(&w1, &w0, &w2, x[17], y[ 3]); word3_muladd(&w1, &w0, &w2, x[18], y[ 2]); word3_muladd(&w1, &w0, &w2, x[19], y[ 1]); word3_muladd(&w1, &w0, &w2, x[20], y[ 0]); z[20] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 0], y[21]); word3_muladd(&w2, &w1, &w0, x[ 1], y[20]); word3_muladd(&w2, &w1, &w0, x[ 2], y[19]); word3_muladd(&w2, &w1, &w0, x[ 3], y[18]); word3_muladd(&w2, &w1, &w0, x[ 4], y[17]); word3_muladd(&w2, &w1, &w0, x[ 5], y[16]); word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); word3_muladd(&w2, &w1, &w0, x[10], y[11]); word3_muladd(&w2, &w1, &w0, x[11], y[10]); word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); word3_muladd(&w2, &w1, &w0, x[16], y[ 5]); word3_muladd(&w2, &w1, &w0, x[17], y[ 4]); word3_muladd(&w2, &w1, &w0, x[18], y[ 3]); word3_muladd(&w2, &w1, &w0, x[19], y[ 2]); word3_muladd(&w2, &w1, &w0, x[20], y[ 1]); word3_muladd(&w2, &w1, &w0, x[21], y[ 0]); z[21] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 0], y[22]); word3_muladd(&w0, &w2, &w1, x[ 1], y[21]); word3_muladd(&w0, &w2, &w1, x[ 2], y[20]); word3_muladd(&w0, &w2, &w1, x[ 3], y[19]); word3_muladd(&w0, &w2, &w1, x[ 4], y[18]); word3_muladd(&w0, &w2, &w1, x[ 5], y[17]); word3_muladd(&w0, &w2, &w1, x[ 6], y[16]); word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); word3_muladd(&w0, &w2, &w1, x[10], y[12]); word3_muladd(&w0, &w2, &w1, x[11], y[11]); word3_muladd(&w0, &w2, &w1, x[12], y[10]); word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); word3_muladd(&w0, &w2, &w1, x[16], y[ 6]); word3_muladd(&w0, &w2, &w1, x[17], y[ 5]); word3_muladd(&w0, &w2, &w1, x[18], y[ 4]); word3_muladd(&w0, &w2, &w1, x[19], y[ 3]); word3_muladd(&w0, &w2, &w1, x[20], y[ 2]); word3_muladd(&w0, &w2, &w1, x[21], y[ 1]); word3_muladd(&w0, &w2, &w1, x[22], y[ 0]); z[22] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 0], y[23]); word3_muladd(&w1, &w0, &w2, x[ 1], y[22]); word3_muladd(&w1, &w0, &w2, x[ 2], y[21]); word3_muladd(&w1, &w0, &w2, x[ 3], y[20]); word3_muladd(&w1, &w0, &w2, x[ 4], y[19]); word3_muladd(&w1, &w0, &w2, x[ 5], y[18]); word3_muladd(&w1, &w0, &w2, x[ 6], y[17]); word3_muladd(&w1, &w0, &w2, x[ 7], y[16]); word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); word3_muladd(&w1, &w0, &w2, x[10], y[13]); word3_muladd(&w1, &w0, &w2, x[11], y[12]); word3_muladd(&w1, &w0, &w2, x[12], y[11]); word3_muladd(&w1, &w0, &w2, x[13], y[10]); word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); word3_muladd(&w1, &w0, &w2, x[16], y[ 7]); word3_muladd(&w1, &w0, &w2, x[17], y[ 6]); word3_muladd(&w1, &w0, &w2, x[18], y[ 5]); word3_muladd(&w1, &w0, &w2, x[19], y[ 4]); word3_muladd(&w1, &w0, &w2, x[20], y[ 3]); word3_muladd(&w1, &w0, &w2, x[21], y[ 2]); word3_muladd(&w1, &w0, &w2, x[22], y[ 1]); word3_muladd(&w1, &w0, &w2, x[23], y[ 0]); z[23] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 1], y[23]); word3_muladd(&w2, &w1, &w0, x[ 2], y[22]); word3_muladd(&w2, &w1, &w0, x[ 3], y[21]); word3_muladd(&w2, &w1, &w0, x[ 4], y[20]); word3_muladd(&w2, &w1, &w0, x[ 5], y[19]); word3_muladd(&w2, &w1, &w0, x[ 6], y[18]); word3_muladd(&w2, &w1, &w0, x[ 7], y[17]); word3_muladd(&w2, &w1, &w0, x[ 8], y[16]); word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); word3_muladd(&w2, &w1, &w0, x[10], y[14]); word3_muladd(&w2, &w1, &w0, x[11], y[13]); word3_muladd(&w2, &w1, &w0, x[12], y[12]); word3_muladd(&w2, &w1, &w0, x[13], y[11]); word3_muladd(&w2, &w1, &w0, x[14], y[10]); word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); word3_muladd(&w2, &w1, &w0, x[16], y[ 8]); word3_muladd(&w2, &w1, &w0, x[17], y[ 7]); word3_muladd(&w2, &w1, &w0, x[18], y[ 6]); word3_muladd(&w2, &w1, &w0, x[19], y[ 5]); word3_muladd(&w2, &w1, &w0, x[20], y[ 4]); word3_muladd(&w2, &w1, &w0, x[21], y[ 3]); word3_muladd(&w2, &w1, &w0, x[22], y[ 2]); word3_muladd(&w2, &w1, &w0, x[23], y[ 1]); z[24] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 2], y[23]); word3_muladd(&w0, &w2, &w1, x[ 3], y[22]); word3_muladd(&w0, &w2, &w1, x[ 4], y[21]); word3_muladd(&w0, &w2, &w1, x[ 5], y[20]); word3_muladd(&w0, &w2, &w1, x[ 6], y[19]); word3_muladd(&w0, &w2, &w1, x[ 7], y[18]); word3_muladd(&w0, &w2, &w1, x[ 8], y[17]); word3_muladd(&w0, &w2, &w1, x[ 9], y[16]); word3_muladd(&w0, &w2, &w1, x[10], y[15]); word3_muladd(&w0, &w2, &w1, x[11], y[14]); word3_muladd(&w0, &w2, &w1, x[12], y[13]); word3_muladd(&w0, &w2, &w1, x[13], y[12]); word3_muladd(&w0, &w2, &w1, x[14], y[11]); word3_muladd(&w0, &w2, &w1, x[15], y[10]); word3_muladd(&w0, &w2, &w1, x[16], y[ 9]); word3_muladd(&w0, &w2, &w1, x[17], y[ 8]); word3_muladd(&w0, &w2, &w1, x[18], y[ 7]); word3_muladd(&w0, &w2, &w1, x[19], y[ 6]); word3_muladd(&w0, &w2, &w1, x[20], y[ 5]); word3_muladd(&w0, &w2, &w1, x[21], y[ 4]); word3_muladd(&w0, &w2, &w1, x[22], y[ 3]); word3_muladd(&w0, &w2, &w1, x[23], y[ 2]); z[25] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 3], y[23]); word3_muladd(&w1, &w0, &w2, x[ 4], y[22]); word3_muladd(&w1, &w0, &w2, x[ 5], y[21]); word3_muladd(&w1, &w0, &w2, x[ 6], y[20]); word3_muladd(&w1, &w0, &w2, x[ 7], y[19]); word3_muladd(&w1, &w0, &w2, x[ 8], y[18]); word3_muladd(&w1, &w0, &w2, x[ 9], y[17]); word3_muladd(&w1, &w0, &w2, x[10], y[16]); word3_muladd(&w1, &w0, &w2, x[11], y[15]); word3_muladd(&w1, &w0, &w2, x[12], y[14]); word3_muladd(&w1, &w0, &w2, x[13], y[13]); word3_muladd(&w1, &w0, &w2, x[14], y[12]); word3_muladd(&w1, &w0, &w2, x[15], y[11]); word3_muladd(&w1, &w0, &w2, x[16], y[10]); word3_muladd(&w1, &w0, &w2, x[17], y[ 9]); word3_muladd(&w1, &w0, &w2, x[18], y[ 8]); word3_muladd(&w1, &w0, &w2, x[19], y[ 7]); word3_muladd(&w1, &w0, &w2, x[20], y[ 6]); word3_muladd(&w1, &w0, &w2, x[21], y[ 5]); word3_muladd(&w1, &w0, &w2, x[22], y[ 4]); word3_muladd(&w1, &w0, &w2, x[23], y[ 3]); z[26] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 4], y[23]); word3_muladd(&w2, &w1, &w0, x[ 5], y[22]); word3_muladd(&w2, &w1, &w0, x[ 6], y[21]); word3_muladd(&w2, &w1, &w0, x[ 7], y[20]); word3_muladd(&w2, &w1, &w0, x[ 8], y[19]); word3_muladd(&w2, &w1, &w0, x[ 9], y[18]); word3_muladd(&w2, &w1, &w0, x[10], y[17]); word3_muladd(&w2, &w1, &w0, x[11], y[16]); word3_muladd(&w2, &w1, &w0, x[12], y[15]); word3_muladd(&w2, &w1, &w0, x[13], y[14]); word3_muladd(&w2, &w1, &w0, x[14], y[13]); word3_muladd(&w2, &w1, &w0, x[15], y[12]); word3_muladd(&w2, &w1, &w0, x[16], y[11]); word3_muladd(&w2, &w1, &w0, x[17], y[10]); word3_muladd(&w2, &w1, &w0, x[18], y[ 9]); word3_muladd(&w2, &w1, &w0, x[19], y[ 8]); word3_muladd(&w2, &w1, &w0, x[20], y[ 7]); word3_muladd(&w2, &w1, &w0, x[21], y[ 6]); word3_muladd(&w2, &w1, &w0, x[22], y[ 5]); word3_muladd(&w2, &w1, &w0, x[23], y[ 4]); z[27] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 5], y[23]); word3_muladd(&w0, &w2, &w1, x[ 6], y[22]); word3_muladd(&w0, &w2, &w1, x[ 7], y[21]); word3_muladd(&w0, &w2, &w1, x[ 8], y[20]); word3_muladd(&w0, &w2, &w1, x[ 9], y[19]); word3_muladd(&w0, &w2, &w1, x[10], y[18]); word3_muladd(&w0, &w2, &w1, x[11], y[17]); word3_muladd(&w0, &w2, &w1, x[12], y[16]); word3_muladd(&w0, &w2, &w1, x[13], y[15]); word3_muladd(&w0, &w2, &w1, x[14], y[14]); word3_muladd(&w0, &w2, &w1, x[15], y[13]); word3_muladd(&w0, &w2, &w1, x[16], y[12]); word3_muladd(&w0, &w2, &w1, x[17], y[11]); word3_muladd(&w0, &w2, &w1, x[18], y[10]); word3_muladd(&w0, &w2, &w1, x[19], y[ 9]); word3_muladd(&w0, &w2, &w1, x[20], y[ 8]); word3_muladd(&w0, &w2, &w1, x[21], y[ 7]); word3_muladd(&w0, &w2, &w1, x[22], y[ 6]); word3_muladd(&w0, &w2, &w1, x[23], y[ 5]); z[28] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 6], y[23]); word3_muladd(&w1, &w0, &w2, x[ 7], y[22]); word3_muladd(&w1, &w0, &w2, x[ 8], y[21]); word3_muladd(&w1, &w0, &w2, x[ 9], y[20]); word3_muladd(&w1, &w0, &w2, x[10], y[19]); word3_muladd(&w1, &w0, &w2, x[11], y[18]); word3_muladd(&w1, &w0, &w2, x[12], y[17]); word3_muladd(&w1, &w0, &w2, x[13], y[16]); word3_muladd(&w1, &w0, &w2, x[14], y[15]); word3_muladd(&w1, &w0, &w2, x[15], y[14]); word3_muladd(&w1, &w0, &w2, x[16], y[13]); word3_muladd(&w1, &w0, &w2, x[17], y[12]); word3_muladd(&w1, &w0, &w2, x[18], y[11]); word3_muladd(&w1, &w0, &w2, x[19], y[10]); word3_muladd(&w1, &w0, &w2, x[20], y[ 9]); word3_muladd(&w1, &w0, &w2, x[21], y[ 8]); word3_muladd(&w1, &w0, &w2, x[22], y[ 7]); word3_muladd(&w1, &w0, &w2, x[23], y[ 6]); z[29] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[ 7], y[23]); word3_muladd(&w2, &w1, &w0, x[ 8], y[22]); word3_muladd(&w2, &w1, &w0, x[ 9], y[21]); word3_muladd(&w2, &w1, &w0, x[10], y[20]); word3_muladd(&w2, &w1, &w0, x[11], y[19]); word3_muladd(&w2, &w1, &w0, x[12], y[18]); word3_muladd(&w2, &w1, &w0, x[13], y[17]); word3_muladd(&w2, &w1, &w0, x[14], y[16]); word3_muladd(&w2, &w1, &w0, x[15], y[15]); word3_muladd(&w2, &w1, &w0, x[16], y[14]); word3_muladd(&w2, &w1, &w0, x[17], y[13]); word3_muladd(&w2, &w1, &w0, x[18], y[12]); word3_muladd(&w2, &w1, &w0, x[19], y[11]); word3_muladd(&w2, &w1, &w0, x[20], y[10]); word3_muladd(&w2, &w1, &w0, x[21], y[ 9]); word3_muladd(&w2, &w1, &w0, x[22], y[ 8]); word3_muladd(&w2, &w1, &w0, x[23], y[ 7]); z[30] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[ 8], y[23]); word3_muladd(&w0, &w2, &w1, x[ 9], y[22]); word3_muladd(&w0, &w2, &w1, x[10], y[21]); word3_muladd(&w0, &w2, &w1, x[11], y[20]); word3_muladd(&w0, &w2, &w1, x[12], y[19]); word3_muladd(&w0, &w2, &w1, x[13], y[18]); word3_muladd(&w0, &w2, &w1, x[14], y[17]); word3_muladd(&w0, &w2, &w1, x[15], y[16]); word3_muladd(&w0, &w2, &w1, x[16], y[15]); word3_muladd(&w0, &w2, &w1, x[17], y[14]); word3_muladd(&w0, &w2, &w1, x[18], y[13]); word3_muladd(&w0, &w2, &w1, x[19], y[12]); word3_muladd(&w0, &w2, &w1, x[20], y[11]); word3_muladd(&w0, &w2, &w1, x[21], y[10]); word3_muladd(&w0, &w2, &w1, x[22], y[ 9]); word3_muladd(&w0, &w2, &w1, x[23], y[ 8]); z[31] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[ 9], y[23]); word3_muladd(&w1, &w0, &w2, x[10], y[22]); word3_muladd(&w1, &w0, &w2, x[11], y[21]); word3_muladd(&w1, &w0, &w2, x[12], y[20]); word3_muladd(&w1, &w0, &w2, x[13], y[19]); word3_muladd(&w1, &w0, &w2, x[14], y[18]); word3_muladd(&w1, &w0, &w2, x[15], y[17]); word3_muladd(&w1, &w0, &w2, x[16], y[16]); word3_muladd(&w1, &w0, &w2, x[17], y[15]); word3_muladd(&w1, &w0, &w2, x[18], y[14]); word3_muladd(&w1, &w0, &w2, x[19], y[13]); word3_muladd(&w1, &w0, &w2, x[20], y[12]); word3_muladd(&w1, &w0, &w2, x[21], y[11]); word3_muladd(&w1, &w0, &w2, x[22], y[10]); word3_muladd(&w1, &w0, &w2, x[23], y[ 9]); z[32] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[10], y[23]); word3_muladd(&w2, &w1, &w0, x[11], y[22]); word3_muladd(&w2, &w1, &w0, x[12], y[21]); word3_muladd(&w2, &w1, &w0, x[13], y[20]); word3_muladd(&w2, &w1, &w0, x[14], y[19]); word3_muladd(&w2, &w1, &w0, x[15], y[18]); word3_muladd(&w2, &w1, &w0, x[16], y[17]); word3_muladd(&w2, &w1, &w0, x[17], y[16]); word3_muladd(&w2, &w1, &w0, x[18], y[15]); word3_muladd(&w2, &w1, &w0, x[19], y[14]); word3_muladd(&w2, &w1, &w0, x[20], y[13]); word3_muladd(&w2, &w1, &w0, x[21], y[12]); word3_muladd(&w2, &w1, &w0, x[22], y[11]); word3_muladd(&w2, &w1, &w0, x[23], y[10]); z[33] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[11], y[23]); word3_muladd(&w0, &w2, &w1, x[12], y[22]); word3_muladd(&w0, &w2, &w1, x[13], y[21]); word3_muladd(&w0, &w2, &w1, x[14], y[20]); word3_muladd(&w0, &w2, &w1, x[15], y[19]); word3_muladd(&w0, &w2, &w1, x[16], y[18]); word3_muladd(&w0, &w2, &w1, x[17], y[17]); word3_muladd(&w0, &w2, &w1, x[18], y[16]); word3_muladd(&w0, &w2, &w1, x[19], y[15]); word3_muladd(&w0, &w2, &w1, x[20], y[14]); word3_muladd(&w0, &w2, &w1, x[21], y[13]); word3_muladd(&w0, &w2, &w1, x[22], y[12]); word3_muladd(&w0, &w2, &w1, x[23], y[11]); z[34] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[12], y[23]); word3_muladd(&w1, &w0, &w2, x[13], y[22]); word3_muladd(&w1, &w0, &w2, x[14], y[21]); word3_muladd(&w1, &w0, &w2, x[15], y[20]); word3_muladd(&w1, &w0, &w2, x[16], y[19]); word3_muladd(&w1, &w0, &w2, x[17], y[18]); word3_muladd(&w1, &w0, &w2, x[18], y[17]); word3_muladd(&w1, &w0, &w2, x[19], y[16]); word3_muladd(&w1, &w0, &w2, x[20], y[15]); word3_muladd(&w1, &w0, &w2, x[21], y[14]); word3_muladd(&w1, &w0, &w2, x[22], y[13]); word3_muladd(&w1, &w0, &w2, x[23], y[12]); z[35] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[13], y[23]); word3_muladd(&w2, &w1, &w0, x[14], y[22]); word3_muladd(&w2, &w1, &w0, x[15], y[21]); word3_muladd(&w2, &w1, &w0, x[16], y[20]); word3_muladd(&w2, &w1, &w0, x[17], y[19]); word3_muladd(&w2, &w1, &w0, x[18], y[18]); word3_muladd(&w2, &w1, &w0, x[19], y[17]); word3_muladd(&w2, &w1, &w0, x[20], y[16]); word3_muladd(&w2, &w1, &w0, x[21], y[15]); word3_muladd(&w2, &w1, &w0, x[22], y[14]); word3_muladd(&w2, &w1, &w0, x[23], y[13]); z[36] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[14], y[23]); word3_muladd(&w0, &w2, &w1, x[15], y[22]); word3_muladd(&w0, &w2, &w1, x[16], y[21]); word3_muladd(&w0, &w2, &w1, x[17], y[20]); word3_muladd(&w0, &w2, &w1, x[18], y[19]); word3_muladd(&w0, &w2, &w1, x[19], y[18]); word3_muladd(&w0, &w2, &w1, x[20], y[17]); word3_muladd(&w0, &w2, &w1, x[21], y[16]); word3_muladd(&w0, &w2, &w1, x[22], y[15]); word3_muladd(&w0, &w2, &w1, x[23], y[14]); z[37] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[15], y[23]); word3_muladd(&w1, &w0, &w2, x[16], y[22]); word3_muladd(&w1, &w0, &w2, x[17], y[21]); word3_muladd(&w1, &w0, &w2, x[18], y[20]); word3_muladd(&w1, &w0, &w2, x[19], y[19]); word3_muladd(&w1, &w0, &w2, x[20], y[18]); word3_muladd(&w1, &w0, &w2, x[21], y[17]); word3_muladd(&w1, &w0, &w2, x[22], y[16]); word3_muladd(&w1, &w0, &w2, x[23], y[15]); z[38] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[16], y[23]); word3_muladd(&w2, &w1, &w0, x[17], y[22]); word3_muladd(&w2, &w1, &w0, x[18], y[21]); word3_muladd(&w2, &w1, &w0, x[19], y[20]); word3_muladd(&w2, &w1, &w0, x[20], y[19]); word3_muladd(&w2, &w1, &w0, x[21], y[18]); word3_muladd(&w2, &w1, &w0, x[22], y[17]); word3_muladd(&w2, &w1, &w0, x[23], y[16]); z[39] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[17], y[23]); word3_muladd(&w0, &w2, &w1, x[18], y[22]); word3_muladd(&w0, &w2, &w1, x[19], y[21]); word3_muladd(&w0, &w2, &w1, x[20], y[20]); word3_muladd(&w0, &w2, &w1, x[21], y[19]); word3_muladd(&w0, &w2, &w1, x[22], y[18]); word3_muladd(&w0, &w2, &w1, x[23], y[17]); z[40] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[18], y[23]); word3_muladd(&w1, &w0, &w2, x[19], y[22]); word3_muladd(&w1, &w0, &w2, x[20], y[21]); word3_muladd(&w1, &w0, &w2, x[21], y[20]); word3_muladd(&w1, &w0, &w2, x[22], y[19]); word3_muladd(&w1, &w0, &w2, x[23], y[18]); z[41] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[19], y[23]); word3_muladd(&w2, &w1, &w0, x[20], y[22]); word3_muladd(&w2, &w1, &w0, x[21], y[21]); word3_muladd(&w2, &w1, &w0, x[22], y[20]); word3_muladd(&w2, &w1, &w0, x[23], y[19]); z[42] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[20], y[23]); word3_muladd(&w0, &w2, &w1, x[21], y[22]); word3_muladd(&w0, &w2, &w1, x[22], y[21]); word3_muladd(&w0, &w2, &w1, x[23], y[20]); z[43] = w1; w1 = 0; word3_muladd(&w1, &w0, &w2, x[21], y[23]); word3_muladd(&w1, &w0, &w2, x[22], y[22]); word3_muladd(&w1, &w0, &w2, x[23], y[21]); z[44] = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, x[22], y[23]); word3_muladd(&w2, &w1, &w0, x[23], y[22]); z[45] = w0; w0 = 0; word3_muladd(&w0, &w2, &w1, x[23], y[23]); z[46] = w1; z[47] = w2; } } /* * Multiplication and Squaring * (C) 1999-2010,2018 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32; const size_t KARATSUBA_SQUARE_THRESHOLD = 32; /* * Simple O(N^2) Multiplication */ void basecase_mul(word z[], size_t z_size, const word x[], size_t x_size, const word y[], size_t y_size) { if(z_size < x_size + y_size) throw Invalid_Argument("basecase_mul z_size too small"); const size_t x_size_8 = x_size - (x_size % 8); clear_mem(z, z_size); for(size_t i = 0; i != y_size; ++i) { const word y_i = y[i]; word carry = 0; for(size_t j = 0; j != x_size_8; j += 8) carry = word8_madd3(z + i + j, x + j, y_i, carry); for(size_t j = x_size_8; j != x_size; ++j) z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry); z[x_size+i] = carry; } } void basecase_sqr(word z[], size_t z_size, const word x[], size_t x_size) { if(z_size < 2*x_size) throw Invalid_Argument("basecase_sqr z_size too small"); const size_t x_size_8 = x_size - (x_size % 8); clear_mem(z, z_size); for(size_t i = 0; i != x_size; ++i) { const word x_i = x[i]; word carry = 0; for(size_t j = 0; j != x_size_8; j += 8) carry = word8_madd3(z + i + j, x + j, x_i, carry); for(size_t j = x_size_8; j != x_size; ++j) z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry); z[x_size+i] = carry; } } /* * Karatsuba Multiplication Operation */ void karatsuba_mul(word z[], const word x[], const word y[], size_t N, word workspace[]) { if(N < KARATSUBA_MULTIPLY_THRESHOLD || N % 2) { switch(N) { case 6: return bigint_comba_mul6(z, x, y); case 8: return bigint_comba_mul8(z, x, y); case 9: return bigint_comba_mul9(z, x, y); case 16: return bigint_comba_mul16(z, x, y); case 24: return bigint_comba_mul24(z, x, y); default: return basecase_mul(z, 2*N, x, N, y, N); } } const size_t N2 = N / 2; const word* x0 = x; const word* x1 = x + N2; const word* y0 = y; const word* y1 = y + N2; word* z0 = z; word* z1 = z + N; word* ws0 = workspace; word* ws1 = workspace + N; clear_mem(workspace, 2*N); /* * If either of cmp0 or cmp1 is zero then z0 or z1 resp is zero here, * resulting in a no-op - z0*z1 will be equal to zero so we don't need to do * anything, clear_mem above already set the correct result. * * However we ignore the result of the comparisons and always perform the * subtractions and recursively multiply to avoid the timing channel. */ // First compute (X_lo - X_hi)*(Y_hi - Y_lo) const auto cmp0 = bigint_sub_abs(z0, x0, x1, N2, workspace); const auto cmp1 = bigint_sub_abs(z1, y1, y0, N2, workspace); const auto neg_mask = ~(cmp0 ^ cmp1); karatsuba_mul(ws0, z0, z1, N2, ws1); // Compute X_lo * Y_lo karatsuba_mul(z0, x0, y0, N2, ws1); // Compute X_hi * Y_hi karatsuba_mul(z1, x1, y1, N2, ws1); const word ws_carry = bigint_add3_nc(ws1, z0, N, z1, N); word z_carry = bigint_add2_nc(z + N2, N, ws1, N); z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); bigint_add2_nc(z + N + N2, N2, &z_carry, 1); clear_mem(workspace + N, N2); bigint_cnd_add_or_sub(neg_mask, z + N2, workspace, 2*N-N2); } /* * Karatsuba Squaring Operation */ void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[]) { if(N < KARATSUBA_SQUARE_THRESHOLD || N % 2) { switch(N) { case 6: return bigint_comba_sqr6(z, x); case 8: return bigint_comba_sqr8(z, x); case 9: return bigint_comba_sqr9(z, x); case 16: return bigint_comba_sqr16(z, x); case 24: return bigint_comba_sqr24(z, x); default: return basecase_sqr(z, 2*N, x, N); } } const size_t N2 = N / 2; const word* x0 = x; const word* x1 = x + N2; word* z0 = z; word* z1 = z + N; word* ws0 = workspace; word* ws1 = workspace + N; clear_mem(workspace, 2*N); // See comment in karatsuba_mul bigint_sub_abs(z0, x0, x1, N2, workspace); karatsuba_sqr(ws0, z0, N2, ws1); karatsuba_sqr(z0, x0, N2, ws1); karatsuba_sqr(z1, x1, N2, ws1); const word ws_carry = bigint_add3_nc(ws1, z0, N, z1, N); word z_carry = bigint_add2_nc(z + N2, N, ws1, N); z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); bigint_add2_nc(z + N + N2, N2, &z_carry, 1); /* * This is only actually required if cmp (result of bigint_sub_abs) is != 0, * however if cmp==0 then ws0[0:N] == 0 and avoiding the jump hides a * timing channel. */ bigint_sub2(z + N2, 2*N-N2, ws0, N); } /* * Pick a good size for the Karatsuba multiply */ size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw, size_t y_size, size_t y_sw) { if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) return 0; if(((x_size == x_sw) && (x_size % 2)) || ((y_size == y_sw) && (y_size % 2))) return 0; const size_t start = (x_sw > y_sw) ? x_sw : y_sw; const size_t end = (x_size < y_size) ? x_size : y_size; if(start == end) { if(start % 2) return 0; return start; } for(size_t j = start; j <= end; ++j) { if(j % 2) continue; if(2*j > z_size) return 0; if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) { if(j % 4 == 2 && (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size) return j+2; return j; } } return 0; } /* * Pick a good size for the Karatsuba squaring */ size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw) { if(x_sw == x_size) { if(x_sw % 2) return 0; return x_sw; } for(size_t j = x_sw; j <= x_size; ++j) { if(j % 2) continue; if(2*j > z_size) return 0; if(j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size) return j+2; return j; } return 0; } template inline bool sized_for_comba_mul(size_t x_sw, size_t x_size, size_t y_sw, size_t y_size, size_t z_size) { return (x_sw <= SZ && x_size >= SZ && y_sw <= SZ && y_size >= SZ && z_size >= 2*SZ); } template inline bool sized_for_comba_sqr(size_t x_sw, size_t x_size, size_t z_size) { return (x_sw <= SZ && x_size >= SZ && z_size >= 2*SZ); } } void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size) { clear_mem(z, z_size); if(x_sw == 1) { bigint_linmul3(z, y, y_sw, x[0]); } else if(y_sw == 1) { bigint_linmul3(z, x, x_sw, y[0]); } else if(sized_for_comba_mul<4>(x_sw, x_size, y_sw, y_size, z_size)) { bigint_comba_mul4(z, x, y); } else if(sized_for_comba_mul<6>(x_sw, x_size, y_sw, y_size, z_size)) { bigint_comba_mul6(z, x, y); } else if(sized_for_comba_mul<8>(x_sw, x_size, y_sw, y_size, z_size)) { bigint_comba_mul8(z, x, y); } else if(sized_for_comba_mul<9>(x_sw, x_size, y_sw, y_size, z_size)) { bigint_comba_mul9(z, x, y); } else if(sized_for_comba_mul<16>(x_sw, x_size, y_sw, y_size, z_size)) { bigint_comba_mul16(z, x, y); } else if(sized_for_comba_mul<24>(x_sw, x_size, y_sw, y_size, z_size)) { bigint_comba_mul24(z, x, y); } else if(x_sw < KARATSUBA_MULTIPLY_THRESHOLD || y_sw < KARATSUBA_MULTIPLY_THRESHOLD || !workspace) { basecase_mul(z, z_size, x, x_sw, y, y_sw); } else { const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); if(N && z_size >= 2*N && ws_size >= 2*N) karatsuba_mul(z, x, y, N, workspace); else basecase_mul(z, z_size, x, x_sw, y, y_sw); } } /* * Squaring Algorithm Dispatcher */ void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size) { clear_mem(z, z_size); BOTAN_ASSERT(z_size/2 >= x_sw, "Output size is sufficient"); if(x_sw == 1) { bigint_linmul3(z, x, x_sw, x[0]); } else if(sized_for_comba_sqr<4>(x_sw, x_size, z_size)) { bigint_comba_sqr4(z, x); } else if(sized_for_comba_sqr<6>(x_sw, x_size, z_size)) { bigint_comba_sqr6(z, x); } else if(sized_for_comba_sqr<8>(x_sw, x_size, z_size)) { bigint_comba_sqr8(z, x); } else if(sized_for_comba_sqr<9>(x_sw, x_size, z_size)) { bigint_comba_sqr9(z, x); } else if(sized_for_comba_sqr<16>(x_sw, x_size, z_size)) { bigint_comba_sqr16(z, x); } else if(sized_for_comba_sqr<24>(x_sw, x_size, z_size)) { bigint_comba_sqr24(z, x); } else if(x_size < KARATSUBA_SQUARE_THRESHOLD || !workspace) { basecase_sqr(z, z_size, x, x_sw); } else { const size_t N = karatsuba_size(z_size, x_size, x_sw); if(N && z_size >= 2*N && ws_size >= 2*N) karatsuba_sqr(z, x, N, workspace); else basecase_sqr(z, z_size, x, x_sw); } } } /* * Montgomery Reduction * (C) 1999-2011 Jack Lloyd * 2006 Luca Piccarreta * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Montgomery reduction - product scanning form * * https://www.iacr.org/archive/ches2005/006.pdf * https://eprint.iacr.org/2013/882.pdf * https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/j37acmon.pdf */ void bigint_monty_redc_generic(word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; for(size_t i = 1; i != p_size; ++i) { for(size_t j = 0; j < i; ++j) { word3_muladd(&w2, &w1, &w0, ws[j], p[i-j]); } word3_add(&w2, &w1, &w0, z[i]); ws[i] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[i], p[0]); w0 = w1; w1 = w2; w2 = 0; } for(size_t i = 0; i != p_size; ++i) { for(size_t j = i + 1; j != p_size; ++j) { word3_muladd(&w2, &w1, &w0, ws[j], p[p_size + i-j]); } word3_add(&w2, &w1, &w0, z[p_size+i]); ws[i] = w0; w0 = w1; w1 = w2; w2 = 0; } word3_add(&w2, &w1, &w0, z[z_size-1]); ws[p_size] = w0; ws[p_size+1] = w1; /* * The result might need to be reduced mod p. To avoid a timing * channel, always perform the subtraction. If in the compution * of x - p a borrow is required then x was already < p. * * x starts at ws[0] and is p_size+1 bytes long. * x - p starts at ws[p_size+1] and is also p_size+1 bytes log * * Select which address to copy from indexing off of the final * borrow. */ // word borrow = bigint_sub3(ws + p_size + 1, ws, p_size + 1, p, p_size); word borrow = 0; for(size_t i = 0; i != p_size; ++i) ws[p_size + 1 + i] = word_sub(ws[i], p[i], &borrow); ws[2*p_size+1] = word_sub(ws[p_size], 0, &borrow); BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); CT::conditional_copy_mem(borrow, z, ws, ws + (p_size + 1), (p_size + 1)); clear_mem(z + p_size, z_size - p_size - 2); } } void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size) { const size_t z_size = 2*(p_size+1); BOTAN_ARG_CHECK(ws_size >= z_size, "workspace too small"); if(p_size == 4) bigint_monty_redc_4(z, p, p_dash, ws); else if(p_size == 6) bigint_monty_redc_6(z, p, p_dash, ws); else if(p_size == 8) bigint_monty_redc_8(z, p, p_dash, ws); else if(p_size == 16) bigint_monty_redc_16(z, p, p_dash, ws); else if(p_size == 24) bigint_monty_redc_24(z, p, p_dash, ws); else if(p_size == 32) bigint_monty_redc_32(z, p, p_dash, ws); else bigint_monty_redc_generic(z, z_size, p, p_size, p_dash, ws); } } /* * This file was automatically generated by ./src/scripts/monty.py on 2018-06-11 * All manual changes will be lost. Edit the script instead. * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void bigint_monty_redc_4(word z[], const word p[4], word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[1]); word3_add(&w2, &w1, &w0, z[1]); ws[1] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[1], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[2]); word3_muladd(&w2, &w1, &w0, ws[1], p[1]); word3_add(&w2, &w1, &w0, z[2]); ws[2] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[2], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[3]); word3_muladd(&w2, &w1, &w0, ws[1], p[2]); word3_muladd(&w2, &w1, &w0, ws[2], p[1]); word3_add(&w2, &w1, &w0, z[3]); ws[3] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[3], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[1], p[3]); word3_muladd(&w2, &w1, &w0, ws[2], p[2]); word3_muladd(&w2, &w1, &w0, ws[3], p[1]); word3_add(&w2, &w1, &w0, z[4]); ws[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[2], p[3]); word3_muladd(&w2, &w1, &w0, ws[3], p[2]); word3_add(&w2, &w1, &w0, z[5]); ws[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[3], p[3]); word3_add(&w2, &w1, &w0, z[6]); ws[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[7]); ws[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[9]); ws[4] = w0; ws[5] = w1; word borrow = 0; ws[5] = word_sub(ws[0], p[0], &borrow); ws[6] = word_sub(ws[1], p[1], &borrow); ws[7] = word_sub(ws[2], p[2], &borrow); ws[8] = word_sub(ws[3], p[3], &borrow); ws[9] = word_sub(ws[4], 0, &borrow); CT::conditional_copy_mem(borrow, z, ws, ws + 5, 5); clear_mem(z + 4, 2*(4+1) - 4); } void bigint_monty_redc_6(word z[], const word p[6], word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[1]); word3_add(&w2, &w1, &w0, z[1]); ws[1] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[1], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[2]); word3_muladd(&w2, &w1, &w0, ws[1], p[1]); word3_add(&w2, &w1, &w0, z[2]); ws[2] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[2], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[3]); word3_muladd(&w2, &w1, &w0, ws[1], p[2]); word3_muladd(&w2, &w1, &w0, ws[2], p[1]); word3_add(&w2, &w1, &w0, z[3]); ws[3] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[3], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[4]); word3_muladd(&w2, &w1, &w0, ws[1], p[3]); word3_muladd(&w2, &w1, &w0, ws[2], p[2]); word3_muladd(&w2, &w1, &w0, ws[3], p[1]); word3_add(&w2, &w1, &w0, z[4]); ws[4] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[4], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[5]); word3_muladd(&w2, &w1, &w0, ws[1], p[4]); word3_muladd(&w2, &w1, &w0, ws[2], p[3]); word3_muladd(&w2, &w1, &w0, ws[3], p[2]); word3_muladd(&w2, &w1, &w0, ws[4], p[1]); word3_add(&w2, &w1, &w0, z[5]); ws[5] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[5], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[1], p[5]); word3_muladd(&w2, &w1, &w0, ws[2], p[4]); word3_muladd(&w2, &w1, &w0, ws[3], p[3]); word3_muladd(&w2, &w1, &w0, ws[4], p[2]); word3_muladd(&w2, &w1, &w0, ws[5], p[1]); word3_add(&w2, &w1, &w0, z[6]); ws[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[2], p[5]); word3_muladd(&w2, &w1, &w0, ws[3], p[4]); word3_muladd(&w2, &w1, &w0, ws[4], p[3]); word3_muladd(&w2, &w1, &w0, ws[5], p[2]); word3_add(&w2, &w1, &w0, z[7]); ws[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[3], p[5]); word3_muladd(&w2, &w1, &w0, ws[4], p[4]); word3_muladd(&w2, &w1, &w0, ws[5], p[3]); word3_add(&w2, &w1, &w0, z[8]); ws[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[4], p[5]); word3_muladd(&w2, &w1, &w0, ws[5], p[4]); word3_add(&w2, &w1, &w0, z[9]); ws[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[5], p[5]); word3_add(&w2, &w1, &w0, z[10]); ws[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[11]); ws[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[13]); ws[6] = w0; ws[7] = w1; word borrow = 0; ws[7] = word_sub(ws[0], p[0], &borrow); ws[8] = word_sub(ws[1], p[1], &borrow); ws[9] = word_sub(ws[2], p[2], &borrow); ws[10] = word_sub(ws[3], p[3], &borrow); ws[11] = word_sub(ws[4], p[4], &borrow); ws[12] = word_sub(ws[5], p[5], &borrow); ws[13] = word_sub(ws[6], 0, &borrow); CT::conditional_copy_mem(borrow, z, ws, ws + 7, 7); clear_mem(z + 6, 2*(6+1) - 6); } void bigint_monty_redc_8(word z[], const word p[8], word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[1]); word3_add(&w2, &w1, &w0, z[1]); ws[1] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[1], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[2]); word3_muladd(&w2, &w1, &w0, ws[1], p[1]); word3_add(&w2, &w1, &w0, z[2]); ws[2] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[2], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[3]); word3_muladd(&w2, &w1, &w0, ws[1], p[2]); word3_muladd(&w2, &w1, &w0, ws[2], p[1]); word3_add(&w2, &w1, &w0, z[3]); ws[3] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[3], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[4]); word3_muladd(&w2, &w1, &w0, ws[1], p[3]); word3_muladd(&w2, &w1, &w0, ws[2], p[2]); word3_muladd(&w2, &w1, &w0, ws[3], p[1]); word3_add(&w2, &w1, &w0, z[4]); ws[4] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[4], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[5]); word3_muladd(&w2, &w1, &w0, ws[1], p[4]); word3_muladd(&w2, &w1, &w0, ws[2], p[3]); word3_muladd(&w2, &w1, &w0, ws[3], p[2]); word3_muladd(&w2, &w1, &w0, ws[4], p[1]); word3_add(&w2, &w1, &w0, z[5]); ws[5] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[5], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[6]); word3_muladd(&w2, &w1, &w0, ws[1], p[5]); word3_muladd(&w2, &w1, &w0, ws[2], p[4]); word3_muladd(&w2, &w1, &w0, ws[3], p[3]); word3_muladd(&w2, &w1, &w0, ws[4], p[2]); word3_muladd(&w2, &w1, &w0, ws[5], p[1]); word3_add(&w2, &w1, &w0, z[6]); ws[6] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[6], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[7]); word3_muladd(&w2, &w1, &w0, ws[1], p[6]); word3_muladd(&w2, &w1, &w0, ws[2], p[5]); word3_muladd(&w2, &w1, &w0, ws[3], p[4]); word3_muladd(&w2, &w1, &w0, ws[4], p[3]); word3_muladd(&w2, &w1, &w0, ws[5], p[2]); word3_muladd(&w2, &w1, &w0, ws[6], p[1]); word3_add(&w2, &w1, &w0, z[7]); ws[7] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[7], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[1], p[7]); word3_muladd(&w2, &w1, &w0, ws[2], p[6]); word3_muladd(&w2, &w1, &w0, ws[3], p[5]); word3_muladd(&w2, &w1, &w0, ws[4], p[4]); word3_muladd(&w2, &w1, &w0, ws[5], p[3]); word3_muladd(&w2, &w1, &w0, ws[6], p[2]); word3_muladd(&w2, &w1, &w0, ws[7], p[1]); word3_add(&w2, &w1, &w0, z[8]); ws[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[2], p[7]); word3_muladd(&w2, &w1, &w0, ws[3], p[6]); word3_muladd(&w2, &w1, &w0, ws[4], p[5]); word3_muladd(&w2, &w1, &w0, ws[5], p[4]); word3_muladd(&w2, &w1, &w0, ws[6], p[3]); word3_muladd(&w2, &w1, &w0, ws[7], p[2]); word3_add(&w2, &w1, &w0, z[9]); ws[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[3], p[7]); word3_muladd(&w2, &w1, &w0, ws[4], p[6]); word3_muladd(&w2, &w1, &w0, ws[5], p[5]); word3_muladd(&w2, &w1, &w0, ws[6], p[4]); word3_muladd(&w2, &w1, &w0, ws[7], p[3]); word3_add(&w2, &w1, &w0, z[10]); ws[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[4], p[7]); word3_muladd(&w2, &w1, &w0, ws[5], p[6]); word3_muladd(&w2, &w1, &w0, ws[6], p[5]); word3_muladd(&w2, &w1, &w0, ws[7], p[4]); word3_add(&w2, &w1, &w0, z[11]); ws[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[5], p[7]); word3_muladd(&w2, &w1, &w0, ws[6], p[6]); word3_muladd(&w2, &w1, &w0, ws[7], p[5]); word3_add(&w2, &w1, &w0, z[12]); ws[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[6], p[7]); word3_muladd(&w2, &w1, &w0, ws[7], p[6]); word3_add(&w2, &w1, &w0, z[13]); ws[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[7], p[7]); word3_add(&w2, &w1, &w0, z[14]); ws[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[15]); ws[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[17]); ws[8] = w0; ws[9] = w1; word borrow = 0; ws[9] = word_sub(ws[0], p[0], &borrow); ws[10] = word_sub(ws[1], p[1], &borrow); ws[11] = word_sub(ws[2], p[2], &borrow); ws[12] = word_sub(ws[3], p[3], &borrow); ws[13] = word_sub(ws[4], p[4], &borrow); ws[14] = word_sub(ws[5], p[5], &borrow); ws[15] = word_sub(ws[6], p[6], &borrow); ws[16] = word_sub(ws[7], p[7], &borrow); ws[17] = word_sub(ws[8], 0, &borrow); CT::conditional_copy_mem(borrow, z, ws, ws + 9, 9); clear_mem(z + 8, 2*(8+1) - 8); } void bigint_monty_redc_16(word z[], const word p[16], word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[1]); word3_add(&w2, &w1, &w0, z[1]); ws[1] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[1], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[2]); word3_muladd(&w2, &w1, &w0, ws[1], p[1]); word3_add(&w2, &w1, &w0, z[2]); ws[2] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[2], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[3]); word3_muladd(&w2, &w1, &w0, ws[1], p[2]); word3_muladd(&w2, &w1, &w0, ws[2], p[1]); word3_add(&w2, &w1, &w0, z[3]); ws[3] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[3], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[4]); word3_muladd(&w2, &w1, &w0, ws[1], p[3]); word3_muladd(&w2, &w1, &w0, ws[2], p[2]); word3_muladd(&w2, &w1, &w0, ws[3], p[1]); word3_add(&w2, &w1, &w0, z[4]); ws[4] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[4], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[5]); word3_muladd(&w2, &w1, &w0, ws[1], p[4]); word3_muladd(&w2, &w1, &w0, ws[2], p[3]); word3_muladd(&w2, &w1, &w0, ws[3], p[2]); word3_muladd(&w2, &w1, &w0, ws[4], p[1]); word3_add(&w2, &w1, &w0, z[5]); ws[5] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[5], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[6]); word3_muladd(&w2, &w1, &w0, ws[1], p[5]); word3_muladd(&w2, &w1, &w0, ws[2], p[4]); word3_muladd(&w2, &w1, &w0, ws[3], p[3]); word3_muladd(&w2, &w1, &w0, ws[4], p[2]); word3_muladd(&w2, &w1, &w0, ws[5], p[1]); word3_add(&w2, &w1, &w0, z[6]); ws[6] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[6], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[7]); word3_muladd(&w2, &w1, &w0, ws[1], p[6]); word3_muladd(&w2, &w1, &w0, ws[2], p[5]); word3_muladd(&w2, &w1, &w0, ws[3], p[4]); word3_muladd(&w2, &w1, &w0, ws[4], p[3]); word3_muladd(&w2, &w1, &w0, ws[5], p[2]); word3_muladd(&w2, &w1, &w0, ws[6], p[1]); word3_add(&w2, &w1, &w0, z[7]); ws[7] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[7], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[8]); word3_muladd(&w2, &w1, &w0, ws[1], p[7]); word3_muladd(&w2, &w1, &w0, ws[2], p[6]); word3_muladd(&w2, &w1, &w0, ws[3], p[5]); word3_muladd(&w2, &w1, &w0, ws[4], p[4]); word3_muladd(&w2, &w1, &w0, ws[5], p[3]); word3_muladd(&w2, &w1, &w0, ws[6], p[2]); word3_muladd(&w2, &w1, &w0, ws[7], p[1]); word3_add(&w2, &w1, &w0, z[8]); ws[8] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[8], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[9]); word3_muladd(&w2, &w1, &w0, ws[1], p[8]); word3_muladd(&w2, &w1, &w0, ws[2], p[7]); word3_muladd(&w2, &w1, &w0, ws[3], p[6]); word3_muladd(&w2, &w1, &w0, ws[4], p[5]); word3_muladd(&w2, &w1, &w0, ws[5], p[4]); word3_muladd(&w2, &w1, &w0, ws[6], p[3]); word3_muladd(&w2, &w1, &w0, ws[7], p[2]); word3_muladd(&w2, &w1, &w0, ws[8], p[1]); word3_add(&w2, &w1, &w0, z[9]); ws[9] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[9], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[10]); word3_muladd(&w2, &w1, &w0, ws[1], p[9]); word3_muladd(&w2, &w1, &w0, ws[2], p[8]); word3_muladd(&w2, &w1, &w0, ws[3], p[7]); word3_muladd(&w2, &w1, &w0, ws[4], p[6]); word3_muladd(&w2, &w1, &w0, ws[5], p[5]); word3_muladd(&w2, &w1, &w0, ws[6], p[4]); word3_muladd(&w2, &w1, &w0, ws[7], p[3]); word3_muladd(&w2, &w1, &w0, ws[8], p[2]); word3_muladd(&w2, &w1, &w0, ws[9], p[1]); word3_add(&w2, &w1, &w0, z[10]); ws[10] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[10], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[11]); word3_muladd(&w2, &w1, &w0, ws[1], p[10]); word3_muladd(&w2, &w1, &w0, ws[2], p[9]); word3_muladd(&w2, &w1, &w0, ws[3], p[8]); word3_muladd(&w2, &w1, &w0, ws[4], p[7]); word3_muladd(&w2, &w1, &w0, ws[5], p[6]); word3_muladd(&w2, &w1, &w0, ws[6], p[5]); word3_muladd(&w2, &w1, &w0, ws[7], p[4]); word3_muladd(&w2, &w1, &w0, ws[8], p[3]); word3_muladd(&w2, &w1, &w0, ws[9], p[2]); word3_muladd(&w2, &w1, &w0, ws[10], p[1]); word3_add(&w2, &w1, &w0, z[11]); ws[11] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[11], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[12]); word3_muladd(&w2, &w1, &w0, ws[1], p[11]); word3_muladd(&w2, &w1, &w0, ws[2], p[10]); word3_muladd(&w2, &w1, &w0, ws[3], p[9]); word3_muladd(&w2, &w1, &w0, ws[4], p[8]); word3_muladd(&w2, &w1, &w0, ws[5], p[7]); word3_muladd(&w2, &w1, &w0, ws[6], p[6]); word3_muladd(&w2, &w1, &w0, ws[7], p[5]); word3_muladd(&w2, &w1, &w0, ws[8], p[4]); word3_muladd(&w2, &w1, &w0, ws[9], p[3]); word3_muladd(&w2, &w1, &w0, ws[10], p[2]); word3_muladd(&w2, &w1, &w0, ws[11], p[1]); word3_add(&w2, &w1, &w0, z[12]); ws[12] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[12], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[13]); word3_muladd(&w2, &w1, &w0, ws[1], p[12]); word3_muladd(&w2, &w1, &w0, ws[2], p[11]); word3_muladd(&w2, &w1, &w0, ws[3], p[10]); word3_muladd(&w2, &w1, &w0, ws[4], p[9]); word3_muladd(&w2, &w1, &w0, ws[5], p[8]); word3_muladd(&w2, &w1, &w0, ws[6], p[7]); word3_muladd(&w2, &w1, &w0, ws[7], p[6]); word3_muladd(&w2, &w1, &w0, ws[8], p[5]); word3_muladd(&w2, &w1, &w0, ws[9], p[4]); word3_muladd(&w2, &w1, &w0, ws[10], p[3]); word3_muladd(&w2, &w1, &w0, ws[11], p[2]); word3_muladd(&w2, &w1, &w0, ws[12], p[1]); word3_add(&w2, &w1, &w0, z[13]); ws[13] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[13], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[14]); word3_muladd(&w2, &w1, &w0, ws[1], p[13]); word3_muladd(&w2, &w1, &w0, ws[2], p[12]); word3_muladd(&w2, &w1, &w0, ws[3], p[11]); word3_muladd(&w2, &w1, &w0, ws[4], p[10]); word3_muladd(&w2, &w1, &w0, ws[5], p[9]); word3_muladd(&w2, &w1, &w0, ws[6], p[8]); word3_muladd(&w2, &w1, &w0, ws[7], p[7]); word3_muladd(&w2, &w1, &w0, ws[8], p[6]); word3_muladd(&w2, &w1, &w0, ws[9], p[5]); word3_muladd(&w2, &w1, &w0, ws[10], p[4]); word3_muladd(&w2, &w1, &w0, ws[11], p[3]); word3_muladd(&w2, &w1, &w0, ws[12], p[2]); word3_muladd(&w2, &w1, &w0, ws[13], p[1]); word3_add(&w2, &w1, &w0, z[14]); ws[14] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[14], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[15]); word3_muladd(&w2, &w1, &w0, ws[1], p[14]); word3_muladd(&w2, &w1, &w0, ws[2], p[13]); word3_muladd(&w2, &w1, &w0, ws[3], p[12]); word3_muladd(&w2, &w1, &w0, ws[4], p[11]); word3_muladd(&w2, &w1, &w0, ws[5], p[10]); word3_muladd(&w2, &w1, &w0, ws[6], p[9]); word3_muladd(&w2, &w1, &w0, ws[7], p[8]); word3_muladd(&w2, &w1, &w0, ws[8], p[7]); word3_muladd(&w2, &w1, &w0, ws[9], p[6]); word3_muladd(&w2, &w1, &w0, ws[10], p[5]); word3_muladd(&w2, &w1, &w0, ws[11], p[4]); word3_muladd(&w2, &w1, &w0, ws[12], p[3]); word3_muladd(&w2, &w1, &w0, ws[13], p[2]); word3_muladd(&w2, &w1, &w0, ws[14], p[1]); word3_add(&w2, &w1, &w0, z[15]); ws[15] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[15], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[1], p[15]); word3_muladd(&w2, &w1, &w0, ws[2], p[14]); word3_muladd(&w2, &w1, &w0, ws[3], p[13]); word3_muladd(&w2, &w1, &w0, ws[4], p[12]); word3_muladd(&w2, &w1, &w0, ws[5], p[11]); word3_muladd(&w2, &w1, &w0, ws[6], p[10]); word3_muladd(&w2, &w1, &w0, ws[7], p[9]); word3_muladd(&w2, &w1, &w0, ws[8], p[8]); word3_muladd(&w2, &w1, &w0, ws[9], p[7]); word3_muladd(&w2, &w1, &w0, ws[10], p[6]); word3_muladd(&w2, &w1, &w0, ws[11], p[5]); word3_muladd(&w2, &w1, &w0, ws[12], p[4]); word3_muladd(&w2, &w1, &w0, ws[13], p[3]); word3_muladd(&w2, &w1, &w0, ws[14], p[2]); word3_muladd(&w2, &w1, &w0, ws[15], p[1]); word3_add(&w2, &w1, &w0, z[16]); ws[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[2], p[15]); word3_muladd(&w2, &w1, &w0, ws[3], p[14]); word3_muladd(&w2, &w1, &w0, ws[4], p[13]); word3_muladd(&w2, &w1, &w0, ws[5], p[12]); word3_muladd(&w2, &w1, &w0, ws[6], p[11]); word3_muladd(&w2, &w1, &w0, ws[7], p[10]); word3_muladd(&w2, &w1, &w0, ws[8], p[9]); word3_muladd(&w2, &w1, &w0, ws[9], p[8]); word3_muladd(&w2, &w1, &w0, ws[10], p[7]); word3_muladd(&w2, &w1, &w0, ws[11], p[6]); word3_muladd(&w2, &w1, &w0, ws[12], p[5]); word3_muladd(&w2, &w1, &w0, ws[13], p[4]); word3_muladd(&w2, &w1, &w0, ws[14], p[3]); word3_muladd(&w2, &w1, &w0, ws[15], p[2]); word3_add(&w2, &w1, &w0, z[17]); ws[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[3], p[15]); word3_muladd(&w2, &w1, &w0, ws[4], p[14]); word3_muladd(&w2, &w1, &w0, ws[5], p[13]); word3_muladd(&w2, &w1, &w0, ws[6], p[12]); word3_muladd(&w2, &w1, &w0, ws[7], p[11]); word3_muladd(&w2, &w1, &w0, ws[8], p[10]); word3_muladd(&w2, &w1, &w0, ws[9], p[9]); word3_muladd(&w2, &w1, &w0, ws[10], p[8]); word3_muladd(&w2, &w1, &w0, ws[11], p[7]); word3_muladd(&w2, &w1, &w0, ws[12], p[6]); word3_muladd(&w2, &w1, &w0, ws[13], p[5]); word3_muladd(&w2, &w1, &w0, ws[14], p[4]); word3_muladd(&w2, &w1, &w0, ws[15], p[3]); word3_add(&w2, &w1, &w0, z[18]); ws[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[4], p[15]); word3_muladd(&w2, &w1, &w0, ws[5], p[14]); word3_muladd(&w2, &w1, &w0, ws[6], p[13]); word3_muladd(&w2, &w1, &w0, ws[7], p[12]); word3_muladd(&w2, &w1, &w0, ws[8], p[11]); word3_muladd(&w2, &w1, &w0, ws[9], p[10]); word3_muladd(&w2, &w1, &w0, ws[10], p[9]); word3_muladd(&w2, &w1, &w0, ws[11], p[8]); word3_muladd(&w2, &w1, &w0, ws[12], p[7]); word3_muladd(&w2, &w1, &w0, ws[13], p[6]); word3_muladd(&w2, &w1, &w0, ws[14], p[5]); word3_muladd(&w2, &w1, &w0, ws[15], p[4]); word3_add(&w2, &w1, &w0, z[19]); ws[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[5], p[15]); word3_muladd(&w2, &w1, &w0, ws[6], p[14]); word3_muladd(&w2, &w1, &w0, ws[7], p[13]); word3_muladd(&w2, &w1, &w0, ws[8], p[12]); word3_muladd(&w2, &w1, &w0, ws[9], p[11]); word3_muladd(&w2, &w1, &w0, ws[10], p[10]); word3_muladd(&w2, &w1, &w0, ws[11], p[9]); word3_muladd(&w2, &w1, &w0, ws[12], p[8]); word3_muladd(&w2, &w1, &w0, ws[13], p[7]); word3_muladd(&w2, &w1, &w0, ws[14], p[6]); word3_muladd(&w2, &w1, &w0, ws[15], p[5]); word3_add(&w2, &w1, &w0, z[20]); ws[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[6], p[15]); word3_muladd(&w2, &w1, &w0, ws[7], p[14]); word3_muladd(&w2, &w1, &w0, ws[8], p[13]); word3_muladd(&w2, &w1, &w0, ws[9], p[12]); word3_muladd(&w2, &w1, &w0, ws[10], p[11]); word3_muladd(&w2, &w1, &w0, ws[11], p[10]); word3_muladd(&w2, &w1, &w0, ws[12], p[9]); word3_muladd(&w2, &w1, &w0, ws[13], p[8]); word3_muladd(&w2, &w1, &w0, ws[14], p[7]); word3_muladd(&w2, &w1, &w0, ws[15], p[6]); word3_add(&w2, &w1, &w0, z[21]); ws[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[7], p[15]); word3_muladd(&w2, &w1, &w0, ws[8], p[14]); word3_muladd(&w2, &w1, &w0, ws[9], p[13]); word3_muladd(&w2, &w1, &w0, ws[10], p[12]); word3_muladd(&w2, &w1, &w0, ws[11], p[11]); word3_muladd(&w2, &w1, &w0, ws[12], p[10]); word3_muladd(&w2, &w1, &w0, ws[13], p[9]); word3_muladd(&w2, &w1, &w0, ws[14], p[8]); word3_muladd(&w2, &w1, &w0, ws[15], p[7]); word3_add(&w2, &w1, &w0, z[22]); ws[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[8], p[15]); word3_muladd(&w2, &w1, &w0, ws[9], p[14]); word3_muladd(&w2, &w1, &w0, ws[10], p[13]); word3_muladd(&w2, &w1, &w0, ws[11], p[12]); word3_muladd(&w2, &w1, &w0, ws[12], p[11]); word3_muladd(&w2, &w1, &w0, ws[13], p[10]); word3_muladd(&w2, &w1, &w0, ws[14], p[9]); word3_muladd(&w2, &w1, &w0, ws[15], p[8]); word3_add(&w2, &w1, &w0, z[23]); ws[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[9], p[15]); word3_muladd(&w2, &w1, &w0, ws[10], p[14]); word3_muladd(&w2, &w1, &w0, ws[11], p[13]); word3_muladd(&w2, &w1, &w0, ws[12], p[12]); word3_muladd(&w2, &w1, &w0, ws[13], p[11]); word3_muladd(&w2, &w1, &w0, ws[14], p[10]); word3_muladd(&w2, &w1, &w0, ws[15], p[9]); word3_add(&w2, &w1, &w0, z[24]); ws[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[10], p[15]); word3_muladd(&w2, &w1, &w0, ws[11], p[14]); word3_muladd(&w2, &w1, &w0, ws[12], p[13]); word3_muladd(&w2, &w1, &w0, ws[13], p[12]); word3_muladd(&w2, &w1, &w0, ws[14], p[11]); word3_muladd(&w2, &w1, &w0, ws[15], p[10]); word3_add(&w2, &w1, &w0, z[25]); ws[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[11], p[15]); word3_muladd(&w2, &w1, &w0, ws[12], p[14]); word3_muladd(&w2, &w1, &w0, ws[13], p[13]); word3_muladd(&w2, &w1, &w0, ws[14], p[12]); word3_muladd(&w2, &w1, &w0, ws[15], p[11]); word3_add(&w2, &w1, &w0, z[26]); ws[10] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[12], p[15]); word3_muladd(&w2, &w1, &w0, ws[13], p[14]); word3_muladd(&w2, &w1, &w0, ws[14], p[13]); word3_muladd(&w2, &w1, &w0, ws[15], p[12]); word3_add(&w2, &w1, &w0, z[27]); ws[11] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[13], p[15]); word3_muladd(&w2, &w1, &w0, ws[14], p[14]); word3_muladd(&w2, &w1, &w0, ws[15], p[13]); word3_add(&w2, &w1, &w0, z[28]); ws[12] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[14], p[15]); word3_muladd(&w2, &w1, &w0, ws[15], p[14]); word3_add(&w2, &w1, &w0, z[29]); ws[13] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[15], p[15]); word3_add(&w2, &w1, &w0, z[30]); ws[14] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[31]); ws[15] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[33]); ws[16] = w0; ws[17] = w1; word borrow = bigint_sub3(ws + 16 + 1, ws, 16 + 1, p, 16); CT::conditional_copy_mem(borrow, z, ws, ws + 17, 17); clear_mem(z + 16, 2*(16+1) - 16); } void bigint_monty_redc_24(word z[], const word p[24], word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[1]); word3_add(&w2, &w1, &w0, z[1]); ws[1] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[1], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[2]); word3_muladd(&w2, &w1, &w0, ws[1], p[1]); word3_add(&w2, &w1, &w0, z[2]); ws[2] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[2], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[3]); word3_muladd(&w2, &w1, &w0, ws[1], p[2]); word3_muladd(&w2, &w1, &w0, ws[2], p[1]); word3_add(&w2, &w1, &w0, z[3]); ws[3] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[3], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[4]); word3_muladd(&w2, &w1, &w0, ws[1], p[3]); word3_muladd(&w2, &w1, &w0, ws[2], p[2]); word3_muladd(&w2, &w1, &w0, ws[3], p[1]); word3_add(&w2, &w1, &w0, z[4]); ws[4] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[4], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[5]); word3_muladd(&w2, &w1, &w0, ws[1], p[4]); word3_muladd(&w2, &w1, &w0, ws[2], p[3]); word3_muladd(&w2, &w1, &w0, ws[3], p[2]); word3_muladd(&w2, &w1, &w0, ws[4], p[1]); word3_add(&w2, &w1, &w0, z[5]); ws[5] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[5], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[6]); word3_muladd(&w2, &w1, &w0, ws[1], p[5]); word3_muladd(&w2, &w1, &w0, ws[2], p[4]); word3_muladd(&w2, &w1, &w0, ws[3], p[3]); word3_muladd(&w2, &w1, &w0, ws[4], p[2]); word3_muladd(&w2, &w1, &w0, ws[5], p[1]); word3_add(&w2, &w1, &w0, z[6]); ws[6] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[6], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[7]); word3_muladd(&w2, &w1, &w0, ws[1], p[6]); word3_muladd(&w2, &w1, &w0, ws[2], p[5]); word3_muladd(&w2, &w1, &w0, ws[3], p[4]); word3_muladd(&w2, &w1, &w0, ws[4], p[3]); word3_muladd(&w2, &w1, &w0, ws[5], p[2]); word3_muladd(&w2, &w1, &w0, ws[6], p[1]); word3_add(&w2, &w1, &w0, z[7]); ws[7] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[7], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[8]); word3_muladd(&w2, &w1, &w0, ws[1], p[7]); word3_muladd(&w2, &w1, &w0, ws[2], p[6]); word3_muladd(&w2, &w1, &w0, ws[3], p[5]); word3_muladd(&w2, &w1, &w0, ws[4], p[4]); word3_muladd(&w2, &w1, &w0, ws[5], p[3]); word3_muladd(&w2, &w1, &w0, ws[6], p[2]); word3_muladd(&w2, &w1, &w0, ws[7], p[1]); word3_add(&w2, &w1, &w0, z[8]); ws[8] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[8], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[9]); word3_muladd(&w2, &w1, &w0, ws[1], p[8]); word3_muladd(&w2, &w1, &w0, ws[2], p[7]); word3_muladd(&w2, &w1, &w0, ws[3], p[6]); word3_muladd(&w2, &w1, &w0, ws[4], p[5]); word3_muladd(&w2, &w1, &w0, ws[5], p[4]); word3_muladd(&w2, &w1, &w0, ws[6], p[3]); word3_muladd(&w2, &w1, &w0, ws[7], p[2]); word3_muladd(&w2, &w1, &w0, ws[8], p[1]); word3_add(&w2, &w1, &w0, z[9]); ws[9] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[9], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[10]); word3_muladd(&w2, &w1, &w0, ws[1], p[9]); word3_muladd(&w2, &w1, &w0, ws[2], p[8]); word3_muladd(&w2, &w1, &w0, ws[3], p[7]); word3_muladd(&w2, &w1, &w0, ws[4], p[6]); word3_muladd(&w2, &w1, &w0, ws[5], p[5]); word3_muladd(&w2, &w1, &w0, ws[6], p[4]); word3_muladd(&w2, &w1, &w0, ws[7], p[3]); word3_muladd(&w2, &w1, &w0, ws[8], p[2]); word3_muladd(&w2, &w1, &w0, ws[9], p[1]); word3_add(&w2, &w1, &w0, z[10]); ws[10] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[10], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[11]); word3_muladd(&w2, &w1, &w0, ws[1], p[10]); word3_muladd(&w2, &w1, &w0, ws[2], p[9]); word3_muladd(&w2, &w1, &w0, ws[3], p[8]); word3_muladd(&w2, &w1, &w0, ws[4], p[7]); word3_muladd(&w2, &w1, &w0, ws[5], p[6]); word3_muladd(&w2, &w1, &w0, ws[6], p[5]); word3_muladd(&w2, &w1, &w0, ws[7], p[4]); word3_muladd(&w2, &w1, &w0, ws[8], p[3]); word3_muladd(&w2, &w1, &w0, ws[9], p[2]); word3_muladd(&w2, &w1, &w0, ws[10], p[1]); word3_add(&w2, &w1, &w0, z[11]); ws[11] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[11], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[12]); word3_muladd(&w2, &w1, &w0, ws[1], p[11]); word3_muladd(&w2, &w1, &w0, ws[2], p[10]); word3_muladd(&w2, &w1, &w0, ws[3], p[9]); word3_muladd(&w2, &w1, &w0, ws[4], p[8]); word3_muladd(&w2, &w1, &w0, ws[5], p[7]); word3_muladd(&w2, &w1, &w0, ws[6], p[6]); word3_muladd(&w2, &w1, &w0, ws[7], p[5]); word3_muladd(&w2, &w1, &w0, ws[8], p[4]); word3_muladd(&w2, &w1, &w0, ws[9], p[3]); word3_muladd(&w2, &w1, &w0, ws[10], p[2]); word3_muladd(&w2, &w1, &w0, ws[11], p[1]); word3_add(&w2, &w1, &w0, z[12]); ws[12] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[12], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[13]); word3_muladd(&w2, &w1, &w0, ws[1], p[12]); word3_muladd(&w2, &w1, &w0, ws[2], p[11]); word3_muladd(&w2, &w1, &w0, ws[3], p[10]); word3_muladd(&w2, &w1, &w0, ws[4], p[9]); word3_muladd(&w2, &w1, &w0, ws[5], p[8]); word3_muladd(&w2, &w1, &w0, ws[6], p[7]); word3_muladd(&w2, &w1, &w0, ws[7], p[6]); word3_muladd(&w2, &w1, &w0, ws[8], p[5]); word3_muladd(&w2, &w1, &w0, ws[9], p[4]); word3_muladd(&w2, &w1, &w0, ws[10], p[3]); word3_muladd(&w2, &w1, &w0, ws[11], p[2]); word3_muladd(&w2, &w1, &w0, ws[12], p[1]); word3_add(&w2, &w1, &w0, z[13]); ws[13] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[13], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[14]); word3_muladd(&w2, &w1, &w0, ws[1], p[13]); word3_muladd(&w2, &w1, &w0, ws[2], p[12]); word3_muladd(&w2, &w1, &w0, ws[3], p[11]); word3_muladd(&w2, &w1, &w0, ws[4], p[10]); word3_muladd(&w2, &w1, &w0, ws[5], p[9]); word3_muladd(&w2, &w1, &w0, ws[6], p[8]); word3_muladd(&w2, &w1, &w0, ws[7], p[7]); word3_muladd(&w2, &w1, &w0, ws[8], p[6]); word3_muladd(&w2, &w1, &w0, ws[9], p[5]); word3_muladd(&w2, &w1, &w0, ws[10], p[4]); word3_muladd(&w2, &w1, &w0, ws[11], p[3]); word3_muladd(&w2, &w1, &w0, ws[12], p[2]); word3_muladd(&w2, &w1, &w0, ws[13], p[1]); word3_add(&w2, &w1, &w0, z[14]); ws[14] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[14], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[15]); word3_muladd(&w2, &w1, &w0, ws[1], p[14]); word3_muladd(&w2, &w1, &w0, ws[2], p[13]); word3_muladd(&w2, &w1, &w0, ws[3], p[12]); word3_muladd(&w2, &w1, &w0, ws[4], p[11]); word3_muladd(&w2, &w1, &w0, ws[5], p[10]); word3_muladd(&w2, &w1, &w0, ws[6], p[9]); word3_muladd(&w2, &w1, &w0, ws[7], p[8]); word3_muladd(&w2, &w1, &w0, ws[8], p[7]); word3_muladd(&w2, &w1, &w0, ws[9], p[6]); word3_muladd(&w2, &w1, &w0, ws[10], p[5]); word3_muladd(&w2, &w1, &w0, ws[11], p[4]); word3_muladd(&w2, &w1, &w0, ws[12], p[3]); word3_muladd(&w2, &w1, &w0, ws[13], p[2]); word3_muladd(&w2, &w1, &w0, ws[14], p[1]); word3_add(&w2, &w1, &w0, z[15]); ws[15] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[15], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[16]); word3_muladd(&w2, &w1, &w0, ws[1], p[15]); word3_muladd(&w2, &w1, &w0, ws[2], p[14]); word3_muladd(&w2, &w1, &w0, ws[3], p[13]); word3_muladd(&w2, &w1, &w0, ws[4], p[12]); word3_muladd(&w2, &w1, &w0, ws[5], p[11]); word3_muladd(&w2, &w1, &w0, ws[6], p[10]); word3_muladd(&w2, &w1, &w0, ws[7], p[9]); word3_muladd(&w2, &w1, &w0, ws[8], p[8]); word3_muladd(&w2, &w1, &w0, ws[9], p[7]); word3_muladd(&w2, &w1, &w0, ws[10], p[6]); word3_muladd(&w2, &w1, &w0, ws[11], p[5]); word3_muladd(&w2, &w1, &w0, ws[12], p[4]); word3_muladd(&w2, &w1, &w0, ws[13], p[3]); word3_muladd(&w2, &w1, &w0, ws[14], p[2]); word3_muladd(&w2, &w1, &w0, ws[15], p[1]); word3_add(&w2, &w1, &w0, z[16]); ws[16] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[16], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[17]); word3_muladd(&w2, &w1, &w0, ws[1], p[16]); word3_muladd(&w2, &w1, &w0, ws[2], p[15]); word3_muladd(&w2, &w1, &w0, ws[3], p[14]); word3_muladd(&w2, &w1, &w0, ws[4], p[13]); word3_muladd(&w2, &w1, &w0, ws[5], p[12]); word3_muladd(&w2, &w1, &w0, ws[6], p[11]); word3_muladd(&w2, &w1, &w0, ws[7], p[10]); word3_muladd(&w2, &w1, &w0, ws[8], p[9]); word3_muladd(&w2, &w1, &w0, ws[9], p[8]); word3_muladd(&w2, &w1, &w0, ws[10], p[7]); word3_muladd(&w2, &w1, &w0, ws[11], p[6]); word3_muladd(&w2, &w1, &w0, ws[12], p[5]); word3_muladd(&w2, &w1, &w0, ws[13], p[4]); word3_muladd(&w2, &w1, &w0, ws[14], p[3]); word3_muladd(&w2, &w1, &w0, ws[15], p[2]); word3_muladd(&w2, &w1, &w0, ws[16], p[1]); word3_add(&w2, &w1, &w0, z[17]); ws[17] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[17], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[18]); word3_muladd(&w2, &w1, &w0, ws[1], p[17]); word3_muladd(&w2, &w1, &w0, ws[2], p[16]); word3_muladd(&w2, &w1, &w0, ws[3], p[15]); word3_muladd(&w2, &w1, &w0, ws[4], p[14]); word3_muladd(&w2, &w1, &w0, ws[5], p[13]); word3_muladd(&w2, &w1, &w0, ws[6], p[12]); word3_muladd(&w2, &w1, &w0, ws[7], p[11]); word3_muladd(&w2, &w1, &w0, ws[8], p[10]); word3_muladd(&w2, &w1, &w0, ws[9], p[9]); word3_muladd(&w2, &w1, &w0, ws[10], p[8]); word3_muladd(&w2, &w1, &w0, ws[11], p[7]); word3_muladd(&w2, &w1, &w0, ws[12], p[6]); word3_muladd(&w2, &w1, &w0, ws[13], p[5]); word3_muladd(&w2, &w1, &w0, ws[14], p[4]); word3_muladd(&w2, &w1, &w0, ws[15], p[3]); word3_muladd(&w2, &w1, &w0, ws[16], p[2]); word3_muladd(&w2, &w1, &w0, ws[17], p[1]); word3_add(&w2, &w1, &w0, z[18]); ws[18] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[18], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[19]); word3_muladd(&w2, &w1, &w0, ws[1], p[18]); word3_muladd(&w2, &w1, &w0, ws[2], p[17]); word3_muladd(&w2, &w1, &w0, ws[3], p[16]); word3_muladd(&w2, &w1, &w0, ws[4], p[15]); word3_muladd(&w2, &w1, &w0, ws[5], p[14]); word3_muladd(&w2, &w1, &w0, ws[6], p[13]); word3_muladd(&w2, &w1, &w0, ws[7], p[12]); word3_muladd(&w2, &w1, &w0, ws[8], p[11]); word3_muladd(&w2, &w1, &w0, ws[9], p[10]); word3_muladd(&w2, &w1, &w0, ws[10], p[9]); word3_muladd(&w2, &w1, &w0, ws[11], p[8]); word3_muladd(&w2, &w1, &w0, ws[12], p[7]); word3_muladd(&w2, &w1, &w0, ws[13], p[6]); word3_muladd(&w2, &w1, &w0, ws[14], p[5]); word3_muladd(&w2, &w1, &w0, ws[15], p[4]); word3_muladd(&w2, &w1, &w0, ws[16], p[3]); word3_muladd(&w2, &w1, &w0, ws[17], p[2]); word3_muladd(&w2, &w1, &w0, ws[18], p[1]); word3_add(&w2, &w1, &w0, z[19]); ws[19] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[19], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[20]); word3_muladd(&w2, &w1, &w0, ws[1], p[19]); word3_muladd(&w2, &w1, &w0, ws[2], p[18]); word3_muladd(&w2, &w1, &w0, ws[3], p[17]); word3_muladd(&w2, &w1, &w0, ws[4], p[16]); word3_muladd(&w2, &w1, &w0, ws[5], p[15]); word3_muladd(&w2, &w1, &w0, ws[6], p[14]); word3_muladd(&w2, &w1, &w0, ws[7], p[13]); word3_muladd(&w2, &w1, &w0, ws[8], p[12]); word3_muladd(&w2, &w1, &w0, ws[9], p[11]); word3_muladd(&w2, &w1, &w0, ws[10], p[10]); word3_muladd(&w2, &w1, &w0, ws[11], p[9]); word3_muladd(&w2, &w1, &w0, ws[12], p[8]); word3_muladd(&w2, &w1, &w0, ws[13], p[7]); word3_muladd(&w2, &w1, &w0, ws[14], p[6]); word3_muladd(&w2, &w1, &w0, ws[15], p[5]); word3_muladd(&w2, &w1, &w0, ws[16], p[4]); word3_muladd(&w2, &w1, &w0, ws[17], p[3]); word3_muladd(&w2, &w1, &w0, ws[18], p[2]); word3_muladd(&w2, &w1, &w0, ws[19], p[1]); word3_add(&w2, &w1, &w0, z[20]); ws[20] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[20], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[21]); word3_muladd(&w2, &w1, &w0, ws[1], p[20]); word3_muladd(&w2, &w1, &w0, ws[2], p[19]); word3_muladd(&w2, &w1, &w0, ws[3], p[18]); word3_muladd(&w2, &w1, &w0, ws[4], p[17]); word3_muladd(&w2, &w1, &w0, ws[5], p[16]); word3_muladd(&w2, &w1, &w0, ws[6], p[15]); word3_muladd(&w2, &w1, &w0, ws[7], p[14]); word3_muladd(&w2, &w1, &w0, ws[8], p[13]); word3_muladd(&w2, &w1, &w0, ws[9], p[12]); word3_muladd(&w2, &w1, &w0, ws[10], p[11]); word3_muladd(&w2, &w1, &w0, ws[11], p[10]); word3_muladd(&w2, &w1, &w0, ws[12], p[9]); word3_muladd(&w2, &w1, &w0, ws[13], p[8]); word3_muladd(&w2, &w1, &w0, ws[14], p[7]); word3_muladd(&w2, &w1, &w0, ws[15], p[6]); word3_muladd(&w2, &w1, &w0, ws[16], p[5]); word3_muladd(&w2, &w1, &w0, ws[17], p[4]); word3_muladd(&w2, &w1, &w0, ws[18], p[3]); word3_muladd(&w2, &w1, &w0, ws[19], p[2]); word3_muladd(&w2, &w1, &w0, ws[20], p[1]); word3_add(&w2, &w1, &w0, z[21]); ws[21] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[21], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[22]); word3_muladd(&w2, &w1, &w0, ws[1], p[21]); word3_muladd(&w2, &w1, &w0, ws[2], p[20]); word3_muladd(&w2, &w1, &w0, ws[3], p[19]); word3_muladd(&w2, &w1, &w0, ws[4], p[18]); word3_muladd(&w2, &w1, &w0, ws[5], p[17]); word3_muladd(&w2, &w1, &w0, ws[6], p[16]); word3_muladd(&w2, &w1, &w0, ws[7], p[15]); word3_muladd(&w2, &w1, &w0, ws[8], p[14]); word3_muladd(&w2, &w1, &w0, ws[9], p[13]); word3_muladd(&w2, &w1, &w0, ws[10], p[12]); word3_muladd(&w2, &w1, &w0, ws[11], p[11]); word3_muladd(&w2, &w1, &w0, ws[12], p[10]); word3_muladd(&w2, &w1, &w0, ws[13], p[9]); word3_muladd(&w2, &w1, &w0, ws[14], p[8]); word3_muladd(&w2, &w1, &w0, ws[15], p[7]); word3_muladd(&w2, &w1, &w0, ws[16], p[6]); word3_muladd(&w2, &w1, &w0, ws[17], p[5]); word3_muladd(&w2, &w1, &w0, ws[18], p[4]); word3_muladd(&w2, &w1, &w0, ws[19], p[3]); word3_muladd(&w2, &w1, &w0, ws[20], p[2]); word3_muladd(&w2, &w1, &w0, ws[21], p[1]); word3_add(&w2, &w1, &w0, z[22]); ws[22] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[22], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[23]); word3_muladd(&w2, &w1, &w0, ws[1], p[22]); word3_muladd(&w2, &w1, &w0, ws[2], p[21]); word3_muladd(&w2, &w1, &w0, ws[3], p[20]); word3_muladd(&w2, &w1, &w0, ws[4], p[19]); word3_muladd(&w2, &w1, &w0, ws[5], p[18]); word3_muladd(&w2, &w1, &w0, ws[6], p[17]); word3_muladd(&w2, &w1, &w0, ws[7], p[16]); word3_muladd(&w2, &w1, &w0, ws[8], p[15]); word3_muladd(&w2, &w1, &w0, ws[9], p[14]); word3_muladd(&w2, &w1, &w0, ws[10], p[13]); word3_muladd(&w2, &w1, &w0, ws[11], p[12]); word3_muladd(&w2, &w1, &w0, ws[12], p[11]); word3_muladd(&w2, &w1, &w0, ws[13], p[10]); word3_muladd(&w2, &w1, &w0, ws[14], p[9]); word3_muladd(&w2, &w1, &w0, ws[15], p[8]); word3_muladd(&w2, &w1, &w0, ws[16], p[7]); word3_muladd(&w2, &w1, &w0, ws[17], p[6]); word3_muladd(&w2, &w1, &w0, ws[18], p[5]); word3_muladd(&w2, &w1, &w0, ws[19], p[4]); word3_muladd(&w2, &w1, &w0, ws[20], p[3]); word3_muladd(&w2, &w1, &w0, ws[21], p[2]); word3_muladd(&w2, &w1, &w0, ws[22], p[1]); word3_add(&w2, &w1, &w0, z[23]); ws[23] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[23], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[1], p[23]); word3_muladd(&w2, &w1, &w0, ws[2], p[22]); word3_muladd(&w2, &w1, &w0, ws[3], p[21]); word3_muladd(&w2, &w1, &w0, ws[4], p[20]); word3_muladd(&w2, &w1, &w0, ws[5], p[19]); word3_muladd(&w2, &w1, &w0, ws[6], p[18]); word3_muladd(&w2, &w1, &w0, ws[7], p[17]); word3_muladd(&w2, &w1, &w0, ws[8], p[16]); word3_muladd(&w2, &w1, &w0, ws[9], p[15]); word3_muladd(&w2, &w1, &w0, ws[10], p[14]); word3_muladd(&w2, &w1, &w0, ws[11], p[13]); word3_muladd(&w2, &w1, &w0, ws[12], p[12]); word3_muladd(&w2, &w1, &w0, ws[13], p[11]); word3_muladd(&w2, &w1, &w0, ws[14], p[10]); word3_muladd(&w2, &w1, &w0, ws[15], p[9]); word3_muladd(&w2, &w1, &w0, ws[16], p[8]); word3_muladd(&w2, &w1, &w0, ws[17], p[7]); word3_muladd(&w2, &w1, &w0, ws[18], p[6]); word3_muladd(&w2, &w1, &w0, ws[19], p[5]); word3_muladd(&w2, &w1, &w0, ws[20], p[4]); word3_muladd(&w2, &w1, &w0, ws[21], p[3]); word3_muladd(&w2, &w1, &w0, ws[22], p[2]); word3_muladd(&w2, &w1, &w0, ws[23], p[1]); word3_add(&w2, &w1, &w0, z[24]); ws[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[2], p[23]); word3_muladd(&w2, &w1, &w0, ws[3], p[22]); word3_muladd(&w2, &w1, &w0, ws[4], p[21]); word3_muladd(&w2, &w1, &w0, ws[5], p[20]); word3_muladd(&w2, &w1, &w0, ws[6], p[19]); word3_muladd(&w2, &w1, &w0, ws[7], p[18]); word3_muladd(&w2, &w1, &w0, ws[8], p[17]); word3_muladd(&w2, &w1, &w0, ws[9], p[16]); word3_muladd(&w2, &w1, &w0, ws[10], p[15]); word3_muladd(&w2, &w1, &w0, ws[11], p[14]); word3_muladd(&w2, &w1, &w0, ws[12], p[13]); word3_muladd(&w2, &w1, &w0, ws[13], p[12]); word3_muladd(&w2, &w1, &w0, ws[14], p[11]); word3_muladd(&w2, &w1, &w0, ws[15], p[10]); word3_muladd(&w2, &w1, &w0, ws[16], p[9]); word3_muladd(&w2, &w1, &w0, ws[17], p[8]); word3_muladd(&w2, &w1, &w0, ws[18], p[7]); word3_muladd(&w2, &w1, &w0, ws[19], p[6]); word3_muladd(&w2, &w1, &w0, ws[20], p[5]); word3_muladd(&w2, &w1, &w0, ws[21], p[4]); word3_muladd(&w2, &w1, &w0, ws[22], p[3]); word3_muladd(&w2, &w1, &w0, ws[23], p[2]); word3_add(&w2, &w1, &w0, z[25]); ws[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[3], p[23]); word3_muladd(&w2, &w1, &w0, ws[4], p[22]); word3_muladd(&w2, &w1, &w0, ws[5], p[21]); word3_muladd(&w2, &w1, &w0, ws[6], p[20]); word3_muladd(&w2, &w1, &w0, ws[7], p[19]); word3_muladd(&w2, &w1, &w0, ws[8], p[18]); word3_muladd(&w2, &w1, &w0, ws[9], p[17]); word3_muladd(&w2, &w1, &w0, ws[10], p[16]); word3_muladd(&w2, &w1, &w0, ws[11], p[15]); word3_muladd(&w2, &w1, &w0, ws[12], p[14]); word3_muladd(&w2, &w1, &w0, ws[13], p[13]); word3_muladd(&w2, &w1, &w0, ws[14], p[12]); word3_muladd(&w2, &w1, &w0, ws[15], p[11]); word3_muladd(&w2, &w1, &w0, ws[16], p[10]); word3_muladd(&w2, &w1, &w0, ws[17], p[9]); word3_muladd(&w2, &w1, &w0, ws[18], p[8]); word3_muladd(&w2, &w1, &w0, ws[19], p[7]); word3_muladd(&w2, &w1, &w0, ws[20], p[6]); word3_muladd(&w2, &w1, &w0, ws[21], p[5]); word3_muladd(&w2, &w1, &w0, ws[22], p[4]); word3_muladd(&w2, &w1, &w0, ws[23], p[3]); word3_add(&w2, &w1, &w0, z[26]); ws[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[4], p[23]); word3_muladd(&w2, &w1, &w0, ws[5], p[22]); word3_muladd(&w2, &w1, &w0, ws[6], p[21]); word3_muladd(&w2, &w1, &w0, ws[7], p[20]); word3_muladd(&w2, &w1, &w0, ws[8], p[19]); word3_muladd(&w2, &w1, &w0, ws[9], p[18]); word3_muladd(&w2, &w1, &w0, ws[10], p[17]); word3_muladd(&w2, &w1, &w0, ws[11], p[16]); word3_muladd(&w2, &w1, &w0, ws[12], p[15]); word3_muladd(&w2, &w1, &w0, ws[13], p[14]); word3_muladd(&w2, &w1, &w0, ws[14], p[13]); word3_muladd(&w2, &w1, &w0, ws[15], p[12]); word3_muladd(&w2, &w1, &w0, ws[16], p[11]); word3_muladd(&w2, &w1, &w0, ws[17], p[10]); word3_muladd(&w2, &w1, &w0, ws[18], p[9]); word3_muladd(&w2, &w1, &w0, ws[19], p[8]); word3_muladd(&w2, &w1, &w0, ws[20], p[7]); word3_muladd(&w2, &w1, &w0, ws[21], p[6]); word3_muladd(&w2, &w1, &w0, ws[22], p[5]); word3_muladd(&w2, &w1, &w0, ws[23], p[4]); word3_add(&w2, &w1, &w0, z[27]); ws[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[5], p[23]); word3_muladd(&w2, &w1, &w0, ws[6], p[22]); word3_muladd(&w2, &w1, &w0, ws[7], p[21]); word3_muladd(&w2, &w1, &w0, ws[8], p[20]); word3_muladd(&w2, &w1, &w0, ws[9], p[19]); word3_muladd(&w2, &w1, &w0, ws[10], p[18]); word3_muladd(&w2, &w1, &w0, ws[11], p[17]); word3_muladd(&w2, &w1, &w0, ws[12], p[16]); word3_muladd(&w2, &w1, &w0, ws[13], p[15]); word3_muladd(&w2, &w1, &w0, ws[14], p[14]); word3_muladd(&w2, &w1, &w0, ws[15], p[13]); word3_muladd(&w2, &w1, &w0, ws[16], p[12]); word3_muladd(&w2, &w1, &w0, ws[17], p[11]); word3_muladd(&w2, &w1, &w0, ws[18], p[10]); word3_muladd(&w2, &w1, &w0, ws[19], p[9]); word3_muladd(&w2, &w1, &w0, ws[20], p[8]); word3_muladd(&w2, &w1, &w0, ws[21], p[7]); word3_muladd(&w2, &w1, &w0, ws[22], p[6]); word3_muladd(&w2, &w1, &w0, ws[23], p[5]); word3_add(&w2, &w1, &w0, z[28]); ws[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[6], p[23]); word3_muladd(&w2, &w1, &w0, ws[7], p[22]); word3_muladd(&w2, &w1, &w0, ws[8], p[21]); word3_muladd(&w2, &w1, &w0, ws[9], p[20]); word3_muladd(&w2, &w1, &w0, ws[10], p[19]); word3_muladd(&w2, &w1, &w0, ws[11], p[18]); word3_muladd(&w2, &w1, &w0, ws[12], p[17]); word3_muladd(&w2, &w1, &w0, ws[13], p[16]); word3_muladd(&w2, &w1, &w0, ws[14], p[15]); word3_muladd(&w2, &w1, &w0, ws[15], p[14]); word3_muladd(&w2, &w1, &w0, ws[16], p[13]); word3_muladd(&w2, &w1, &w0, ws[17], p[12]); word3_muladd(&w2, &w1, &w0, ws[18], p[11]); word3_muladd(&w2, &w1, &w0, ws[19], p[10]); word3_muladd(&w2, &w1, &w0, ws[20], p[9]); word3_muladd(&w2, &w1, &w0, ws[21], p[8]); word3_muladd(&w2, &w1, &w0, ws[22], p[7]); word3_muladd(&w2, &w1, &w0, ws[23], p[6]); word3_add(&w2, &w1, &w0, z[29]); ws[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[7], p[23]); word3_muladd(&w2, &w1, &w0, ws[8], p[22]); word3_muladd(&w2, &w1, &w0, ws[9], p[21]); word3_muladd(&w2, &w1, &w0, ws[10], p[20]); word3_muladd(&w2, &w1, &w0, ws[11], p[19]); word3_muladd(&w2, &w1, &w0, ws[12], p[18]); word3_muladd(&w2, &w1, &w0, ws[13], p[17]); word3_muladd(&w2, &w1, &w0, ws[14], p[16]); word3_muladd(&w2, &w1, &w0, ws[15], p[15]); word3_muladd(&w2, &w1, &w0, ws[16], p[14]); word3_muladd(&w2, &w1, &w0, ws[17], p[13]); word3_muladd(&w2, &w1, &w0, ws[18], p[12]); word3_muladd(&w2, &w1, &w0, ws[19], p[11]); word3_muladd(&w2, &w1, &w0, ws[20], p[10]); word3_muladd(&w2, &w1, &w0, ws[21], p[9]); word3_muladd(&w2, &w1, &w0, ws[22], p[8]); word3_muladd(&w2, &w1, &w0, ws[23], p[7]); word3_add(&w2, &w1, &w0, z[30]); ws[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[8], p[23]); word3_muladd(&w2, &w1, &w0, ws[9], p[22]); word3_muladd(&w2, &w1, &w0, ws[10], p[21]); word3_muladd(&w2, &w1, &w0, ws[11], p[20]); word3_muladd(&w2, &w1, &w0, ws[12], p[19]); word3_muladd(&w2, &w1, &w0, ws[13], p[18]); word3_muladd(&w2, &w1, &w0, ws[14], p[17]); word3_muladd(&w2, &w1, &w0, ws[15], p[16]); word3_muladd(&w2, &w1, &w0, ws[16], p[15]); word3_muladd(&w2, &w1, &w0, ws[17], p[14]); word3_muladd(&w2, &w1, &w0, ws[18], p[13]); word3_muladd(&w2, &w1, &w0, ws[19], p[12]); word3_muladd(&w2, &w1, &w0, ws[20], p[11]); word3_muladd(&w2, &w1, &w0, ws[21], p[10]); word3_muladd(&w2, &w1, &w0, ws[22], p[9]); word3_muladd(&w2, &w1, &w0, ws[23], p[8]); word3_add(&w2, &w1, &w0, z[31]); ws[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[9], p[23]); word3_muladd(&w2, &w1, &w0, ws[10], p[22]); word3_muladd(&w2, &w1, &w0, ws[11], p[21]); word3_muladd(&w2, &w1, &w0, ws[12], p[20]); word3_muladd(&w2, &w1, &w0, ws[13], p[19]); word3_muladd(&w2, &w1, &w0, ws[14], p[18]); word3_muladd(&w2, &w1, &w0, ws[15], p[17]); word3_muladd(&w2, &w1, &w0, ws[16], p[16]); word3_muladd(&w2, &w1, &w0, ws[17], p[15]); word3_muladd(&w2, &w1, &w0, ws[18], p[14]); word3_muladd(&w2, &w1, &w0, ws[19], p[13]); word3_muladd(&w2, &w1, &w0, ws[20], p[12]); word3_muladd(&w2, &w1, &w0, ws[21], p[11]); word3_muladd(&w2, &w1, &w0, ws[22], p[10]); word3_muladd(&w2, &w1, &w0, ws[23], p[9]); word3_add(&w2, &w1, &w0, z[32]); ws[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[10], p[23]); word3_muladd(&w2, &w1, &w0, ws[11], p[22]); word3_muladd(&w2, &w1, &w0, ws[12], p[21]); word3_muladd(&w2, &w1, &w0, ws[13], p[20]); word3_muladd(&w2, &w1, &w0, ws[14], p[19]); word3_muladd(&w2, &w1, &w0, ws[15], p[18]); word3_muladd(&w2, &w1, &w0, ws[16], p[17]); word3_muladd(&w2, &w1, &w0, ws[17], p[16]); word3_muladd(&w2, &w1, &w0, ws[18], p[15]); word3_muladd(&w2, &w1, &w0, ws[19], p[14]); word3_muladd(&w2, &w1, &w0, ws[20], p[13]); word3_muladd(&w2, &w1, &w0, ws[21], p[12]); word3_muladd(&w2, &w1, &w0, ws[22], p[11]); word3_muladd(&w2, &w1, &w0, ws[23], p[10]); word3_add(&w2, &w1, &w0, z[33]); ws[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[11], p[23]); word3_muladd(&w2, &w1, &w0, ws[12], p[22]); word3_muladd(&w2, &w1, &w0, ws[13], p[21]); word3_muladd(&w2, &w1, &w0, ws[14], p[20]); word3_muladd(&w2, &w1, &w0, ws[15], p[19]); word3_muladd(&w2, &w1, &w0, ws[16], p[18]); word3_muladd(&w2, &w1, &w0, ws[17], p[17]); word3_muladd(&w2, &w1, &w0, ws[18], p[16]); word3_muladd(&w2, &w1, &w0, ws[19], p[15]); word3_muladd(&w2, &w1, &w0, ws[20], p[14]); word3_muladd(&w2, &w1, &w0, ws[21], p[13]); word3_muladd(&w2, &w1, &w0, ws[22], p[12]); word3_muladd(&w2, &w1, &w0, ws[23], p[11]); word3_add(&w2, &w1, &w0, z[34]); ws[10] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[12], p[23]); word3_muladd(&w2, &w1, &w0, ws[13], p[22]); word3_muladd(&w2, &w1, &w0, ws[14], p[21]); word3_muladd(&w2, &w1, &w0, ws[15], p[20]); word3_muladd(&w2, &w1, &w0, ws[16], p[19]); word3_muladd(&w2, &w1, &w0, ws[17], p[18]); word3_muladd(&w2, &w1, &w0, ws[18], p[17]); word3_muladd(&w2, &w1, &w0, ws[19], p[16]); word3_muladd(&w2, &w1, &w0, ws[20], p[15]); word3_muladd(&w2, &w1, &w0, ws[21], p[14]); word3_muladd(&w2, &w1, &w0, ws[22], p[13]); word3_muladd(&w2, &w1, &w0, ws[23], p[12]); word3_add(&w2, &w1, &w0, z[35]); ws[11] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[13], p[23]); word3_muladd(&w2, &w1, &w0, ws[14], p[22]); word3_muladd(&w2, &w1, &w0, ws[15], p[21]); word3_muladd(&w2, &w1, &w0, ws[16], p[20]); word3_muladd(&w2, &w1, &w0, ws[17], p[19]); word3_muladd(&w2, &w1, &w0, ws[18], p[18]); word3_muladd(&w2, &w1, &w0, ws[19], p[17]); word3_muladd(&w2, &w1, &w0, ws[20], p[16]); word3_muladd(&w2, &w1, &w0, ws[21], p[15]); word3_muladd(&w2, &w1, &w0, ws[22], p[14]); word3_muladd(&w2, &w1, &w0, ws[23], p[13]); word3_add(&w2, &w1, &w0, z[36]); ws[12] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[14], p[23]); word3_muladd(&w2, &w1, &w0, ws[15], p[22]); word3_muladd(&w2, &w1, &w0, ws[16], p[21]); word3_muladd(&w2, &w1, &w0, ws[17], p[20]); word3_muladd(&w2, &w1, &w0, ws[18], p[19]); word3_muladd(&w2, &w1, &w0, ws[19], p[18]); word3_muladd(&w2, &w1, &w0, ws[20], p[17]); word3_muladd(&w2, &w1, &w0, ws[21], p[16]); word3_muladd(&w2, &w1, &w0, ws[22], p[15]); word3_muladd(&w2, &w1, &w0, ws[23], p[14]); word3_add(&w2, &w1, &w0, z[37]); ws[13] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[15], p[23]); word3_muladd(&w2, &w1, &w0, ws[16], p[22]); word3_muladd(&w2, &w1, &w0, ws[17], p[21]); word3_muladd(&w2, &w1, &w0, ws[18], p[20]); word3_muladd(&w2, &w1, &w0, ws[19], p[19]); word3_muladd(&w2, &w1, &w0, ws[20], p[18]); word3_muladd(&w2, &w1, &w0, ws[21], p[17]); word3_muladd(&w2, &w1, &w0, ws[22], p[16]); word3_muladd(&w2, &w1, &w0, ws[23], p[15]); word3_add(&w2, &w1, &w0, z[38]); ws[14] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[16], p[23]); word3_muladd(&w2, &w1, &w0, ws[17], p[22]); word3_muladd(&w2, &w1, &w0, ws[18], p[21]); word3_muladd(&w2, &w1, &w0, ws[19], p[20]); word3_muladd(&w2, &w1, &w0, ws[20], p[19]); word3_muladd(&w2, &w1, &w0, ws[21], p[18]); word3_muladd(&w2, &w1, &w0, ws[22], p[17]); word3_muladd(&w2, &w1, &w0, ws[23], p[16]); word3_add(&w2, &w1, &w0, z[39]); ws[15] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[17], p[23]); word3_muladd(&w2, &w1, &w0, ws[18], p[22]); word3_muladd(&w2, &w1, &w0, ws[19], p[21]); word3_muladd(&w2, &w1, &w0, ws[20], p[20]); word3_muladd(&w2, &w1, &w0, ws[21], p[19]); word3_muladd(&w2, &w1, &w0, ws[22], p[18]); word3_muladd(&w2, &w1, &w0, ws[23], p[17]); word3_add(&w2, &w1, &w0, z[40]); ws[16] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[18], p[23]); word3_muladd(&w2, &w1, &w0, ws[19], p[22]); word3_muladd(&w2, &w1, &w0, ws[20], p[21]); word3_muladd(&w2, &w1, &w0, ws[21], p[20]); word3_muladd(&w2, &w1, &w0, ws[22], p[19]); word3_muladd(&w2, &w1, &w0, ws[23], p[18]); word3_add(&w2, &w1, &w0, z[41]); ws[17] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[19], p[23]); word3_muladd(&w2, &w1, &w0, ws[20], p[22]); word3_muladd(&w2, &w1, &w0, ws[21], p[21]); word3_muladd(&w2, &w1, &w0, ws[22], p[20]); word3_muladd(&w2, &w1, &w0, ws[23], p[19]); word3_add(&w2, &w1, &w0, z[42]); ws[18] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[20], p[23]); word3_muladd(&w2, &w1, &w0, ws[21], p[22]); word3_muladd(&w2, &w1, &w0, ws[22], p[21]); word3_muladd(&w2, &w1, &w0, ws[23], p[20]); word3_add(&w2, &w1, &w0, z[43]); ws[19] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[21], p[23]); word3_muladd(&w2, &w1, &w0, ws[22], p[22]); word3_muladd(&w2, &w1, &w0, ws[23], p[21]); word3_add(&w2, &w1, &w0, z[44]); ws[20] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[22], p[23]); word3_muladd(&w2, &w1, &w0, ws[23], p[22]); word3_add(&w2, &w1, &w0, z[45]); ws[21] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[23], p[23]); word3_add(&w2, &w1, &w0, z[46]); ws[22] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[47]); ws[23] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[49]); ws[24] = w0; ws[25] = w1; word borrow = bigint_sub3(ws + 24 + 1, ws, 24 + 1, p, 24); CT::conditional_copy_mem(borrow, z, ws, ws + 25, 25); clear_mem(z + 24, 2*(24+1) - 24); } void bigint_monty_redc_32(word z[], const word p[32], word p_dash, word ws[]) { word w2 = 0, w1 = 0, w0 = 0; w0 = z[0]; ws[0] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[0], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[1]); word3_add(&w2, &w1, &w0, z[1]); ws[1] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[1], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[2]); word3_muladd(&w2, &w1, &w0, ws[1], p[1]); word3_add(&w2, &w1, &w0, z[2]); ws[2] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[2], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[3]); word3_muladd(&w2, &w1, &w0, ws[1], p[2]); word3_muladd(&w2, &w1, &w0, ws[2], p[1]); word3_add(&w2, &w1, &w0, z[3]); ws[3] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[3], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[4]); word3_muladd(&w2, &w1, &w0, ws[1], p[3]); word3_muladd(&w2, &w1, &w0, ws[2], p[2]); word3_muladd(&w2, &w1, &w0, ws[3], p[1]); word3_add(&w2, &w1, &w0, z[4]); ws[4] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[4], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[5]); word3_muladd(&w2, &w1, &w0, ws[1], p[4]); word3_muladd(&w2, &w1, &w0, ws[2], p[3]); word3_muladd(&w2, &w1, &w0, ws[3], p[2]); word3_muladd(&w2, &w1, &w0, ws[4], p[1]); word3_add(&w2, &w1, &w0, z[5]); ws[5] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[5], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[6]); word3_muladd(&w2, &w1, &w0, ws[1], p[5]); word3_muladd(&w2, &w1, &w0, ws[2], p[4]); word3_muladd(&w2, &w1, &w0, ws[3], p[3]); word3_muladd(&w2, &w1, &w0, ws[4], p[2]); word3_muladd(&w2, &w1, &w0, ws[5], p[1]); word3_add(&w2, &w1, &w0, z[6]); ws[6] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[6], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[7]); word3_muladd(&w2, &w1, &w0, ws[1], p[6]); word3_muladd(&w2, &w1, &w0, ws[2], p[5]); word3_muladd(&w2, &w1, &w0, ws[3], p[4]); word3_muladd(&w2, &w1, &w0, ws[4], p[3]); word3_muladd(&w2, &w1, &w0, ws[5], p[2]); word3_muladd(&w2, &w1, &w0, ws[6], p[1]); word3_add(&w2, &w1, &w0, z[7]); ws[7] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[7], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[8]); word3_muladd(&w2, &w1, &w0, ws[1], p[7]); word3_muladd(&w2, &w1, &w0, ws[2], p[6]); word3_muladd(&w2, &w1, &w0, ws[3], p[5]); word3_muladd(&w2, &w1, &w0, ws[4], p[4]); word3_muladd(&w2, &w1, &w0, ws[5], p[3]); word3_muladd(&w2, &w1, &w0, ws[6], p[2]); word3_muladd(&w2, &w1, &w0, ws[7], p[1]); word3_add(&w2, &w1, &w0, z[8]); ws[8] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[8], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[9]); word3_muladd(&w2, &w1, &w0, ws[1], p[8]); word3_muladd(&w2, &w1, &w0, ws[2], p[7]); word3_muladd(&w2, &w1, &w0, ws[3], p[6]); word3_muladd(&w2, &w1, &w0, ws[4], p[5]); word3_muladd(&w2, &w1, &w0, ws[5], p[4]); word3_muladd(&w2, &w1, &w0, ws[6], p[3]); word3_muladd(&w2, &w1, &w0, ws[7], p[2]); word3_muladd(&w2, &w1, &w0, ws[8], p[1]); word3_add(&w2, &w1, &w0, z[9]); ws[9] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[9], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[10]); word3_muladd(&w2, &w1, &w0, ws[1], p[9]); word3_muladd(&w2, &w1, &w0, ws[2], p[8]); word3_muladd(&w2, &w1, &w0, ws[3], p[7]); word3_muladd(&w2, &w1, &w0, ws[4], p[6]); word3_muladd(&w2, &w1, &w0, ws[5], p[5]); word3_muladd(&w2, &w1, &w0, ws[6], p[4]); word3_muladd(&w2, &w1, &w0, ws[7], p[3]); word3_muladd(&w2, &w1, &w0, ws[8], p[2]); word3_muladd(&w2, &w1, &w0, ws[9], p[1]); word3_add(&w2, &w1, &w0, z[10]); ws[10] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[10], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[11]); word3_muladd(&w2, &w1, &w0, ws[1], p[10]); word3_muladd(&w2, &w1, &w0, ws[2], p[9]); word3_muladd(&w2, &w1, &w0, ws[3], p[8]); word3_muladd(&w2, &w1, &w0, ws[4], p[7]); word3_muladd(&w2, &w1, &w0, ws[5], p[6]); word3_muladd(&w2, &w1, &w0, ws[6], p[5]); word3_muladd(&w2, &w1, &w0, ws[7], p[4]); word3_muladd(&w2, &w1, &w0, ws[8], p[3]); word3_muladd(&w2, &w1, &w0, ws[9], p[2]); word3_muladd(&w2, &w1, &w0, ws[10], p[1]); word3_add(&w2, &w1, &w0, z[11]); ws[11] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[11], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[12]); word3_muladd(&w2, &w1, &w0, ws[1], p[11]); word3_muladd(&w2, &w1, &w0, ws[2], p[10]); word3_muladd(&w2, &w1, &w0, ws[3], p[9]); word3_muladd(&w2, &w1, &w0, ws[4], p[8]); word3_muladd(&w2, &w1, &w0, ws[5], p[7]); word3_muladd(&w2, &w1, &w0, ws[6], p[6]); word3_muladd(&w2, &w1, &w0, ws[7], p[5]); word3_muladd(&w2, &w1, &w0, ws[8], p[4]); word3_muladd(&w2, &w1, &w0, ws[9], p[3]); word3_muladd(&w2, &w1, &w0, ws[10], p[2]); word3_muladd(&w2, &w1, &w0, ws[11], p[1]); word3_add(&w2, &w1, &w0, z[12]); ws[12] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[12], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[13]); word3_muladd(&w2, &w1, &w0, ws[1], p[12]); word3_muladd(&w2, &w1, &w0, ws[2], p[11]); word3_muladd(&w2, &w1, &w0, ws[3], p[10]); word3_muladd(&w2, &w1, &w0, ws[4], p[9]); word3_muladd(&w2, &w1, &w0, ws[5], p[8]); word3_muladd(&w2, &w1, &w0, ws[6], p[7]); word3_muladd(&w2, &w1, &w0, ws[7], p[6]); word3_muladd(&w2, &w1, &w0, ws[8], p[5]); word3_muladd(&w2, &w1, &w0, ws[9], p[4]); word3_muladd(&w2, &w1, &w0, ws[10], p[3]); word3_muladd(&w2, &w1, &w0, ws[11], p[2]); word3_muladd(&w2, &w1, &w0, ws[12], p[1]); word3_add(&w2, &w1, &w0, z[13]); ws[13] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[13], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[14]); word3_muladd(&w2, &w1, &w0, ws[1], p[13]); word3_muladd(&w2, &w1, &w0, ws[2], p[12]); word3_muladd(&w2, &w1, &w0, ws[3], p[11]); word3_muladd(&w2, &w1, &w0, ws[4], p[10]); word3_muladd(&w2, &w1, &w0, ws[5], p[9]); word3_muladd(&w2, &w1, &w0, ws[6], p[8]); word3_muladd(&w2, &w1, &w0, ws[7], p[7]); word3_muladd(&w2, &w1, &w0, ws[8], p[6]); word3_muladd(&w2, &w1, &w0, ws[9], p[5]); word3_muladd(&w2, &w1, &w0, ws[10], p[4]); word3_muladd(&w2, &w1, &w0, ws[11], p[3]); word3_muladd(&w2, &w1, &w0, ws[12], p[2]); word3_muladd(&w2, &w1, &w0, ws[13], p[1]); word3_add(&w2, &w1, &w0, z[14]); ws[14] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[14], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[15]); word3_muladd(&w2, &w1, &w0, ws[1], p[14]); word3_muladd(&w2, &w1, &w0, ws[2], p[13]); word3_muladd(&w2, &w1, &w0, ws[3], p[12]); word3_muladd(&w2, &w1, &w0, ws[4], p[11]); word3_muladd(&w2, &w1, &w0, ws[5], p[10]); word3_muladd(&w2, &w1, &w0, ws[6], p[9]); word3_muladd(&w2, &w1, &w0, ws[7], p[8]); word3_muladd(&w2, &w1, &w0, ws[8], p[7]); word3_muladd(&w2, &w1, &w0, ws[9], p[6]); word3_muladd(&w2, &w1, &w0, ws[10], p[5]); word3_muladd(&w2, &w1, &w0, ws[11], p[4]); word3_muladd(&w2, &w1, &w0, ws[12], p[3]); word3_muladd(&w2, &w1, &w0, ws[13], p[2]); word3_muladd(&w2, &w1, &w0, ws[14], p[1]); word3_add(&w2, &w1, &w0, z[15]); ws[15] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[15], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[16]); word3_muladd(&w2, &w1, &w0, ws[1], p[15]); word3_muladd(&w2, &w1, &w0, ws[2], p[14]); word3_muladd(&w2, &w1, &w0, ws[3], p[13]); word3_muladd(&w2, &w1, &w0, ws[4], p[12]); word3_muladd(&w2, &w1, &w0, ws[5], p[11]); word3_muladd(&w2, &w1, &w0, ws[6], p[10]); word3_muladd(&w2, &w1, &w0, ws[7], p[9]); word3_muladd(&w2, &w1, &w0, ws[8], p[8]); word3_muladd(&w2, &w1, &w0, ws[9], p[7]); word3_muladd(&w2, &w1, &w0, ws[10], p[6]); word3_muladd(&w2, &w1, &w0, ws[11], p[5]); word3_muladd(&w2, &w1, &w0, ws[12], p[4]); word3_muladd(&w2, &w1, &w0, ws[13], p[3]); word3_muladd(&w2, &w1, &w0, ws[14], p[2]); word3_muladd(&w2, &w1, &w0, ws[15], p[1]); word3_add(&w2, &w1, &w0, z[16]); ws[16] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[16], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[17]); word3_muladd(&w2, &w1, &w0, ws[1], p[16]); word3_muladd(&w2, &w1, &w0, ws[2], p[15]); word3_muladd(&w2, &w1, &w0, ws[3], p[14]); word3_muladd(&w2, &w1, &w0, ws[4], p[13]); word3_muladd(&w2, &w1, &w0, ws[5], p[12]); word3_muladd(&w2, &w1, &w0, ws[6], p[11]); word3_muladd(&w2, &w1, &w0, ws[7], p[10]); word3_muladd(&w2, &w1, &w0, ws[8], p[9]); word3_muladd(&w2, &w1, &w0, ws[9], p[8]); word3_muladd(&w2, &w1, &w0, ws[10], p[7]); word3_muladd(&w2, &w1, &w0, ws[11], p[6]); word3_muladd(&w2, &w1, &w0, ws[12], p[5]); word3_muladd(&w2, &w1, &w0, ws[13], p[4]); word3_muladd(&w2, &w1, &w0, ws[14], p[3]); word3_muladd(&w2, &w1, &w0, ws[15], p[2]); word3_muladd(&w2, &w1, &w0, ws[16], p[1]); word3_add(&w2, &w1, &w0, z[17]); ws[17] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[17], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[18]); word3_muladd(&w2, &w1, &w0, ws[1], p[17]); word3_muladd(&w2, &w1, &w0, ws[2], p[16]); word3_muladd(&w2, &w1, &w0, ws[3], p[15]); word3_muladd(&w2, &w1, &w0, ws[4], p[14]); word3_muladd(&w2, &w1, &w0, ws[5], p[13]); word3_muladd(&w2, &w1, &w0, ws[6], p[12]); word3_muladd(&w2, &w1, &w0, ws[7], p[11]); word3_muladd(&w2, &w1, &w0, ws[8], p[10]); word3_muladd(&w2, &w1, &w0, ws[9], p[9]); word3_muladd(&w2, &w1, &w0, ws[10], p[8]); word3_muladd(&w2, &w1, &w0, ws[11], p[7]); word3_muladd(&w2, &w1, &w0, ws[12], p[6]); word3_muladd(&w2, &w1, &w0, ws[13], p[5]); word3_muladd(&w2, &w1, &w0, ws[14], p[4]); word3_muladd(&w2, &w1, &w0, ws[15], p[3]); word3_muladd(&w2, &w1, &w0, ws[16], p[2]); word3_muladd(&w2, &w1, &w0, ws[17], p[1]); word3_add(&w2, &w1, &w0, z[18]); ws[18] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[18], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[19]); word3_muladd(&w2, &w1, &w0, ws[1], p[18]); word3_muladd(&w2, &w1, &w0, ws[2], p[17]); word3_muladd(&w2, &w1, &w0, ws[3], p[16]); word3_muladd(&w2, &w1, &w0, ws[4], p[15]); word3_muladd(&w2, &w1, &w0, ws[5], p[14]); word3_muladd(&w2, &w1, &w0, ws[6], p[13]); word3_muladd(&w2, &w1, &w0, ws[7], p[12]); word3_muladd(&w2, &w1, &w0, ws[8], p[11]); word3_muladd(&w2, &w1, &w0, ws[9], p[10]); word3_muladd(&w2, &w1, &w0, ws[10], p[9]); word3_muladd(&w2, &w1, &w0, ws[11], p[8]); word3_muladd(&w2, &w1, &w0, ws[12], p[7]); word3_muladd(&w2, &w1, &w0, ws[13], p[6]); word3_muladd(&w2, &w1, &w0, ws[14], p[5]); word3_muladd(&w2, &w1, &w0, ws[15], p[4]); word3_muladd(&w2, &w1, &w0, ws[16], p[3]); word3_muladd(&w2, &w1, &w0, ws[17], p[2]); word3_muladd(&w2, &w1, &w0, ws[18], p[1]); word3_add(&w2, &w1, &w0, z[19]); ws[19] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[19], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[20]); word3_muladd(&w2, &w1, &w0, ws[1], p[19]); word3_muladd(&w2, &w1, &w0, ws[2], p[18]); word3_muladd(&w2, &w1, &w0, ws[3], p[17]); word3_muladd(&w2, &w1, &w0, ws[4], p[16]); word3_muladd(&w2, &w1, &w0, ws[5], p[15]); word3_muladd(&w2, &w1, &w0, ws[6], p[14]); word3_muladd(&w2, &w1, &w0, ws[7], p[13]); word3_muladd(&w2, &w1, &w0, ws[8], p[12]); word3_muladd(&w2, &w1, &w0, ws[9], p[11]); word3_muladd(&w2, &w1, &w0, ws[10], p[10]); word3_muladd(&w2, &w1, &w0, ws[11], p[9]); word3_muladd(&w2, &w1, &w0, ws[12], p[8]); word3_muladd(&w2, &w1, &w0, ws[13], p[7]); word3_muladd(&w2, &w1, &w0, ws[14], p[6]); word3_muladd(&w2, &w1, &w0, ws[15], p[5]); word3_muladd(&w2, &w1, &w0, ws[16], p[4]); word3_muladd(&w2, &w1, &w0, ws[17], p[3]); word3_muladd(&w2, &w1, &w0, ws[18], p[2]); word3_muladd(&w2, &w1, &w0, ws[19], p[1]); word3_add(&w2, &w1, &w0, z[20]); ws[20] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[20], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[21]); word3_muladd(&w2, &w1, &w0, ws[1], p[20]); word3_muladd(&w2, &w1, &w0, ws[2], p[19]); word3_muladd(&w2, &w1, &w0, ws[3], p[18]); word3_muladd(&w2, &w1, &w0, ws[4], p[17]); word3_muladd(&w2, &w1, &w0, ws[5], p[16]); word3_muladd(&w2, &w1, &w0, ws[6], p[15]); word3_muladd(&w2, &w1, &w0, ws[7], p[14]); word3_muladd(&w2, &w1, &w0, ws[8], p[13]); word3_muladd(&w2, &w1, &w0, ws[9], p[12]); word3_muladd(&w2, &w1, &w0, ws[10], p[11]); word3_muladd(&w2, &w1, &w0, ws[11], p[10]); word3_muladd(&w2, &w1, &w0, ws[12], p[9]); word3_muladd(&w2, &w1, &w0, ws[13], p[8]); word3_muladd(&w2, &w1, &w0, ws[14], p[7]); word3_muladd(&w2, &w1, &w0, ws[15], p[6]); word3_muladd(&w2, &w1, &w0, ws[16], p[5]); word3_muladd(&w2, &w1, &w0, ws[17], p[4]); word3_muladd(&w2, &w1, &w0, ws[18], p[3]); word3_muladd(&w2, &w1, &w0, ws[19], p[2]); word3_muladd(&w2, &w1, &w0, ws[20], p[1]); word3_add(&w2, &w1, &w0, z[21]); ws[21] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[21], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[22]); word3_muladd(&w2, &w1, &w0, ws[1], p[21]); word3_muladd(&w2, &w1, &w0, ws[2], p[20]); word3_muladd(&w2, &w1, &w0, ws[3], p[19]); word3_muladd(&w2, &w1, &w0, ws[4], p[18]); word3_muladd(&w2, &w1, &w0, ws[5], p[17]); word3_muladd(&w2, &w1, &w0, ws[6], p[16]); word3_muladd(&w2, &w1, &w0, ws[7], p[15]); word3_muladd(&w2, &w1, &w0, ws[8], p[14]); word3_muladd(&w2, &w1, &w0, ws[9], p[13]); word3_muladd(&w2, &w1, &w0, ws[10], p[12]); word3_muladd(&w2, &w1, &w0, ws[11], p[11]); word3_muladd(&w2, &w1, &w0, ws[12], p[10]); word3_muladd(&w2, &w1, &w0, ws[13], p[9]); word3_muladd(&w2, &w1, &w0, ws[14], p[8]); word3_muladd(&w2, &w1, &w0, ws[15], p[7]); word3_muladd(&w2, &w1, &w0, ws[16], p[6]); word3_muladd(&w2, &w1, &w0, ws[17], p[5]); word3_muladd(&w2, &w1, &w0, ws[18], p[4]); word3_muladd(&w2, &w1, &w0, ws[19], p[3]); word3_muladd(&w2, &w1, &w0, ws[20], p[2]); word3_muladd(&w2, &w1, &w0, ws[21], p[1]); word3_add(&w2, &w1, &w0, z[22]); ws[22] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[22], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[23]); word3_muladd(&w2, &w1, &w0, ws[1], p[22]); word3_muladd(&w2, &w1, &w0, ws[2], p[21]); word3_muladd(&w2, &w1, &w0, ws[3], p[20]); word3_muladd(&w2, &w1, &w0, ws[4], p[19]); word3_muladd(&w2, &w1, &w0, ws[5], p[18]); word3_muladd(&w2, &w1, &w0, ws[6], p[17]); word3_muladd(&w2, &w1, &w0, ws[7], p[16]); word3_muladd(&w2, &w1, &w0, ws[8], p[15]); word3_muladd(&w2, &w1, &w0, ws[9], p[14]); word3_muladd(&w2, &w1, &w0, ws[10], p[13]); word3_muladd(&w2, &w1, &w0, ws[11], p[12]); word3_muladd(&w2, &w1, &w0, ws[12], p[11]); word3_muladd(&w2, &w1, &w0, ws[13], p[10]); word3_muladd(&w2, &w1, &w0, ws[14], p[9]); word3_muladd(&w2, &w1, &w0, ws[15], p[8]); word3_muladd(&w2, &w1, &w0, ws[16], p[7]); word3_muladd(&w2, &w1, &w0, ws[17], p[6]); word3_muladd(&w2, &w1, &w0, ws[18], p[5]); word3_muladd(&w2, &w1, &w0, ws[19], p[4]); word3_muladd(&w2, &w1, &w0, ws[20], p[3]); word3_muladd(&w2, &w1, &w0, ws[21], p[2]); word3_muladd(&w2, &w1, &w0, ws[22], p[1]); word3_add(&w2, &w1, &w0, z[23]); ws[23] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[23], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[24]); word3_muladd(&w2, &w1, &w0, ws[1], p[23]); word3_muladd(&w2, &w1, &w0, ws[2], p[22]); word3_muladd(&w2, &w1, &w0, ws[3], p[21]); word3_muladd(&w2, &w1, &w0, ws[4], p[20]); word3_muladd(&w2, &w1, &w0, ws[5], p[19]); word3_muladd(&w2, &w1, &w0, ws[6], p[18]); word3_muladd(&w2, &w1, &w0, ws[7], p[17]); word3_muladd(&w2, &w1, &w0, ws[8], p[16]); word3_muladd(&w2, &w1, &w0, ws[9], p[15]); word3_muladd(&w2, &w1, &w0, ws[10], p[14]); word3_muladd(&w2, &w1, &w0, ws[11], p[13]); word3_muladd(&w2, &w1, &w0, ws[12], p[12]); word3_muladd(&w2, &w1, &w0, ws[13], p[11]); word3_muladd(&w2, &w1, &w0, ws[14], p[10]); word3_muladd(&w2, &w1, &w0, ws[15], p[9]); word3_muladd(&w2, &w1, &w0, ws[16], p[8]); word3_muladd(&w2, &w1, &w0, ws[17], p[7]); word3_muladd(&w2, &w1, &w0, ws[18], p[6]); word3_muladd(&w2, &w1, &w0, ws[19], p[5]); word3_muladd(&w2, &w1, &w0, ws[20], p[4]); word3_muladd(&w2, &w1, &w0, ws[21], p[3]); word3_muladd(&w2, &w1, &w0, ws[22], p[2]); word3_muladd(&w2, &w1, &w0, ws[23], p[1]); word3_add(&w2, &w1, &w0, z[24]); ws[24] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[24], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[25]); word3_muladd(&w2, &w1, &w0, ws[1], p[24]); word3_muladd(&w2, &w1, &w0, ws[2], p[23]); word3_muladd(&w2, &w1, &w0, ws[3], p[22]); word3_muladd(&w2, &w1, &w0, ws[4], p[21]); word3_muladd(&w2, &w1, &w0, ws[5], p[20]); word3_muladd(&w2, &w1, &w0, ws[6], p[19]); word3_muladd(&w2, &w1, &w0, ws[7], p[18]); word3_muladd(&w2, &w1, &w0, ws[8], p[17]); word3_muladd(&w2, &w1, &w0, ws[9], p[16]); word3_muladd(&w2, &w1, &w0, ws[10], p[15]); word3_muladd(&w2, &w1, &w0, ws[11], p[14]); word3_muladd(&w2, &w1, &w0, ws[12], p[13]); word3_muladd(&w2, &w1, &w0, ws[13], p[12]); word3_muladd(&w2, &w1, &w0, ws[14], p[11]); word3_muladd(&w2, &w1, &w0, ws[15], p[10]); word3_muladd(&w2, &w1, &w0, ws[16], p[9]); word3_muladd(&w2, &w1, &w0, ws[17], p[8]); word3_muladd(&w2, &w1, &w0, ws[18], p[7]); word3_muladd(&w2, &w1, &w0, ws[19], p[6]); word3_muladd(&w2, &w1, &w0, ws[20], p[5]); word3_muladd(&w2, &w1, &w0, ws[21], p[4]); word3_muladd(&w2, &w1, &w0, ws[22], p[3]); word3_muladd(&w2, &w1, &w0, ws[23], p[2]); word3_muladd(&w2, &w1, &w0, ws[24], p[1]); word3_add(&w2, &w1, &w0, z[25]); ws[25] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[25], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[26]); word3_muladd(&w2, &w1, &w0, ws[1], p[25]); word3_muladd(&w2, &w1, &w0, ws[2], p[24]); word3_muladd(&w2, &w1, &w0, ws[3], p[23]); word3_muladd(&w2, &w1, &w0, ws[4], p[22]); word3_muladd(&w2, &w1, &w0, ws[5], p[21]); word3_muladd(&w2, &w1, &w0, ws[6], p[20]); word3_muladd(&w2, &w1, &w0, ws[7], p[19]); word3_muladd(&w2, &w1, &w0, ws[8], p[18]); word3_muladd(&w2, &w1, &w0, ws[9], p[17]); word3_muladd(&w2, &w1, &w0, ws[10], p[16]); word3_muladd(&w2, &w1, &w0, ws[11], p[15]); word3_muladd(&w2, &w1, &w0, ws[12], p[14]); word3_muladd(&w2, &w1, &w0, ws[13], p[13]); word3_muladd(&w2, &w1, &w0, ws[14], p[12]); word3_muladd(&w2, &w1, &w0, ws[15], p[11]); word3_muladd(&w2, &w1, &w0, ws[16], p[10]); word3_muladd(&w2, &w1, &w0, ws[17], p[9]); word3_muladd(&w2, &w1, &w0, ws[18], p[8]); word3_muladd(&w2, &w1, &w0, ws[19], p[7]); word3_muladd(&w2, &w1, &w0, ws[20], p[6]); word3_muladd(&w2, &w1, &w0, ws[21], p[5]); word3_muladd(&w2, &w1, &w0, ws[22], p[4]); word3_muladd(&w2, &w1, &w0, ws[23], p[3]); word3_muladd(&w2, &w1, &w0, ws[24], p[2]); word3_muladd(&w2, &w1, &w0, ws[25], p[1]); word3_add(&w2, &w1, &w0, z[26]); ws[26] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[26], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[27]); word3_muladd(&w2, &w1, &w0, ws[1], p[26]); word3_muladd(&w2, &w1, &w0, ws[2], p[25]); word3_muladd(&w2, &w1, &w0, ws[3], p[24]); word3_muladd(&w2, &w1, &w0, ws[4], p[23]); word3_muladd(&w2, &w1, &w0, ws[5], p[22]); word3_muladd(&w2, &w1, &w0, ws[6], p[21]); word3_muladd(&w2, &w1, &w0, ws[7], p[20]); word3_muladd(&w2, &w1, &w0, ws[8], p[19]); word3_muladd(&w2, &w1, &w0, ws[9], p[18]); word3_muladd(&w2, &w1, &w0, ws[10], p[17]); word3_muladd(&w2, &w1, &w0, ws[11], p[16]); word3_muladd(&w2, &w1, &w0, ws[12], p[15]); word3_muladd(&w2, &w1, &w0, ws[13], p[14]); word3_muladd(&w2, &w1, &w0, ws[14], p[13]); word3_muladd(&w2, &w1, &w0, ws[15], p[12]); word3_muladd(&w2, &w1, &w0, ws[16], p[11]); word3_muladd(&w2, &w1, &w0, ws[17], p[10]); word3_muladd(&w2, &w1, &w0, ws[18], p[9]); word3_muladd(&w2, &w1, &w0, ws[19], p[8]); word3_muladd(&w2, &w1, &w0, ws[20], p[7]); word3_muladd(&w2, &w1, &w0, ws[21], p[6]); word3_muladd(&w2, &w1, &w0, ws[22], p[5]); word3_muladd(&w2, &w1, &w0, ws[23], p[4]); word3_muladd(&w2, &w1, &w0, ws[24], p[3]); word3_muladd(&w2, &w1, &w0, ws[25], p[2]); word3_muladd(&w2, &w1, &w0, ws[26], p[1]); word3_add(&w2, &w1, &w0, z[27]); ws[27] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[27], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[28]); word3_muladd(&w2, &w1, &w0, ws[1], p[27]); word3_muladd(&w2, &w1, &w0, ws[2], p[26]); word3_muladd(&w2, &w1, &w0, ws[3], p[25]); word3_muladd(&w2, &w1, &w0, ws[4], p[24]); word3_muladd(&w2, &w1, &w0, ws[5], p[23]); word3_muladd(&w2, &w1, &w0, ws[6], p[22]); word3_muladd(&w2, &w1, &w0, ws[7], p[21]); word3_muladd(&w2, &w1, &w0, ws[8], p[20]); word3_muladd(&w2, &w1, &w0, ws[9], p[19]); word3_muladd(&w2, &w1, &w0, ws[10], p[18]); word3_muladd(&w2, &w1, &w0, ws[11], p[17]); word3_muladd(&w2, &w1, &w0, ws[12], p[16]); word3_muladd(&w2, &w1, &w0, ws[13], p[15]); word3_muladd(&w2, &w1, &w0, ws[14], p[14]); word3_muladd(&w2, &w1, &w0, ws[15], p[13]); word3_muladd(&w2, &w1, &w0, ws[16], p[12]); word3_muladd(&w2, &w1, &w0, ws[17], p[11]); word3_muladd(&w2, &w1, &w0, ws[18], p[10]); word3_muladd(&w2, &w1, &w0, ws[19], p[9]); word3_muladd(&w2, &w1, &w0, ws[20], p[8]); word3_muladd(&w2, &w1, &w0, ws[21], p[7]); word3_muladd(&w2, &w1, &w0, ws[22], p[6]); word3_muladd(&w2, &w1, &w0, ws[23], p[5]); word3_muladd(&w2, &w1, &w0, ws[24], p[4]); word3_muladd(&w2, &w1, &w0, ws[25], p[3]); word3_muladd(&w2, &w1, &w0, ws[26], p[2]); word3_muladd(&w2, &w1, &w0, ws[27], p[1]); word3_add(&w2, &w1, &w0, z[28]); ws[28] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[28], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[29]); word3_muladd(&w2, &w1, &w0, ws[1], p[28]); word3_muladd(&w2, &w1, &w0, ws[2], p[27]); word3_muladd(&w2, &w1, &w0, ws[3], p[26]); word3_muladd(&w2, &w1, &w0, ws[4], p[25]); word3_muladd(&w2, &w1, &w0, ws[5], p[24]); word3_muladd(&w2, &w1, &w0, ws[6], p[23]); word3_muladd(&w2, &w1, &w0, ws[7], p[22]); word3_muladd(&w2, &w1, &w0, ws[8], p[21]); word3_muladd(&w2, &w1, &w0, ws[9], p[20]); word3_muladd(&w2, &w1, &w0, ws[10], p[19]); word3_muladd(&w2, &w1, &w0, ws[11], p[18]); word3_muladd(&w2, &w1, &w0, ws[12], p[17]); word3_muladd(&w2, &w1, &w0, ws[13], p[16]); word3_muladd(&w2, &w1, &w0, ws[14], p[15]); word3_muladd(&w2, &w1, &w0, ws[15], p[14]); word3_muladd(&w2, &w1, &w0, ws[16], p[13]); word3_muladd(&w2, &w1, &w0, ws[17], p[12]); word3_muladd(&w2, &w1, &w0, ws[18], p[11]); word3_muladd(&w2, &w1, &w0, ws[19], p[10]); word3_muladd(&w2, &w1, &w0, ws[20], p[9]); word3_muladd(&w2, &w1, &w0, ws[21], p[8]); word3_muladd(&w2, &w1, &w0, ws[22], p[7]); word3_muladd(&w2, &w1, &w0, ws[23], p[6]); word3_muladd(&w2, &w1, &w0, ws[24], p[5]); word3_muladd(&w2, &w1, &w0, ws[25], p[4]); word3_muladd(&w2, &w1, &w0, ws[26], p[3]); word3_muladd(&w2, &w1, &w0, ws[27], p[2]); word3_muladd(&w2, &w1, &w0, ws[28], p[1]); word3_add(&w2, &w1, &w0, z[29]); ws[29] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[29], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[30]); word3_muladd(&w2, &w1, &w0, ws[1], p[29]); word3_muladd(&w2, &w1, &w0, ws[2], p[28]); word3_muladd(&w2, &w1, &w0, ws[3], p[27]); word3_muladd(&w2, &w1, &w0, ws[4], p[26]); word3_muladd(&w2, &w1, &w0, ws[5], p[25]); word3_muladd(&w2, &w1, &w0, ws[6], p[24]); word3_muladd(&w2, &w1, &w0, ws[7], p[23]); word3_muladd(&w2, &w1, &w0, ws[8], p[22]); word3_muladd(&w2, &w1, &w0, ws[9], p[21]); word3_muladd(&w2, &w1, &w0, ws[10], p[20]); word3_muladd(&w2, &w1, &w0, ws[11], p[19]); word3_muladd(&w2, &w1, &w0, ws[12], p[18]); word3_muladd(&w2, &w1, &w0, ws[13], p[17]); word3_muladd(&w2, &w1, &w0, ws[14], p[16]); word3_muladd(&w2, &w1, &w0, ws[15], p[15]); word3_muladd(&w2, &w1, &w0, ws[16], p[14]); word3_muladd(&w2, &w1, &w0, ws[17], p[13]); word3_muladd(&w2, &w1, &w0, ws[18], p[12]); word3_muladd(&w2, &w1, &w0, ws[19], p[11]); word3_muladd(&w2, &w1, &w0, ws[20], p[10]); word3_muladd(&w2, &w1, &w0, ws[21], p[9]); word3_muladd(&w2, &w1, &w0, ws[22], p[8]); word3_muladd(&w2, &w1, &w0, ws[23], p[7]); word3_muladd(&w2, &w1, &w0, ws[24], p[6]); word3_muladd(&w2, &w1, &w0, ws[25], p[5]); word3_muladd(&w2, &w1, &w0, ws[26], p[4]); word3_muladd(&w2, &w1, &w0, ws[27], p[3]); word3_muladd(&w2, &w1, &w0, ws[28], p[2]); word3_muladd(&w2, &w1, &w0, ws[29], p[1]); word3_add(&w2, &w1, &w0, z[30]); ws[30] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[30], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[0], p[31]); word3_muladd(&w2, &w1, &w0, ws[1], p[30]); word3_muladd(&w2, &w1, &w0, ws[2], p[29]); word3_muladd(&w2, &w1, &w0, ws[3], p[28]); word3_muladd(&w2, &w1, &w0, ws[4], p[27]); word3_muladd(&w2, &w1, &w0, ws[5], p[26]); word3_muladd(&w2, &w1, &w0, ws[6], p[25]); word3_muladd(&w2, &w1, &w0, ws[7], p[24]); word3_muladd(&w2, &w1, &w0, ws[8], p[23]); word3_muladd(&w2, &w1, &w0, ws[9], p[22]); word3_muladd(&w2, &w1, &w0, ws[10], p[21]); word3_muladd(&w2, &w1, &w0, ws[11], p[20]); word3_muladd(&w2, &w1, &w0, ws[12], p[19]); word3_muladd(&w2, &w1, &w0, ws[13], p[18]); word3_muladd(&w2, &w1, &w0, ws[14], p[17]); word3_muladd(&w2, &w1, &w0, ws[15], p[16]); word3_muladd(&w2, &w1, &w0, ws[16], p[15]); word3_muladd(&w2, &w1, &w0, ws[17], p[14]); word3_muladd(&w2, &w1, &w0, ws[18], p[13]); word3_muladd(&w2, &w1, &w0, ws[19], p[12]); word3_muladd(&w2, &w1, &w0, ws[20], p[11]); word3_muladd(&w2, &w1, &w0, ws[21], p[10]); word3_muladd(&w2, &w1, &w0, ws[22], p[9]); word3_muladd(&w2, &w1, &w0, ws[23], p[8]); word3_muladd(&w2, &w1, &w0, ws[24], p[7]); word3_muladd(&w2, &w1, &w0, ws[25], p[6]); word3_muladd(&w2, &w1, &w0, ws[26], p[5]); word3_muladd(&w2, &w1, &w0, ws[27], p[4]); word3_muladd(&w2, &w1, &w0, ws[28], p[3]); word3_muladd(&w2, &w1, &w0, ws[29], p[2]); word3_muladd(&w2, &w1, &w0, ws[30], p[1]); word3_add(&w2, &w1, &w0, z[31]); ws[31] = w0 * p_dash; word3_muladd(&w2, &w1, &w0, ws[31], p[0]); w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[1], p[31]); word3_muladd(&w2, &w1, &w0, ws[2], p[30]); word3_muladd(&w2, &w1, &w0, ws[3], p[29]); word3_muladd(&w2, &w1, &w0, ws[4], p[28]); word3_muladd(&w2, &w1, &w0, ws[5], p[27]); word3_muladd(&w2, &w1, &w0, ws[6], p[26]); word3_muladd(&w2, &w1, &w0, ws[7], p[25]); word3_muladd(&w2, &w1, &w0, ws[8], p[24]); word3_muladd(&w2, &w1, &w0, ws[9], p[23]); word3_muladd(&w2, &w1, &w0, ws[10], p[22]); word3_muladd(&w2, &w1, &w0, ws[11], p[21]); word3_muladd(&w2, &w1, &w0, ws[12], p[20]); word3_muladd(&w2, &w1, &w0, ws[13], p[19]); word3_muladd(&w2, &w1, &w0, ws[14], p[18]); word3_muladd(&w2, &w1, &w0, ws[15], p[17]); word3_muladd(&w2, &w1, &w0, ws[16], p[16]); word3_muladd(&w2, &w1, &w0, ws[17], p[15]); word3_muladd(&w2, &w1, &w0, ws[18], p[14]); word3_muladd(&w2, &w1, &w0, ws[19], p[13]); word3_muladd(&w2, &w1, &w0, ws[20], p[12]); word3_muladd(&w2, &w1, &w0, ws[21], p[11]); word3_muladd(&w2, &w1, &w0, ws[22], p[10]); word3_muladd(&w2, &w1, &w0, ws[23], p[9]); word3_muladd(&w2, &w1, &w0, ws[24], p[8]); word3_muladd(&w2, &w1, &w0, ws[25], p[7]); word3_muladd(&w2, &w1, &w0, ws[26], p[6]); word3_muladd(&w2, &w1, &w0, ws[27], p[5]); word3_muladd(&w2, &w1, &w0, ws[28], p[4]); word3_muladd(&w2, &w1, &w0, ws[29], p[3]); word3_muladd(&w2, &w1, &w0, ws[30], p[2]); word3_muladd(&w2, &w1, &w0, ws[31], p[1]); word3_add(&w2, &w1, &w0, z[32]); ws[0] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[2], p[31]); word3_muladd(&w2, &w1, &w0, ws[3], p[30]); word3_muladd(&w2, &w1, &w0, ws[4], p[29]); word3_muladd(&w2, &w1, &w0, ws[5], p[28]); word3_muladd(&w2, &w1, &w0, ws[6], p[27]); word3_muladd(&w2, &w1, &w0, ws[7], p[26]); word3_muladd(&w2, &w1, &w0, ws[8], p[25]); word3_muladd(&w2, &w1, &w0, ws[9], p[24]); word3_muladd(&w2, &w1, &w0, ws[10], p[23]); word3_muladd(&w2, &w1, &w0, ws[11], p[22]); word3_muladd(&w2, &w1, &w0, ws[12], p[21]); word3_muladd(&w2, &w1, &w0, ws[13], p[20]); word3_muladd(&w2, &w1, &w0, ws[14], p[19]); word3_muladd(&w2, &w1, &w0, ws[15], p[18]); word3_muladd(&w2, &w1, &w0, ws[16], p[17]); word3_muladd(&w2, &w1, &w0, ws[17], p[16]); word3_muladd(&w2, &w1, &w0, ws[18], p[15]); word3_muladd(&w2, &w1, &w0, ws[19], p[14]); word3_muladd(&w2, &w1, &w0, ws[20], p[13]); word3_muladd(&w2, &w1, &w0, ws[21], p[12]); word3_muladd(&w2, &w1, &w0, ws[22], p[11]); word3_muladd(&w2, &w1, &w0, ws[23], p[10]); word3_muladd(&w2, &w1, &w0, ws[24], p[9]); word3_muladd(&w2, &w1, &w0, ws[25], p[8]); word3_muladd(&w2, &w1, &w0, ws[26], p[7]); word3_muladd(&w2, &w1, &w0, ws[27], p[6]); word3_muladd(&w2, &w1, &w0, ws[28], p[5]); word3_muladd(&w2, &w1, &w0, ws[29], p[4]); word3_muladd(&w2, &w1, &w0, ws[30], p[3]); word3_muladd(&w2, &w1, &w0, ws[31], p[2]); word3_add(&w2, &w1, &w0, z[33]); ws[1] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[3], p[31]); word3_muladd(&w2, &w1, &w0, ws[4], p[30]); word3_muladd(&w2, &w1, &w0, ws[5], p[29]); word3_muladd(&w2, &w1, &w0, ws[6], p[28]); word3_muladd(&w2, &w1, &w0, ws[7], p[27]); word3_muladd(&w2, &w1, &w0, ws[8], p[26]); word3_muladd(&w2, &w1, &w0, ws[9], p[25]); word3_muladd(&w2, &w1, &w0, ws[10], p[24]); word3_muladd(&w2, &w1, &w0, ws[11], p[23]); word3_muladd(&w2, &w1, &w0, ws[12], p[22]); word3_muladd(&w2, &w1, &w0, ws[13], p[21]); word3_muladd(&w2, &w1, &w0, ws[14], p[20]); word3_muladd(&w2, &w1, &w0, ws[15], p[19]); word3_muladd(&w2, &w1, &w0, ws[16], p[18]); word3_muladd(&w2, &w1, &w0, ws[17], p[17]); word3_muladd(&w2, &w1, &w0, ws[18], p[16]); word3_muladd(&w2, &w1, &w0, ws[19], p[15]); word3_muladd(&w2, &w1, &w0, ws[20], p[14]); word3_muladd(&w2, &w1, &w0, ws[21], p[13]); word3_muladd(&w2, &w1, &w0, ws[22], p[12]); word3_muladd(&w2, &w1, &w0, ws[23], p[11]); word3_muladd(&w2, &w1, &w0, ws[24], p[10]); word3_muladd(&w2, &w1, &w0, ws[25], p[9]); word3_muladd(&w2, &w1, &w0, ws[26], p[8]); word3_muladd(&w2, &w1, &w0, ws[27], p[7]); word3_muladd(&w2, &w1, &w0, ws[28], p[6]); word3_muladd(&w2, &w1, &w0, ws[29], p[5]); word3_muladd(&w2, &w1, &w0, ws[30], p[4]); word3_muladd(&w2, &w1, &w0, ws[31], p[3]); word3_add(&w2, &w1, &w0, z[34]); ws[2] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[4], p[31]); word3_muladd(&w2, &w1, &w0, ws[5], p[30]); word3_muladd(&w2, &w1, &w0, ws[6], p[29]); word3_muladd(&w2, &w1, &w0, ws[7], p[28]); word3_muladd(&w2, &w1, &w0, ws[8], p[27]); word3_muladd(&w2, &w1, &w0, ws[9], p[26]); word3_muladd(&w2, &w1, &w0, ws[10], p[25]); word3_muladd(&w2, &w1, &w0, ws[11], p[24]); word3_muladd(&w2, &w1, &w0, ws[12], p[23]); word3_muladd(&w2, &w1, &w0, ws[13], p[22]); word3_muladd(&w2, &w1, &w0, ws[14], p[21]); word3_muladd(&w2, &w1, &w0, ws[15], p[20]); word3_muladd(&w2, &w1, &w0, ws[16], p[19]); word3_muladd(&w2, &w1, &w0, ws[17], p[18]); word3_muladd(&w2, &w1, &w0, ws[18], p[17]); word3_muladd(&w2, &w1, &w0, ws[19], p[16]); word3_muladd(&w2, &w1, &w0, ws[20], p[15]); word3_muladd(&w2, &w1, &w0, ws[21], p[14]); word3_muladd(&w2, &w1, &w0, ws[22], p[13]); word3_muladd(&w2, &w1, &w0, ws[23], p[12]); word3_muladd(&w2, &w1, &w0, ws[24], p[11]); word3_muladd(&w2, &w1, &w0, ws[25], p[10]); word3_muladd(&w2, &w1, &w0, ws[26], p[9]); word3_muladd(&w2, &w1, &w0, ws[27], p[8]); word3_muladd(&w2, &w1, &w0, ws[28], p[7]); word3_muladd(&w2, &w1, &w0, ws[29], p[6]); word3_muladd(&w2, &w1, &w0, ws[30], p[5]); word3_muladd(&w2, &w1, &w0, ws[31], p[4]); word3_add(&w2, &w1, &w0, z[35]); ws[3] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[5], p[31]); word3_muladd(&w2, &w1, &w0, ws[6], p[30]); word3_muladd(&w2, &w1, &w0, ws[7], p[29]); word3_muladd(&w2, &w1, &w0, ws[8], p[28]); word3_muladd(&w2, &w1, &w0, ws[9], p[27]); word3_muladd(&w2, &w1, &w0, ws[10], p[26]); word3_muladd(&w2, &w1, &w0, ws[11], p[25]); word3_muladd(&w2, &w1, &w0, ws[12], p[24]); word3_muladd(&w2, &w1, &w0, ws[13], p[23]); word3_muladd(&w2, &w1, &w0, ws[14], p[22]); word3_muladd(&w2, &w1, &w0, ws[15], p[21]); word3_muladd(&w2, &w1, &w0, ws[16], p[20]); word3_muladd(&w2, &w1, &w0, ws[17], p[19]); word3_muladd(&w2, &w1, &w0, ws[18], p[18]); word3_muladd(&w2, &w1, &w0, ws[19], p[17]); word3_muladd(&w2, &w1, &w0, ws[20], p[16]); word3_muladd(&w2, &w1, &w0, ws[21], p[15]); word3_muladd(&w2, &w1, &w0, ws[22], p[14]); word3_muladd(&w2, &w1, &w0, ws[23], p[13]); word3_muladd(&w2, &w1, &w0, ws[24], p[12]); word3_muladd(&w2, &w1, &w0, ws[25], p[11]); word3_muladd(&w2, &w1, &w0, ws[26], p[10]); word3_muladd(&w2, &w1, &w0, ws[27], p[9]); word3_muladd(&w2, &w1, &w0, ws[28], p[8]); word3_muladd(&w2, &w1, &w0, ws[29], p[7]); word3_muladd(&w2, &w1, &w0, ws[30], p[6]); word3_muladd(&w2, &w1, &w0, ws[31], p[5]); word3_add(&w2, &w1, &w0, z[36]); ws[4] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[6], p[31]); word3_muladd(&w2, &w1, &w0, ws[7], p[30]); word3_muladd(&w2, &w1, &w0, ws[8], p[29]); word3_muladd(&w2, &w1, &w0, ws[9], p[28]); word3_muladd(&w2, &w1, &w0, ws[10], p[27]); word3_muladd(&w2, &w1, &w0, ws[11], p[26]); word3_muladd(&w2, &w1, &w0, ws[12], p[25]); word3_muladd(&w2, &w1, &w0, ws[13], p[24]); word3_muladd(&w2, &w1, &w0, ws[14], p[23]); word3_muladd(&w2, &w1, &w0, ws[15], p[22]); word3_muladd(&w2, &w1, &w0, ws[16], p[21]); word3_muladd(&w2, &w1, &w0, ws[17], p[20]); word3_muladd(&w2, &w1, &w0, ws[18], p[19]); word3_muladd(&w2, &w1, &w0, ws[19], p[18]); word3_muladd(&w2, &w1, &w0, ws[20], p[17]); word3_muladd(&w2, &w1, &w0, ws[21], p[16]); word3_muladd(&w2, &w1, &w0, ws[22], p[15]); word3_muladd(&w2, &w1, &w0, ws[23], p[14]); word3_muladd(&w2, &w1, &w0, ws[24], p[13]); word3_muladd(&w2, &w1, &w0, ws[25], p[12]); word3_muladd(&w2, &w1, &w0, ws[26], p[11]); word3_muladd(&w2, &w1, &w0, ws[27], p[10]); word3_muladd(&w2, &w1, &w0, ws[28], p[9]); word3_muladd(&w2, &w1, &w0, ws[29], p[8]); word3_muladd(&w2, &w1, &w0, ws[30], p[7]); word3_muladd(&w2, &w1, &w0, ws[31], p[6]); word3_add(&w2, &w1, &w0, z[37]); ws[5] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[7], p[31]); word3_muladd(&w2, &w1, &w0, ws[8], p[30]); word3_muladd(&w2, &w1, &w0, ws[9], p[29]); word3_muladd(&w2, &w1, &w0, ws[10], p[28]); word3_muladd(&w2, &w1, &w0, ws[11], p[27]); word3_muladd(&w2, &w1, &w0, ws[12], p[26]); word3_muladd(&w2, &w1, &w0, ws[13], p[25]); word3_muladd(&w2, &w1, &w0, ws[14], p[24]); word3_muladd(&w2, &w1, &w0, ws[15], p[23]); word3_muladd(&w2, &w1, &w0, ws[16], p[22]); word3_muladd(&w2, &w1, &w0, ws[17], p[21]); word3_muladd(&w2, &w1, &w0, ws[18], p[20]); word3_muladd(&w2, &w1, &w0, ws[19], p[19]); word3_muladd(&w2, &w1, &w0, ws[20], p[18]); word3_muladd(&w2, &w1, &w0, ws[21], p[17]); word3_muladd(&w2, &w1, &w0, ws[22], p[16]); word3_muladd(&w2, &w1, &w0, ws[23], p[15]); word3_muladd(&w2, &w1, &w0, ws[24], p[14]); word3_muladd(&w2, &w1, &w0, ws[25], p[13]); word3_muladd(&w2, &w1, &w0, ws[26], p[12]); word3_muladd(&w2, &w1, &w0, ws[27], p[11]); word3_muladd(&w2, &w1, &w0, ws[28], p[10]); word3_muladd(&w2, &w1, &w0, ws[29], p[9]); word3_muladd(&w2, &w1, &w0, ws[30], p[8]); word3_muladd(&w2, &w1, &w0, ws[31], p[7]); word3_add(&w2, &w1, &w0, z[38]); ws[6] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[8], p[31]); word3_muladd(&w2, &w1, &w0, ws[9], p[30]); word3_muladd(&w2, &w1, &w0, ws[10], p[29]); word3_muladd(&w2, &w1, &w0, ws[11], p[28]); word3_muladd(&w2, &w1, &w0, ws[12], p[27]); word3_muladd(&w2, &w1, &w0, ws[13], p[26]); word3_muladd(&w2, &w1, &w0, ws[14], p[25]); word3_muladd(&w2, &w1, &w0, ws[15], p[24]); word3_muladd(&w2, &w1, &w0, ws[16], p[23]); word3_muladd(&w2, &w1, &w0, ws[17], p[22]); word3_muladd(&w2, &w1, &w0, ws[18], p[21]); word3_muladd(&w2, &w1, &w0, ws[19], p[20]); word3_muladd(&w2, &w1, &w0, ws[20], p[19]); word3_muladd(&w2, &w1, &w0, ws[21], p[18]); word3_muladd(&w2, &w1, &w0, ws[22], p[17]); word3_muladd(&w2, &w1, &w0, ws[23], p[16]); word3_muladd(&w2, &w1, &w0, ws[24], p[15]); word3_muladd(&w2, &w1, &w0, ws[25], p[14]); word3_muladd(&w2, &w1, &w0, ws[26], p[13]); word3_muladd(&w2, &w1, &w0, ws[27], p[12]); word3_muladd(&w2, &w1, &w0, ws[28], p[11]); word3_muladd(&w2, &w1, &w0, ws[29], p[10]); word3_muladd(&w2, &w1, &w0, ws[30], p[9]); word3_muladd(&w2, &w1, &w0, ws[31], p[8]); word3_add(&w2, &w1, &w0, z[39]); ws[7] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[9], p[31]); word3_muladd(&w2, &w1, &w0, ws[10], p[30]); word3_muladd(&w2, &w1, &w0, ws[11], p[29]); word3_muladd(&w2, &w1, &w0, ws[12], p[28]); word3_muladd(&w2, &w1, &w0, ws[13], p[27]); word3_muladd(&w2, &w1, &w0, ws[14], p[26]); word3_muladd(&w2, &w1, &w0, ws[15], p[25]); word3_muladd(&w2, &w1, &w0, ws[16], p[24]); word3_muladd(&w2, &w1, &w0, ws[17], p[23]); word3_muladd(&w2, &w1, &w0, ws[18], p[22]); word3_muladd(&w2, &w1, &w0, ws[19], p[21]); word3_muladd(&w2, &w1, &w0, ws[20], p[20]); word3_muladd(&w2, &w1, &w0, ws[21], p[19]); word3_muladd(&w2, &w1, &w0, ws[22], p[18]); word3_muladd(&w2, &w1, &w0, ws[23], p[17]); word3_muladd(&w2, &w1, &w0, ws[24], p[16]); word3_muladd(&w2, &w1, &w0, ws[25], p[15]); word3_muladd(&w2, &w1, &w0, ws[26], p[14]); word3_muladd(&w2, &w1, &w0, ws[27], p[13]); word3_muladd(&w2, &w1, &w0, ws[28], p[12]); word3_muladd(&w2, &w1, &w0, ws[29], p[11]); word3_muladd(&w2, &w1, &w0, ws[30], p[10]); word3_muladd(&w2, &w1, &w0, ws[31], p[9]); word3_add(&w2, &w1, &w0, z[40]); ws[8] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[10], p[31]); word3_muladd(&w2, &w1, &w0, ws[11], p[30]); word3_muladd(&w2, &w1, &w0, ws[12], p[29]); word3_muladd(&w2, &w1, &w0, ws[13], p[28]); word3_muladd(&w2, &w1, &w0, ws[14], p[27]); word3_muladd(&w2, &w1, &w0, ws[15], p[26]); word3_muladd(&w2, &w1, &w0, ws[16], p[25]); word3_muladd(&w2, &w1, &w0, ws[17], p[24]); word3_muladd(&w2, &w1, &w0, ws[18], p[23]); word3_muladd(&w2, &w1, &w0, ws[19], p[22]); word3_muladd(&w2, &w1, &w0, ws[20], p[21]); word3_muladd(&w2, &w1, &w0, ws[21], p[20]); word3_muladd(&w2, &w1, &w0, ws[22], p[19]); word3_muladd(&w2, &w1, &w0, ws[23], p[18]); word3_muladd(&w2, &w1, &w0, ws[24], p[17]); word3_muladd(&w2, &w1, &w0, ws[25], p[16]); word3_muladd(&w2, &w1, &w0, ws[26], p[15]); word3_muladd(&w2, &w1, &w0, ws[27], p[14]); word3_muladd(&w2, &w1, &w0, ws[28], p[13]); word3_muladd(&w2, &w1, &w0, ws[29], p[12]); word3_muladd(&w2, &w1, &w0, ws[30], p[11]); word3_muladd(&w2, &w1, &w0, ws[31], p[10]); word3_add(&w2, &w1, &w0, z[41]); ws[9] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[11], p[31]); word3_muladd(&w2, &w1, &w0, ws[12], p[30]); word3_muladd(&w2, &w1, &w0, ws[13], p[29]); word3_muladd(&w2, &w1, &w0, ws[14], p[28]); word3_muladd(&w2, &w1, &w0, ws[15], p[27]); word3_muladd(&w2, &w1, &w0, ws[16], p[26]); word3_muladd(&w2, &w1, &w0, ws[17], p[25]); word3_muladd(&w2, &w1, &w0, ws[18], p[24]); word3_muladd(&w2, &w1, &w0, ws[19], p[23]); word3_muladd(&w2, &w1, &w0, ws[20], p[22]); word3_muladd(&w2, &w1, &w0, ws[21], p[21]); word3_muladd(&w2, &w1, &w0, ws[22], p[20]); word3_muladd(&w2, &w1, &w0, ws[23], p[19]); word3_muladd(&w2, &w1, &w0, ws[24], p[18]); word3_muladd(&w2, &w1, &w0, ws[25], p[17]); word3_muladd(&w2, &w1, &w0, ws[26], p[16]); word3_muladd(&w2, &w1, &w0, ws[27], p[15]); word3_muladd(&w2, &w1, &w0, ws[28], p[14]); word3_muladd(&w2, &w1, &w0, ws[29], p[13]); word3_muladd(&w2, &w1, &w0, ws[30], p[12]); word3_muladd(&w2, &w1, &w0, ws[31], p[11]); word3_add(&w2, &w1, &w0, z[42]); ws[10] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[12], p[31]); word3_muladd(&w2, &w1, &w0, ws[13], p[30]); word3_muladd(&w2, &w1, &w0, ws[14], p[29]); word3_muladd(&w2, &w1, &w0, ws[15], p[28]); word3_muladd(&w2, &w1, &w0, ws[16], p[27]); word3_muladd(&w2, &w1, &w0, ws[17], p[26]); word3_muladd(&w2, &w1, &w0, ws[18], p[25]); word3_muladd(&w2, &w1, &w0, ws[19], p[24]); word3_muladd(&w2, &w1, &w0, ws[20], p[23]); word3_muladd(&w2, &w1, &w0, ws[21], p[22]); word3_muladd(&w2, &w1, &w0, ws[22], p[21]); word3_muladd(&w2, &w1, &w0, ws[23], p[20]); word3_muladd(&w2, &w1, &w0, ws[24], p[19]); word3_muladd(&w2, &w1, &w0, ws[25], p[18]); word3_muladd(&w2, &w1, &w0, ws[26], p[17]); word3_muladd(&w2, &w1, &w0, ws[27], p[16]); word3_muladd(&w2, &w1, &w0, ws[28], p[15]); word3_muladd(&w2, &w1, &w0, ws[29], p[14]); word3_muladd(&w2, &w1, &w0, ws[30], p[13]); word3_muladd(&w2, &w1, &w0, ws[31], p[12]); word3_add(&w2, &w1, &w0, z[43]); ws[11] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[13], p[31]); word3_muladd(&w2, &w1, &w0, ws[14], p[30]); word3_muladd(&w2, &w1, &w0, ws[15], p[29]); word3_muladd(&w2, &w1, &w0, ws[16], p[28]); word3_muladd(&w2, &w1, &w0, ws[17], p[27]); word3_muladd(&w2, &w1, &w0, ws[18], p[26]); word3_muladd(&w2, &w1, &w0, ws[19], p[25]); word3_muladd(&w2, &w1, &w0, ws[20], p[24]); word3_muladd(&w2, &w1, &w0, ws[21], p[23]); word3_muladd(&w2, &w1, &w0, ws[22], p[22]); word3_muladd(&w2, &w1, &w0, ws[23], p[21]); word3_muladd(&w2, &w1, &w0, ws[24], p[20]); word3_muladd(&w2, &w1, &w0, ws[25], p[19]); word3_muladd(&w2, &w1, &w0, ws[26], p[18]); word3_muladd(&w2, &w1, &w0, ws[27], p[17]); word3_muladd(&w2, &w1, &w0, ws[28], p[16]); word3_muladd(&w2, &w1, &w0, ws[29], p[15]); word3_muladd(&w2, &w1, &w0, ws[30], p[14]); word3_muladd(&w2, &w1, &w0, ws[31], p[13]); word3_add(&w2, &w1, &w0, z[44]); ws[12] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[14], p[31]); word3_muladd(&w2, &w1, &w0, ws[15], p[30]); word3_muladd(&w2, &w1, &w0, ws[16], p[29]); word3_muladd(&w2, &w1, &w0, ws[17], p[28]); word3_muladd(&w2, &w1, &w0, ws[18], p[27]); word3_muladd(&w2, &w1, &w0, ws[19], p[26]); word3_muladd(&w2, &w1, &w0, ws[20], p[25]); word3_muladd(&w2, &w1, &w0, ws[21], p[24]); word3_muladd(&w2, &w1, &w0, ws[22], p[23]); word3_muladd(&w2, &w1, &w0, ws[23], p[22]); word3_muladd(&w2, &w1, &w0, ws[24], p[21]); word3_muladd(&w2, &w1, &w0, ws[25], p[20]); word3_muladd(&w2, &w1, &w0, ws[26], p[19]); word3_muladd(&w2, &w1, &w0, ws[27], p[18]); word3_muladd(&w2, &w1, &w0, ws[28], p[17]); word3_muladd(&w2, &w1, &w0, ws[29], p[16]); word3_muladd(&w2, &w1, &w0, ws[30], p[15]); word3_muladd(&w2, &w1, &w0, ws[31], p[14]); word3_add(&w2, &w1, &w0, z[45]); ws[13] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[15], p[31]); word3_muladd(&w2, &w1, &w0, ws[16], p[30]); word3_muladd(&w2, &w1, &w0, ws[17], p[29]); word3_muladd(&w2, &w1, &w0, ws[18], p[28]); word3_muladd(&w2, &w1, &w0, ws[19], p[27]); word3_muladd(&w2, &w1, &w0, ws[20], p[26]); word3_muladd(&w2, &w1, &w0, ws[21], p[25]); word3_muladd(&w2, &w1, &w0, ws[22], p[24]); word3_muladd(&w2, &w1, &w0, ws[23], p[23]); word3_muladd(&w2, &w1, &w0, ws[24], p[22]); word3_muladd(&w2, &w1, &w0, ws[25], p[21]); word3_muladd(&w2, &w1, &w0, ws[26], p[20]); word3_muladd(&w2, &w1, &w0, ws[27], p[19]); word3_muladd(&w2, &w1, &w0, ws[28], p[18]); word3_muladd(&w2, &w1, &w0, ws[29], p[17]); word3_muladd(&w2, &w1, &w0, ws[30], p[16]); word3_muladd(&w2, &w1, &w0, ws[31], p[15]); word3_add(&w2, &w1, &w0, z[46]); ws[14] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[16], p[31]); word3_muladd(&w2, &w1, &w0, ws[17], p[30]); word3_muladd(&w2, &w1, &w0, ws[18], p[29]); word3_muladd(&w2, &w1, &w0, ws[19], p[28]); word3_muladd(&w2, &w1, &w0, ws[20], p[27]); word3_muladd(&w2, &w1, &w0, ws[21], p[26]); word3_muladd(&w2, &w1, &w0, ws[22], p[25]); word3_muladd(&w2, &w1, &w0, ws[23], p[24]); word3_muladd(&w2, &w1, &w0, ws[24], p[23]); word3_muladd(&w2, &w1, &w0, ws[25], p[22]); word3_muladd(&w2, &w1, &w0, ws[26], p[21]); word3_muladd(&w2, &w1, &w0, ws[27], p[20]); word3_muladd(&w2, &w1, &w0, ws[28], p[19]); word3_muladd(&w2, &w1, &w0, ws[29], p[18]); word3_muladd(&w2, &w1, &w0, ws[30], p[17]); word3_muladd(&w2, &w1, &w0, ws[31], p[16]); word3_add(&w2, &w1, &w0, z[47]); ws[15] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[17], p[31]); word3_muladd(&w2, &w1, &w0, ws[18], p[30]); word3_muladd(&w2, &w1, &w0, ws[19], p[29]); word3_muladd(&w2, &w1, &w0, ws[20], p[28]); word3_muladd(&w2, &w1, &w0, ws[21], p[27]); word3_muladd(&w2, &w1, &w0, ws[22], p[26]); word3_muladd(&w2, &w1, &w0, ws[23], p[25]); word3_muladd(&w2, &w1, &w0, ws[24], p[24]); word3_muladd(&w2, &w1, &w0, ws[25], p[23]); word3_muladd(&w2, &w1, &w0, ws[26], p[22]); word3_muladd(&w2, &w1, &w0, ws[27], p[21]); word3_muladd(&w2, &w1, &w0, ws[28], p[20]); word3_muladd(&w2, &w1, &w0, ws[29], p[19]); word3_muladd(&w2, &w1, &w0, ws[30], p[18]); word3_muladd(&w2, &w1, &w0, ws[31], p[17]); word3_add(&w2, &w1, &w0, z[48]); ws[16] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[18], p[31]); word3_muladd(&w2, &w1, &w0, ws[19], p[30]); word3_muladd(&w2, &w1, &w0, ws[20], p[29]); word3_muladd(&w2, &w1, &w0, ws[21], p[28]); word3_muladd(&w2, &w1, &w0, ws[22], p[27]); word3_muladd(&w2, &w1, &w0, ws[23], p[26]); word3_muladd(&w2, &w1, &w0, ws[24], p[25]); word3_muladd(&w2, &w1, &w0, ws[25], p[24]); word3_muladd(&w2, &w1, &w0, ws[26], p[23]); word3_muladd(&w2, &w1, &w0, ws[27], p[22]); word3_muladd(&w2, &w1, &w0, ws[28], p[21]); word3_muladd(&w2, &w1, &w0, ws[29], p[20]); word3_muladd(&w2, &w1, &w0, ws[30], p[19]); word3_muladd(&w2, &w1, &w0, ws[31], p[18]); word3_add(&w2, &w1, &w0, z[49]); ws[17] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[19], p[31]); word3_muladd(&w2, &w1, &w0, ws[20], p[30]); word3_muladd(&w2, &w1, &w0, ws[21], p[29]); word3_muladd(&w2, &w1, &w0, ws[22], p[28]); word3_muladd(&w2, &w1, &w0, ws[23], p[27]); word3_muladd(&w2, &w1, &w0, ws[24], p[26]); word3_muladd(&w2, &w1, &w0, ws[25], p[25]); word3_muladd(&w2, &w1, &w0, ws[26], p[24]); word3_muladd(&w2, &w1, &w0, ws[27], p[23]); word3_muladd(&w2, &w1, &w0, ws[28], p[22]); word3_muladd(&w2, &w1, &w0, ws[29], p[21]); word3_muladd(&w2, &w1, &w0, ws[30], p[20]); word3_muladd(&w2, &w1, &w0, ws[31], p[19]); word3_add(&w2, &w1, &w0, z[50]); ws[18] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[20], p[31]); word3_muladd(&w2, &w1, &w0, ws[21], p[30]); word3_muladd(&w2, &w1, &w0, ws[22], p[29]); word3_muladd(&w2, &w1, &w0, ws[23], p[28]); word3_muladd(&w2, &w1, &w0, ws[24], p[27]); word3_muladd(&w2, &w1, &w0, ws[25], p[26]); word3_muladd(&w2, &w1, &w0, ws[26], p[25]); word3_muladd(&w2, &w1, &w0, ws[27], p[24]); word3_muladd(&w2, &w1, &w0, ws[28], p[23]); word3_muladd(&w2, &w1, &w0, ws[29], p[22]); word3_muladd(&w2, &w1, &w0, ws[30], p[21]); word3_muladd(&w2, &w1, &w0, ws[31], p[20]); word3_add(&w2, &w1, &w0, z[51]); ws[19] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[21], p[31]); word3_muladd(&w2, &w1, &w0, ws[22], p[30]); word3_muladd(&w2, &w1, &w0, ws[23], p[29]); word3_muladd(&w2, &w1, &w0, ws[24], p[28]); word3_muladd(&w2, &w1, &w0, ws[25], p[27]); word3_muladd(&w2, &w1, &w0, ws[26], p[26]); word3_muladd(&w2, &w1, &w0, ws[27], p[25]); word3_muladd(&w2, &w1, &w0, ws[28], p[24]); word3_muladd(&w2, &w1, &w0, ws[29], p[23]); word3_muladd(&w2, &w1, &w0, ws[30], p[22]); word3_muladd(&w2, &w1, &w0, ws[31], p[21]); word3_add(&w2, &w1, &w0, z[52]); ws[20] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[22], p[31]); word3_muladd(&w2, &w1, &w0, ws[23], p[30]); word3_muladd(&w2, &w1, &w0, ws[24], p[29]); word3_muladd(&w2, &w1, &w0, ws[25], p[28]); word3_muladd(&w2, &w1, &w0, ws[26], p[27]); word3_muladd(&w2, &w1, &w0, ws[27], p[26]); word3_muladd(&w2, &w1, &w0, ws[28], p[25]); word3_muladd(&w2, &w1, &w0, ws[29], p[24]); word3_muladd(&w2, &w1, &w0, ws[30], p[23]); word3_muladd(&w2, &w1, &w0, ws[31], p[22]); word3_add(&w2, &w1, &w0, z[53]); ws[21] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[23], p[31]); word3_muladd(&w2, &w1, &w0, ws[24], p[30]); word3_muladd(&w2, &w1, &w0, ws[25], p[29]); word3_muladd(&w2, &w1, &w0, ws[26], p[28]); word3_muladd(&w2, &w1, &w0, ws[27], p[27]); word3_muladd(&w2, &w1, &w0, ws[28], p[26]); word3_muladd(&w2, &w1, &w0, ws[29], p[25]); word3_muladd(&w2, &w1, &w0, ws[30], p[24]); word3_muladd(&w2, &w1, &w0, ws[31], p[23]); word3_add(&w2, &w1, &w0, z[54]); ws[22] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[24], p[31]); word3_muladd(&w2, &w1, &w0, ws[25], p[30]); word3_muladd(&w2, &w1, &w0, ws[26], p[29]); word3_muladd(&w2, &w1, &w0, ws[27], p[28]); word3_muladd(&w2, &w1, &w0, ws[28], p[27]); word3_muladd(&w2, &w1, &w0, ws[29], p[26]); word3_muladd(&w2, &w1, &w0, ws[30], p[25]); word3_muladd(&w2, &w1, &w0, ws[31], p[24]); word3_add(&w2, &w1, &w0, z[55]); ws[23] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[25], p[31]); word3_muladd(&w2, &w1, &w0, ws[26], p[30]); word3_muladd(&w2, &w1, &w0, ws[27], p[29]); word3_muladd(&w2, &w1, &w0, ws[28], p[28]); word3_muladd(&w2, &w1, &w0, ws[29], p[27]); word3_muladd(&w2, &w1, &w0, ws[30], p[26]); word3_muladd(&w2, &w1, &w0, ws[31], p[25]); word3_add(&w2, &w1, &w0, z[56]); ws[24] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[26], p[31]); word3_muladd(&w2, &w1, &w0, ws[27], p[30]); word3_muladd(&w2, &w1, &w0, ws[28], p[29]); word3_muladd(&w2, &w1, &w0, ws[29], p[28]); word3_muladd(&w2, &w1, &w0, ws[30], p[27]); word3_muladd(&w2, &w1, &w0, ws[31], p[26]); word3_add(&w2, &w1, &w0, z[57]); ws[25] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[27], p[31]); word3_muladd(&w2, &w1, &w0, ws[28], p[30]); word3_muladd(&w2, &w1, &w0, ws[29], p[29]); word3_muladd(&w2, &w1, &w0, ws[30], p[28]); word3_muladd(&w2, &w1, &w0, ws[31], p[27]); word3_add(&w2, &w1, &w0, z[58]); ws[26] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[28], p[31]); word3_muladd(&w2, &w1, &w0, ws[29], p[30]); word3_muladd(&w2, &w1, &w0, ws[30], p[29]); word3_muladd(&w2, &w1, &w0, ws[31], p[28]); word3_add(&w2, &w1, &w0, z[59]); ws[27] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[29], p[31]); word3_muladd(&w2, &w1, &w0, ws[30], p[30]); word3_muladd(&w2, &w1, &w0, ws[31], p[29]); word3_add(&w2, &w1, &w0, z[60]); ws[28] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[30], p[31]); word3_muladd(&w2, &w1, &w0, ws[31], p[30]); word3_add(&w2, &w1, &w0, z[61]); ws[29] = w0; w0 = w1; w1 = w2; w2 = 0; word3_muladd(&w2, &w1, &w0, ws[31], p[31]); word3_add(&w2, &w1, &w0, z[62]); ws[30] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[63]); ws[31] = w0; w0 = w1; w1 = w2; w2 = 0; word3_add(&w2, &w1, &w0, z[65]); ws[32] = w0; ws[33] = w1; word borrow = bigint_sub3(ws + 32 + 1, ws, 32 + 1, p, 32); CT::conditional_copy_mem(borrow, z, ws, ws + 33, 33); clear_mem(z + 32, 2*(32+1) - 32); } } /* * NEWHOPE Ring-LWE scheme * Based on the public domain reference implementation by the * designers (https://github.com/tpoeppelmann/newhope) * * Further changes * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { newhope_poly::~newhope_poly() { secure_scrub_memory(coeffs, sizeof(coeffs)); } typedef newhope_poly poly; namespace { static const uint16_t PARAM_Q = 12289; static const size_t PARAM_N = 1024; /* Incomplete-reduction routines; for details on allowed input ranges * and produced output ranges, see the description in the paper: * https://cryptojedi.org/papers/#newhope */ inline uint16_t montgomery_reduce(uint32_t a) { const uint32_t qinv = 12287; // -inverse_mod(p,2^18) const uint32_t rlog = 18; const uint32_t rlog_mask = ((1 << rlog) - 1); uint32_t u = (a * qinv); u &= rlog_mask; u *= PARAM_Q; u += a; return (u >> rlog); } inline uint16_t barrett_reduce(uint16_t a) { uint32_t u = (static_cast(a) * 5) >> 16; u *= PARAM_Q; a = static_cast(a - u); return a; } inline void mul_coefficients(uint16_t* poly, const uint16_t* factors) { for(size_t i = 0; i < PARAM_N; i++) { poly[i] = montgomery_reduce(poly[i] * factors[i]); } } /* GS_bo_to_no; omegas need to be in Montgomery domain */ inline void ntt(uint16_t* a, const uint16_t* omega) { for(size_t i = 0; i < 10; i+=2) { // Even level size_t distance = (1ULL << i); for(size_t start = 0; start < distance; start++) { size_t jTwiddle = 0; for(size_t j = start; j < PARAM_N-1; j += 2*distance) { uint16_t W = omega[jTwiddle++]; uint16_t temp = a[j]; a[j] = (temp + a[j + distance]); // Omit reduction (be lazy) a[j + distance] = montgomery_reduce((W * (static_cast(temp) + 3*PARAM_Q - a[j + distance]))); } } // Odd level distance <<= 1; for(size_t start = 0; start < distance; start++) { size_t jTwiddle = 0; for(size_t j = start; j < PARAM_N-1; j += 2*distance) { uint16_t W = omega[jTwiddle++]; uint16_t temp = a[j]; a[j] = barrett_reduce((temp + a[j + distance])); a[j + distance] = montgomery_reduce((W * (static_cast(temp) + 3*PARAM_Q - a[j + distance]))); } } } } inline void poly_frombytes(poly* r, const uint8_t* a) { for(size_t i = 0; i < PARAM_N/4; i++) { r->coeffs[4*i+0] = a[7*i+0] | ((static_cast(a[7*i+1]) & 0x3f) << 8); r->coeffs[4*i+1] = (a[7*i+1] >> 6) | (static_cast(a[7*i+2]) << 2) | (static_cast (a[7*i+3] & 0x0f) << 10); r->coeffs[4*i+2] = (a[7*i+3] >> 4) | (static_cast(a[7*i+4]) << 4) | (static_cast (a[7*i+5] & 0x03) << 12); r->coeffs[4*i+3] = (a[7*i+5] >> 2) | (static_cast(a[7*i+6]) << 6); } } inline void poly_tobytes(uint8_t* r, const poly* p) { for(size_t i = 0; i < PARAM_N/4; i++) { uint16_t t0 = barrett_reduce(p->coeffs[4*i+0]); //Make sure that coefficients have only 14 bits uint16_t t1 = barrett_reduce(p->coeffs[4*i+1]); uint16_t t2 = barrett_reduce(p->coeffs[4*i+2]); uint16_t t3 = barrett_reduce(p->coeffs[4*i+3]); uint16_t m; int16_t c; m = t0 - PARAM_Q; c = m; c >>= 15; t0 = m ^ ((t0^m)&c); // >= 15; t1 = m ^ ((t1^m)&c); // >= 15; t2 = m ^ ((t2^m)&c); // >= 15; t3 = m ^ ((t3^m)&c); // ((t0 >> 8) | (t1 << 6)); r[7*i+2] = static_cast((t1 >> 2)); r[7*i+3] = static_cast((t1 >> 10) | (t2 << 4)); r[7*i+4] = static_cast((t2 >> 4)); r[7*i+5] = static_cast((t2 >> 12) | (t3 << 2)); r[7*i+6] = static_cast((t3 >> 6)); } } inline void poly_getnoise(Botan::RandomNumberGenerator& rng, poly* r) { uint8_t buf[4*PARAM_N]; rng.randomize(buf, 4*PARAM_N); for(size_t i = 0; i < PARAM_N; i++) { const uint32_t t = load_le(buf, i); uint32_t d = 0; for(size_t j = 0; j < 8; j++) { d += (t >> j) & 0x01010101; } const uint32_t a = ((d >> 8) & 0xff) + (d & 0xff); const uint32_t b = (d >> 24) + ((d >> 16) & 0xff); r->coeffs[i] = static_cast(a + PARAM_Q - b); } } inline void poly_pointwise(poly* r, const poly* a, const poly* b) { for(size_t i = 0; i < PARAM_N; i++) { const uint16_t t = montgomery_reduce(3186*b->coeffs[i]); /* t is now in Montgomery domain */ r->coeffs[i] = montgomery_reduce(a->coeffs[i] * t); /* r->coeffs[i] is back in normal domain */ } } inline void poly_add(poly* r, const poly* a, const poly* b) { for(size_t i = 0; i < PARAM_N; i++) { r->coeffs[i] = barrett_reduce(a->coeffs[i] + b->coeffs[i]); } } inline void poly_ntt(poly* r) { static const uint16_t omegas_montgomery[PARAM_N/2] = { 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775, 2344, 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449, 3789, 12142, 11973, 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879, 11889, 1728, 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, 9987, 605, 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080, 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681, 3477, 1105, 142, 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968, 12097, 7591, 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874, 677, 3336, 6234, 2766, 1323, 9115, 12237, 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, 4774, 5429, 11871, 3772, 453, 5908, 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030, 1843, 2361, 12071, 2908, 3529, 3434, 3202, 7796, 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942, 10706, 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634, 6554, 10596, 9280, 11566, 174, 2948, 2503, 6507, 10723, 11606, 2459, 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065, 835, 3570, 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, 1112, 3728, 4049, 11130, 5990, 1404, 325, 948, 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105, 7991, 3329, 9597, 12121, 5106, 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969, 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, 1062, 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088, 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, 7143, 11567, 10984, 4134, 5736, 4978, 10938, 5777, 8961, 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283, 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, 4452, 10908, 2525, 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791, 5092, 2089, 9005, 2881, 3289, 2013, 9048, 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, 9558, 8830, 3637, 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952, 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, 1002, 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045, 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188, 11516, 390, 8511, 8456, 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730, 10745, 10111, 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777, 4654, 10863, 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, 4414, 9442, 7917, 2174 }; static const uint16_t psis_bitrev_montgomery[PARAM_N] = { 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775, 2344, 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449, 3789, 12142, 11973, 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879, 11889, 1728, 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, 9987, 605, 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080, 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681, 3477, 1105, 142, 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968, 12097, 7591, 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874, 677, 3336, 6234, 2766, 1323, 9115, 12237, 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, 4774, 5429, 11871, 3772, 453, 5908, 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030, 1843, 2361, 12071, 2908, 3529, 3434, 3202, 7796, 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942, 10706, 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634, 6554, 10596, 9280, 11566, 174, 2948, 2503, 6507, 10723, 11606, 2459, 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065, 835, 3570, 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, 1112, 3728, 4049, 11130, 5990, 1404, 325, 948, 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105, 7991, 3329, 9597, 12121, 5106, 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969, 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, 1062, 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088, 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, 7143, 11567, 10984, 4134, 5736, 4978, 10938, 5777, 8961, 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283, 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, 4452, 10908, 2525, 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791, 5092, 2089, 9005, 2881, 3289, 2013, 9048, 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, 9558, 8830, 3637, 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952, 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, 1002, 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045, 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188, 11516, 390, 8511, 8456, 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730, 10745, 10111, 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777, 4654, 10863, 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, 4414, 9442, 7917, 2174, 3947, 11951, 2455, 6599, 10545, 10975, 3654, 2894, 7681, 7126, 7287, 12269, 4119, 3343, 2151, 1522, 7174, 7350, 11041, 2442, 2148, 5959, 6492, 8330, 8945, 5598, 3624, 10397, 1325, 6565, 1945, 11260, 10077, 2674, 3338, 3276, 11034, 506, 6505, 1392, 5478, 8778, 1178, 2776, 3408, 10347, 11124, 2575, 9489, 12096, 6092, 10058, 4167, 6085, 923, 11251, 11912, 4578, 10669, 11914, 425, 10453, 392, 10104, 8464, 4235, 8761, 7376, 2291, 3375, 7954, 8896, 6617, 7790, 1737, 11667, 3982, 9342, 6680, 636, 6825, 7383, 512, 4670, 2900, 12050, 7735, 994, 1687, 11883, 7021, 146, 10485, 1403, 5189, 6094, 2483, 2054, 3042, 10945, 3981, 10821, 11826, 8882, 8151, 180, 9600, 7684, 5219, 10880, 6780, 204, 11232, 2600, 7584, 3121, 3017, 11053, 7814, 7043, 4251, 4739, 11063, 6771, 7073, 9261, 2360, 11925, 1928, 11825, 8024, 3678, 3205, 3359, 11197, 5209, 8581, 3238, 8840, 1136, 9363, 1826, 3171, 4489, 7885, 346, 2068, 1389, 8257, 3163, 4840, 6127, 8062, 8921, 612, 4238, 10763, 8067, 125, 11749, 10125, 5416, 2110, 716, 9839, 10584, 11475, 11873, 3448, 343, 1908, 4538, 10423, 7078, 4727, 1208, 11572, 3589, 2982, 1373, 1721, 10753, 4103, 2429, 4209, 5412, 5993, 9011, 438, 3515, 7228, 1218, 8347, 5232, 8682, 1327, 7508, 4924, 448, 1014, 10029, 12221, 4566, 5836, 12229, 2717, 1535, 3200, 5588, 5845, 412, 5102, 7326, 3744, 3056, 2528, 7406, 8314, 9202, 6454, 6613, 1417, 10032, 7784, 1518, 3765, 4176, 5063, 9828, 2275, 6636, 4267, 6463, 2065, 7725, 3495, 8328, 8755, 8144, 10533, 5966, 12077, 9175, 9520, 5596, 6302, 8400, 579, 6781, 11014, 5734, 11113, 11164, 4860, 1131, 10844, 9068, 8016, 9694, 3837, 567, 9348, 7000, 6627, 7699, 5082, 682, 11309, 5207, 4050, 7087, 844, 7434, 3769, 293, 9057, 6940, 9344, 10883, 2633, 8190, 3944, 5530, 5604, 3480, 2171, 9282, 11024, 2213, 8136, 3805, 767, 12239, 216, 11520, 6763, 10353, 7, 8566, 845, 7235, 3154, 4360, 3285, 10268, 2832, 3572, 1282, 7559, 3229, 8360, 10583, 6105, 3120, 6643, 6203, 8536, 8348, 6919, 3536, 9199, 10891, 11463, 5043, 1658, 5618, 8787, 5789, 4719, 751, 11379, 6389, 10783, 3065, 7806, 6586, 2622, 5386, 510, 7628, 6921, 578, 10345, 11839, 8929, 4684, 12226, 7154, 9916, 7302, 8481, 3670, 11066, 2334, 1590, 7878, 10734, 1802, 1891, 5103, 6151, 8820, 3418, 7846, 9951, 4693, 417, 9996, 9652, 4510, 2946, 5461, 365, 881, 1927, 1015, 11675, 11009, 1371, 12265, 2485, 11385, 5039, 6742, 8449, 1842, 12217, 8176, 9577, 4834, 7937, 9461, 2643, 11194, 3045, 6508, 4094, 3451, 7911, 11048, 5406, 4665, 3020, 6616, 11345, 7519, 3669, 5287, 1790, 7014, 5410, 11038, 11249, 2035, 6125, 10407, 4565, 7315, 5078, 10506, 2840, 2478, 9270, 4194, 9195, 4518, 7469, 1160, 6878, 2730, 10421, 10036, 1734, 3815, 10939, 5832, 10595, 10759, 4423, 8420, 9617, 7119, 11010, 11424, 9173, 189, 10080, 10526, 3466, 10588, 7592, 3578, 11511, 7785, 9663, 530, 12150, 8957, 2532, 3317, 9349, 10243, 1481, 9332, 3454, 3758, 7899, 4218, 2593, 11410, 2276, 982, 6513, 1849, 8494, 9021, 4523, 7988, 8, 457, 648, 150, 8000, 2307, 2301, 874, 5650, 170, 9462, 2873, 9855, 11498, 2535, 11169, 5808, 12268, 9687, 1901, 7171, 11787, 3846, 1573, 6063, 3793, 466, 11259, 10608, 3821, 6320, 4649, 6263, 2929 }; mul_coefficients(r->coeffs, psis_bitrev_montgomery); ntt(r->coeffs, omegas_montgomery); } inline void bitrev_vector(uint16_t* poly) { static const uint16_t bitrev_table[1024] = { 0, 512, 256, 768, 128, 640, 384, 896, 64, 576, 320, 832, 192, 704, 448, 960, 32, 544, 288, 800, 160, 672, 416, 928, 96, 608, 352, 864, 224, 736, 480, 992, 16, 528, 272, 784, 144, 656, 400, 912, 80, 592, 336, 848, 208, 720, 464, 976, 48, 560, 304, 816, 176, 688, 432, 944, 112, 624, 368, 880, 240, 752, 496, 1008, 8, 520, 264, 776, 136, 648, 392, 904, 72, 584, 328, 840, 200, 712, 456, 968, 40, 552, 296, 808, 168, 680, 424, 936, 104, 616, 360, 872, 232, 744, 488, 1000, 24, 536, 280, 792, 152, 664, 408, 920, 88, 600, 344, 856, 216, 728, 472, 984, 56, 568, 312, 824, 184, 696, 440, 952, 120, 632, 376, 888, 248, 760, 504, 1016, 4, 516, 260, 772, 132, 644, 388, 900, 68, 580, 324, 836, 196, 708, 452, 964, 36, 548, 292, 804, 164, 676, 420, 932, 100, 612, 356, 868, 228, 740, 484, 996, 20, 532, 276, 788, 148, 660, 404, 916, 84, 596, 340, 852, 212, 724, 468, 980, 52, 564, 308, 820, 180, 692, 436, 948, 116, 628, 372, 884, 244, 756, 500, 1012, 12, 524, 268, 780, 140, 652, 396, 908, 76, 588, 332, 844, 204, 716, 460, 972, 44, 556, 300, 812, 172, 684, 428, 940, 108, 620, 364, 876, 236, 748, 492, 1004, 28, 540, 284, 796, 156, 668, 412, 924, 92, 604, 348, 860, 220, 732, 476, 988, 60, 572, 316, 828, 188, 700, 444, 956, 124, 636, 380, 892, 252, 764, 508, 1020, 2, 514, 258, 770, 130, 642, 386, 898, 66, 578, 322, 834, 194, 706, 450, 962, 34, 546, 290, 802, 162, 674, 418, 930, 98, 610, 354, 866, 226, 738, 482, 994, 18, 530, 274, 786, 146, 658, 402, 914, 82, 594, 338, 850, 210, 722, 466, 978, 50, 562, 306, 818, 178, 690, 434, 946, 114, 626, 370, 882, 242, 754, 498, 1010, 10, 522, 266, 778, 138, 650, 394, 906, 74, 586, 330, 842, 202, 714, 458, 970, 42, 554, 298, 810, 170, 682, 426, 938, 106, 618, 362, 874, 234, 746, 490, 1002, 26, 538, 282, 794, 154, 666, 410, 922, 90, 602, 346, 858, 218, 730, 474, 986, 58, 570, 314, 826, 186, 698, 442, 954, 122, 634, 378, 890, 250, 762, 506, 1018, 6, 518, 262, 774, 134, 646, 390, 902, 70, 582, 326, 838, 198, 710, 454, 966, 38, 550, 294, 806, 166, 678, 422, 934, 102, 614, 358, 870, 230, 742, 486, 998, 22, 534, 278, 790, 150, 662, 406, 918, 86, 598, 342, 854, 214, 726, 470, 982, 54, 566, 310, 822, 182, 694, 438, 950, 118, 630, 374, 886, 246, 758, 502, 1014, 14, 526, 270, 782, 142, 654, 398, 910, 78, 590, 334, 846, 206, 718, 462, 974, 46, 558, 302, 814, 174, 686, 430, 942, 110, 622, 366, 878, 238, 750, 494, 1006, 30, 542, 286, 798, 158, 670, 414, 926, 94, 606, 350, 862, 222, 734, 478, 990, 62, 574, 318, 830, 190, 702, 446, 958, 126, 638, 382, 894, 254, 766, 510, 1022, 1, 513, 257, 769, 129, 641, 385, 897, 65, 577, 321, 833, 193, 705, 449, 961, 33, 545, 289, 801, 161, 673, 417, 929, 97, 609, 353, 865, 225, 737, 481, 993, 17, 529, 273, 785, 145, 657, 401, 913, 81, 593, 337, 849, 209, 721, 465, 977, 49, 561, 305, 817, 177, 689, 433, 945, 113, 625, 369, 881, 241, 753, 497, 1009, 9, 521, 265, 777, 137, 649, 393, 905, 73, 585, 329, 841, 201, 713, 457, 969, 41, 553, 297, 809, 169, 681, 425, 937, 105, 617, 361, 873, 233, 745, 489, 1001, 25, 537, 281, 793, 153, 665, 409, 921, 89, 601, 345, 857, 217, 729, 473, 985, 57, 569, 313, 825, 185, 697, 441, 953, 121, 633, 377, 889, 249, 761, 505, 1017, 5, 517, 261, 773, 133, 645, 389, 901, 69, 581, 325, 837, 197, 709, 453, 965, 37, 549, 293, 805, 165, 677, 421, 933, 101, 613, 357, 869, 229, 741, 485, 997, 21, 533, 277, 789, 149, 661, 405, 917, 85, 597, 341, 853, 213, 725, 469, 981, 53, 565, 309, 821, 181, 693, 437, 949, 117, 629, 373, 885, 245, 757, 501, 1013, 13, 525, 269, 781, 141, 653, 397, 909, 77, 589, 333, 845, 205, 717, 461, 973, 45, 557, 301, 813, 173, 685, 429, 941, 109, 621, 365, 877, 237, 749, 493, 1005, 29, 541, 285, 797, 157, 669, 413, 925, 93, 605, 349, 861, 221, 733, 477, 989, 61, 573, 317, 829, 189, 701, 445, 957, 125, 637, 381, 893, 253, 765, 509, 1021, 3, 515, 259, 771, 131, 643, 387, 899, 67, 579, 323, 835, 195, 707, 451, 963, 35, 547, 291, 803, 163, 675, 419, 931, 99, 611, 355, 867, 227, 739, 483, 995, 19, 531, 275, 787, 147, 659, 403, 915, 83, 595, 339, 851, 211, 723, 467, 979, 51, 563, 307, 819, 179, 691, 435, 947, 115, 627, 371, 883, 243, 755, 499, 1011, 11, 523, 267, 779, 139, 651, 395, 907, 75, 587, 331, 843, 203, 715, 459, 971, 43, 555, 299, 811, 171, 683, 427, 939, 107, 619, 363, 875, 235, 747, 491, 1003, 27, 539, 283, 795, 155, 667, 411, 923, 91, 603, 347, 859, 219, 731, 475, 987, 59, 571, 315, 827, 187, 699, 443, 955, 123, 635, 379, 891, 251, 763, 507, 1019, 7, 519, 263, 775, 135, 647, 391, 903, 71, 583, 327, 839, 199, 711, 455, 967, 39, 551, 295, 807, 167, 679, 423, 935, 103, 615, 359, 871, 231, 743, 487, 999, 23, 535, 279, 791, 151, 663, 407, 919, 87, 599, 343, 855, 215, 727, 471, 983, 55, 567, 311, 823, 183, 695, 439, 951, 119, 631, 375, 887, 247, 759, 503, 1015, 15, 527, 271, 783, 143, 655, 399, 911, 79, 591, 335, 847, 207, 719, 463, 975, 47, 559, 303, 815, 175, 687, 431, 943, 111, 623, 367, 879, 239, 751, 495, 1007, 31, 543, 287, 799, 159, 671, 415, 927, 95, 607, 351, 863, 223, 735, 479, 991, 63, 575, 319, 831, 191, 703, 447, 959, 127, 639, 383, 895, 255, 767, 511, 1023 }; for(size_t i = 0; i < PARAM_N; i++) { const uint16_t r = bitrev_table[i]; if(i < r) { const uint16_t tmp = poly[i]; poly[i] = poly[r]; poly[r] = tmp; } } } inline void poly_invntt(poly* r) { static const uint16_t omegas_inv_montgomery[PARAM_N/2] = { 4075, 5315, 4324, 4916, 10120, 11767, 7210, 9027, 10316, 6715, 1278, 9945, 3514, 11248, 11271, 5925, 147, 8500, 7840, 6833, 5537, 4749, 4467, 7500, 11099, 9606, 6171, 8471, 8429, 5445, 11239, 7753, 9090, 12233, 5529, 5206, 10587, 1987, 11635, 3565, 5415, 8646, 6153, 6427, 7341, 6152, 10561, 400, 8410, 1922, 2033, 8291, 1359, 6854, 11035, 973, 8579, 6093, 6950, 5446, 11821, 8301, 11907, 316, 52, 3174, 10966, 9523, 6055, 8953, 11612, 6415, 2505, 5906, 10710, 11858, 8332, 9450, 10162, 151, 3482, 787, 5468, 1010, 4169, 9162, 5241, 9369, 7509, 8844, 7232, 4698, 192, 1321, 10240, 4912, 885, 6281, 10333, 7280, 8757, 11286, 58, 12048, 12147, 11184, 8812, 6608, 2844, 3438, 4212, 11314, 8687, 6068, 421, 8209, 3600, 3263, 7665, 6077, 7507, 5886, 3029, 6695, 4213, 504, 11684, 2302, 1962, 1594, 6328, 7183, 168, 2692, 8960, 4298, 5184, 11089, 6122, 9734, 10929, 3956, 5297, 6170, 3762, 9370, 4016, 4077, 6523, 652, 11994, 6099, 1146, 11341, 11964, 10885, 6299, 1159, 8240, 8561, 11177, 2078, 10331, 4322, 11367, 441, 4079, 11231, 3150, 1319, 8243, 709, 8049, 8719, 11454, 6224, 3054, 6803, 3123, 10542, 4433, 6370, 7032, 3834, 8633, 12225, 9830, 683, 1566, 5782, 9786, 9341, 12115, 723, 3009, 1693, 5735, 2655, 2738, 6421, 11942, 2925, 1975, 8532, 3315, 11863, 4754, 1858, 1583, 6347, 2500, 10800, 6374, 1483, 12240, 1263, 1815, 5383, 10777, 350, 6920, 10232, 4493, 9087, 8855, 8760, 9381, 218, 9928, 10446, 9259, 4115, 6147, 9842, 8326, 576, 10335, 10238, 10484, 9407, 6381, 11836, 8517, 418, 6860, 7515, 1293, 7552, 2767, 156, 8298, 8320, 10008, 5876, 5333, 10258, 10115, 4372, 2847, 7875, 8232, 9018, 8925, 1689, 8236, 2645, 5042, 9984, 7094, 9509, 1484, 7394, 3, 4437, 160, 3149, 113, 7370, 10123, 3915, 6998, 2704, 8653, 4938, 1426, 7635, 10512, 1663, 6957, 3510, 2370, 2865, 3978, 9320, 3247, 9603, 6882, 3186, 10659, 10163, 1153, 9405, 8241, 10040, 2178, 1544, 5559, 420, 8304, 4905, 476, 3531, 5191, 9153, 2399, 8889, 3000, 671, 243, 3016, 3763, 10849, 12262, 9223, 10657, 7205, 11272, 7404, 7575, 8146, 10752, 242, 2678, 3704, 11744, 5019, 3833, 3778, 11899, 773, 5101, 11222, 9888, 442, 2912, 5698, 11935, 4861, 7277, 9808, 11244, 2859, 3780, 11414, 4976, 10682, 7201, 8005, 11287, 5011, 6267, 2987, 2437, 3646, 2566, 10102, 9867, 6250, 5444, 2381, 11796, 8193, 4337, 11854, 1912, 1378, 404, 7644, 1065, 2143, 11121, 5277, 3248, 11082, 2548, 8058, 8907, 11934, 1759, 8582, 3694, 7110, 12144, 6747, 8652, 3459, 2731, 8357, 6378, 7399, 10861, 1696, 9863, 334, 7657, 6534, 11029, 4388, 11560, 3241, 10276, 9000, 9408, 3284, 10200, 7197, 6498, 544, 2468, 339, 11267, 9, 2842, 480, 5331, 7300, 1673, 4278, 4177, 8705, 9764, 1381, 7837, 2396, 8340, 8993, 4354, 130, 6915, 2837, 11462, 5767, 953, 8541, 9813, 118, 7222, 2197, 3006, 9545, 563, 9314, 2625, 11340, 4821, 2639, 7266, 5828, 6561, 7698, 3328, 6512, 1351, 7311, 6553, 8155, 1305, 722, 5146, 4043, 12288, 10810, 2545, 3621, 8747, 8785, 1646, 1212, 5860, 3195, 7203, 10963, 3201, 3014, 955, 11499, 9970, 11119, 3135, 3712, 7443, 9542, 7484, 8736, 9995, 11227, 1635, 9521, 1177, 8034, 140, 10436, 11563, 7678, 4320, 11289, 9198, 12208, 2963, 7393, 2366, 9238 }; static const uint16_t psis_inv_montgomery[PARAM_N] = { 256, 10570, 1510, 7238, 1034, 7170, 6291, 7921, 11665, 3422, 4000, 2327, 2088, 5565, 795, 10647, 1521, 5484, 2539, 7385, 1055, 7173, 8047, 11683, 1669, 1994, 3796, 5809, 4341, 9398, 11876, 12230, 10525, 12037, 12253, 3506, 4012, 9351, 4847, 2448, 7372, 9831, 3160, 2207, 5582, 2553, 7387, 6322, 9681, 1383, 10731, 1533, 219, 5298, 4268, 7632, 6357, 9686, 8406, 4712, 9451, 10128, 4958, 5975, 11387, 8649, 11769, 6948, 11526, 12180, 1740, 10782, 6807, 2728, 7412, 4570, 4164, 4106, 11120, 12122, 8754, 11784, 3439, 5758, 11356, 6889, 9762, 11928, 1704, 1999, 10819, 12079, 12259, 7018, 11536, 1648, 1991, 2040, 2047, 2048, 10826, 12080, 8748, 8272, 8204, 1172, 1923, 7297, 2798, 7422, 6327, 4415, 7653, 6360, 11442, 12168, 7005, 8023, 9924, 8440, 8228, 2931, 7441, 1063, 3663, 5790, 9605, 10150, 1450, 8985, 11817, 10466, 10273, 12001, 3470, 7518, 1074, 1909, 7295, 9820, 4914, 702, 5367, 7789, 8135, 9940, 1420, 3714, 11064, 12114, 12264, 1752, 5517, 9566, 11900, 1700, 3754, 5803, 829, 1874, 7290, 2797, 10933, 5073, 7747, 8129, 6428, 6185, 11417, 1631, 233, 5300, 9535, 10140, 11982, 8734, 8270, 2937, 10953, 8587, 8249, 2934, 9197, 4825, 5956, 4362, 9401, 1343, 3703, 529, 10609, 12049, 6988, 6265, 895, 3639, 4031, 4087, 4095, 585, 10617, 8539, 4731, 4187, 9376, 3095, 9220, 10095, 10220, 1460, 10742, 12068, 1724, 5513, 11321, 6884, 2739, 5658, 6075, 4379, 11159, 10372, 8504, 4726, 9453, 3106, 7466, 11600, 10435, 8513, 9994, 8450, 9985, 3182, 10988, 8592, 2983, 9204, 4826, 2445, 5616, 6069, 867, 3635, 5786, 11360, 5134, 2489, 10889, 12089, 1727, 7269, 2794, 9177, 1311, 5454, 9557, 6632, 2703, 9164, 10087, 1441, 3717, 531, 3587, 2268, 324, 5313, 759, 1864, 5533, 2546, 7386, 9833, 8427, 4715, 11207, 1601, 7251, 4547, 11183, 12131, 1733, 10781, 10318, 1474, 10744, 5046, 4232, 11138, 10369, 6748, 964, 7160, 4534, 7670, 8118, 8182, 4680, 11202, 6867, 981, 8918, 1274, 182, 26, 7026, 8026, 11680, 12202, 10521, 1503, 7237, 4545, 5916, 9623, 8397, 11733, 10454, 3249, 9242, 6587, 941, 1890, 270, 10572, 6777, 9746, 6659, 6218, 6155, 6146, 878, 1881, 7291, 11575, 12187, 1741, 7271, 8061, 11685, 6936, 4502, 9421, 4857, 4205, 7623, 1089, 10689, 1527, 8996, 10063, 11971, 10488, 6765, 2722, 3900, 9335, 11867, 6962, 11528, 5158, 4248, 4118, 5855, 2592, 5637, 6072, 2623, 7397, 8079, 9932, 4930, 5971, 853, 3633, 519, 8852, 11798, 3441, 11025, 1575, 225, 8810, 11792, 12218, 3501, 9278, 3081, 9218, 4828, 7712, 8124, 11694, 12204, 3499, 4011, 573, 3593, 5780, 7848, 9899, 10192, 1456, 208, 7052, 2763, 7417, 11593, 10434, 12024, 8740, 11782, 10461, 3250, 5731, 7841, 9898, 1414, 202, 3540, 7528, 2831, 2160, 10842, 5060, 4234, 4116, 588, 84, 12, 7024, 2759, 9172, 6577, 11473, 1639, 9012, 3043, 7457, 6332, 11438, 1634, 1989, 9062, 11828, 8712, 11778, 12216, 10523, 6770, 9745, 10170, 4964, 9487, 6622, 946, 8913, 6540, 6201, 4397, 9406, 8366, 9973, 8447, 8229, 11709, 8695, 10020, 3187, 5722, 2573, 10901, 6824, 4486, 4152, 9371, 8361, 2950, 2177, 311, 1800, 9035, 8313, 11721, 3430, 490, 70, 10, 1757, 251, 3547, 7529, 11609, 3414, 7510, 4584, 4166, 9373, 1339, 5458, 7802, 11648, 1664, 7260, 9815, 10180, 6721, 9738, 10169, 8475, 8233, 9954, 1422, 8981, 1283, 5450, 11312, 1616, 3742, 11068, 10359, 4991, 713, 3613, 9294, 8350, 4704, 672, 96, 7036, 9783, 11931, 3460, 5761, 823, 10651, 12055, 10500, 1500, 5481, 783, 3623, 11051, 8601, 8251, 8201, 11705, 10450, 5004, 4226, 7626, 2845, 2162, 3820, 7568, 9859, 3164, 452, 10598, 1514, 5483, 6050, 6131, 4387, 7649, 8115, 6426, 918, 8909, 8295, 1185, 5436, 11310, 8638, 1234, 5443, 11311, 5127, 2488, 2111, 10835, 5059, 7745, 2862, 3920, 560, 80, 1767, 2008, 3798, 11076, 6849, 2734, 10924, 12094, 8750, 1250, 10712, 6797, 971, 7161, 1023, 8924, 4786, 7706, 4612, 4170, 7618, 6355, 4419, 5898, 11376, 10403, 10264, 6733, 4473, 639, 5358, 2521, 9138, 3061, 5704, 4326, 618, 5355, 765, 5376, 768, 7132, 4530, 9425, 3102, 9221, 6584, 11474, 10417, 10266, 12000, 6981, 6264, 4406, 2385, 7363, 4563, 4163, 7617, 9866, 3165, 9230, 11852, 10471, 5007, 5982, 11388, 5138, 734, 3616, 11050, 12112, 6997, 11533, 12181, 10518, 12036, 3475, 2252, 7344, 9827, 4915, 9480, 6621, 4457, 7659, 9872, 6677, 4465, 4149, 7615, 4599, 657, 3605, 515, 10607, 6782, 4480, 640, 1847, 3775, 5806, 2585, 5636, 9583, 1369, 10729, 8555, 10000, 11962, 5220, 7768, 8132, 8184, 9947, 1421, 203, 29, 8782, 11788, 1684, 10774, 10317, 4985, 9490, 8378, 4708, 11206, 5112, 5997, 7879, 11659, 12199, 8765, 10030, 4944, 5973, 6120, 6141, 6144, 7900, 11662, 1666, 238, 34, 3516, 5769, 9602, 8394, 9977, 6692, 956, 10670, 6791, 9748, 11926, 8726, 11780, 5194, 742, 106, 8793, 10034, 3189, 10989, 5081, 4237, 5872, 4350, 2377, 10873, 6820, 6241, 11425, 10410, 10265, 3222, 5727, 9596, 4882, 2453, 2106, 3812, 11078, 12116, 5242, 4260, 11142, 8614, 11764, 12214, 5256, 4262, 4120, 11122, 5100, 11262, 5120, 2487, 5622, 9581, 8391, 8221, 2930, 10952, 12098, 6995, 6266, 9673, 4893, 699, 3611, 4027, 5842, 11368, 1624, 232, 8811, 8281, 1183, 169, 8802, 3013, 2186, 5579, 797, 3625, 4029, 11109, 1587, 7249, 11569, 8675, 6506, 2685, 10917, 12093, 12261, 12285, 1755, 7273, 1039, 1904, 272, 3550, 9285, 3082, 5707, 6082, 4380, 7648, 11626, 5172, 4250, 9385, 8363, 8217, 4685, 5936, 848, 8899, 6538, 934, 1889, 3781, 9318, 10109, 10222, 6727, 961, 5404, 772, 5377, 9546, 8386, 1198, 8949, 3034, 2189, 7335, 4559, 5918, 2601, 10905, 5069, 9502, 3113, 7467, 8089, 11689, 5181, 9518, 8382, 2953, 3933, 4073, 4093, 7607, 8109, 2914, 5683, 4323, 11151, 1593, 10761, 6804, 972, 3650, 2277, 5592, 4310, 7638, 9869, 4921, 703, 1856, 9043, 4803, 9464, 1352, 8971, 11815, 5199, 7765, 6376, 4422, 7654, 2849, 407, 8836, 6529, 7955, 2892, 9191, 1313, 10721, 12065, 12257, 1751, 9028, 8312, 2943, 2176, 3822, 546, 78, 8789, 11789, 10462, 12028, 6985, 4509, 9422, 1346, 5459, 4291, 613, 10621, 6784, 9747, 3148, 7472, 2823, 5670, 810, 7138, 8042, 4660, 7688, 6365, 6176, 6149, 2634, 5643, 9584, 10147, 11983, 5223, 9524, 11894, 10477, 8519, 1217, 3685, 2282, 326, 10580, 3267, 7489, 4581, 2410, 5611, 11335, 6886, 8006, 8166, 11700, 3427, 11023, 8597, 10006, 3185, 455, 65, 5276, 7776, 4622, 5927, 7869, 9902, 11948, 5218, 2501, 5624, 2559, 10899, 1557, 1978, 10816, 10323, 8497, 4725, 675, 1852, 10798, 12076, 10503, 3256, 9243, 3076, 2195, 10847, 12083, 10504, 12034, 10497 }; bitrev_vector(r->coeffs); ntt(r->coeffs, omegas_inv_montgomery); mul_coefficients(r->coeffs, psis_inv_montgomery); } inline void encode_a(uint8_t* r, const poly* pk, const uint8_t* seed) { poly_tobytes(r, pk); for(size_t i = 0; i < NEWHOPE_SEED_BYTES; i++) { r[NEWHOPE_POLY_BYTES+i] = seed[i]; } } inline void decode_a(poly* pk, uint8_t* seed, const uint8_t* r) { poly_frombytes(pk, r); for(size_t i = 0; i < NEWHOPE_SEED_BYTES; i++) { seed[i] = r[NEWHOPE_POLY_BYTES+i]; } } inline void encode_b(uint8_t* r, const poly* b, const poly* c) { poly_tobytes(r, b); for(size_t i = 0; i < PARAM_N/4; i++) { r[NEWHOPE_POLY_BYTES+i] = static_cast(c->coeffs[4*i] | (c->coeffs[4*i+1] << 2) | (c->coeffs[4*i+2] << 4) | (c->coeffs[4*i+3] << 6)); } } inline void decode_b(poly* b, poly* c, const uint8_t* r) { poly_frombytes(b, r); for(size_t i = 0; i < PARAM_N/4; i++) { c->coeffs[4*i+0] = r[NEWHOPE_POLY_BYTES+i] & 0x03; c->coeffs[4*i+1] = (r[NEWHOPE_POLY_BYTES+i] >> 2) & 0x03; c->coeffs[4*i+2] = (r[NEWHOPE_POLY_BYTES+i] >> 4) & 0x03; c->coeffs[4*i+3] = (r[NEWHOPE_POLY_BYTES+i] >> 6); } } inline int32_t ct_abs(int32_t v) { int32_t mask = v >> 31; return (v ^ mask) - mask; } inline int32_t f(int32_t* v0, int32_t* v1, int32_t x) { int32_t xit, t, r, b; // Next 6 lines compute t = x/PARAM_Q; b = x*2730; t = b >> 25; b = x - t*12289; b = 12288 - b; b >>= 31; t -= b; r = t & 1; xit = (t>>1); *v0 = xit+r; // v0 = round(x/(2*PARAM_Q)) t -= 1; r = t & 1; *v1 = (t>>1)+r; return ct_abs(x-((*v0)*2*PARAM_Q)); } inline void helprec(poly* c, const poly* v, RandomNumberGenerator& rng) { uint8_t rand[32]; rng.randomize(rand, 32); for(size_t i = 0; i < 256; i++) { int32_t v0[4], v1[4]; uint8_t rbit = (rand[i>>3] >> (i&7)) & 1; int32_t k; k = f(v0+0, v1+0, 8*v->coeffs[ 0+i] + 4*rbit); k += f(v0+1, v1+1, 8*v->coeffs[256+i] + 4*rbit); k += f(v0+2, v1+2, 8*v->coeffs[512+i] + 4*rbit); k += f(v0+3, v1+3, 8*v->coeffs[768+i] + 4*rbit); k = (2*PARAM_Q-1-k) >> 31; int32_t v_tmp[4]; v_tmp[0] = ((~k) & v0[0]) ^ (k & v1[0]); v_tmp[1] = ((~k) & v0[1]) ^ (k & v1[1]); v_tmp[2] = ((~k) & v0[2]) ^ (k & v1[2]); v_tmp[3] = ((~k) & v0[3]) ^ (k & v1[3]); c->coeffs[ 0+i] = (v_tmp[0] - v_tmp[3]) & 3; c->coeffs[256+i] = (v_tmp[1] - v_tmp[3]) & 3; c->coeffs[512+i] = (v_tmp[2] - v_tmp[3]) & 3; c->coeffs[768+i] = (- k + 2*v_tmp[3]) & 3; } } inline int32_t g(int32_t x) { int32_t t, c, b; // Next 6 lines compute t = x/(4*PARAM_Q); b = x*2730; t = b >> 27; b = x - t*49156; b = 49155 - b; b >>= 31; t -= b; c = t & 1; t = (t >> 1) + c; // t = round(x/(8*PARAM_Q)) t *= 8*PARAM_Q; return ct_abs(t - x); } inline int16_t LDDecode(int32_t xi0, int32_t xi1, int32_t xi2, int32_t xi3) { int32_t t; t = g(xi0); t += g(xi1); t += g(xi2); t += g(xi3); t -= 8*PARAM_Q; t >>= 31; return t&1; } inline void rec(uint8_t* key, const poly* v, const poly* c) { clear_mem(key, 32); for(size_t i = 0; i < 256; i++) { const int32_t tmp0 = 16*PARAM_Q + 8*static_cast(v->coeffs[ 0+i]) - PARAM_Q * (2*c->coeffs[ 0+i]+c->coeffs[768+i]); const int32_t tmp1 = 16*PARAM_Q + 8*static_cast(v->coeffs[256+i]) - PARAM_Q * (2*c->coeffs[256+i]+c->coeffs[768+i]); const int32_t tmp2 = 16*PARAM_Q + 8*static_cast(v->coeffs[512+i]) - PARAM_Q * (2*c->coeffs[512+i]+c->coeffs[768+i]); const int32_t tmp3 = 16*PARAM_Q + 8*static_cast(v->coeffs[768+i]) - PARAM_Q * (c->coeffs[768+i]); key[i>>3] |= LDDecode(tmp0, tmp1, tmp2, tmp3) << (i & 7); } } void gen_a(poly* a, const uint8_t* seed, Newhope_Mode mode) { std::vector buf(168*16); std::unique_ptr xof; if(mode == Newhope_Mode::BoringSSL) { xof = StreamCipher::create_or_throw("CTR-BE(AES-128)"); xof->set_key(seed, 16); xof->set_iv(seed + 16, 16); } else { xof = StreamCipher::create_or_throw("SHAKE-128"); xof->set_key(seed, NEWHOPE_SEED_BYTES); } zeroise(buf); xof->encrypt(buf); size_t pos = 0, ctr = 0; while(ctr < PARAM_N) { // Specialized for q = 12889 const uint16_t val = (buf[pos] | (static_cast(buf[pos+1]) << 8)) & 0x3fff; if(val < PARAM_Q) { a->coeffs[ctr++] = val; } pos += 2; if(pos >= buf.size()) { zeroise(buf); xof->encrypt(buf); pos = 0; } } } } // API FUNCTIONS void newhope_keygen(uint8_t* send, poly* sk, RandomNumberGenerator& rng, Newhope_Mode mode) { poly a, e, r, pk; uint8_t seed[NEWHOPE_SEED_BYTES]; rng.randomize(seed, NEWHOPE_SEED_BYTES); gen_a(&a, seed, mode); poly_getnoise(rng, sk); poly_ntt(sk); poly_getnoise(rng, &e); poly_ntt(&e); poly_pointwise(&r, sk, &a); poly_add(&pk, &e, &r); encode_a(send, &pk, seed); } void newhope_sharedb(uint8_t* sharedkey, uint8_t* send, const uint8_t* received, RandomNumberGenerator& rng, Newhope_Mode mode) { poly sp, ep, v, a, pka, c, epp, bp; uint8_t seed[NEWHOPE_SEED_BYTES]; decode_a(&pka, seed, received); gen_a(&a, seed, mode); poly_getnoise(rng, &sp); poly_ntt(&sp); poly_getnoise(rng, &ep); poly_ntt(&ep); poly_pointwise(&bp, &a, &sp); poly_add(&bp, &bp, &ep); poly_pointwise(&v, &pka, &sp); poly_invntt(&v); poly_getnoise(rng, &epp); poly_add(&v, &v, &epp); helprec(&c, &v, rng); encode_b(send, &bp, &c); rec(sharedkey, &v, &c); const std::string kdf_hash = (mode == Newhope_Mode::SHA3) ? "SHA-3(256)" : "SHA-256"; std::unique_ptr hash = HashFunction::create_or_throw(kdf_hash); hash->update(sharedkey, 32); hash->final(sharedkey); } void newhope_shareda(uint8_t sharedkey[], const poly* sk, const uint8_t received[], Newhope_Mode mode) { poly v, bp, c; decode_b(&bp, &c, received); poly_pointwise(&v, sk, &bp); poly_invntt(&v); rec(sharedkey, &v, &c); const std::string kdf_hash = (mode == Newhope_Mode::SHA3) ? "SHA-3(256)" : "SHA-256"; std::unique_ptr hash = HashFunction::create_or_throw(kdf_hash); hash->update(sharedkey, 32); hash->final(sharedkey); } } /* * (C) 2011,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { std::vector raw_nist_key_wrap(const uint8_t input[], size_t input_len, const BlockCipher& bc, uint64_t ICV) { const size_t n = (input_len + 7) / 8; secure_vector R((n + 1) * 8); secure_vector A(16); store_be(ICV, A.data()); copy_mem(&R[8], input, input_len); for(size_t j = 0; j <= 5; ++j) { for(size_t i = 1; i <= n; ++i) { const uint32_t t = static_cast((n * j) + i); copy_mem(&A[8], &R[8*i], 8); bc.encrypt(A.data()); copy_mem(&R[8*i], &A[8], 8); uint8_t t_buf[4] = { 0 }; store_be(t, t_buf); xor_buf(&A[4], t_buf, 4); } } copy_mem(R.data(), A.data(), 8); return std::vector(R.begin(), R.end()); } secure_vector raw_nist_key_unwrap(const uint8_t input[], size_t input_len, const BlockCipher& bc, uint64_t& ICV_out) { if(input_len < 16 || input_len % 8 != 0) throw Invalid_Argument("Bad input size for NIST key unwrap"); const size_t n = (input_len - 8) / 8; secure_vector R(n * 8); secure_vector A(16); for(size_t i = 0; i != 8; ++i) A[i] = input[i]; copy_mem(R.data(), input + 8, input_len - 8); for(size_t j = 0; j <= 5; ++j) { for(size_t i = n; i != 0; --i) { const uint32_t t = static_cast((5 - j) * n + i); uint8_t t_buf[4] = { 0 }; store_be(t, t_buf); xor_buf(&A[4], t_buf, 4); copy_mem(&A[8], &R[8*(i-1)], 8); bc.decrypt(A.data()); copy_mem(&R[8*(i-1)], &A[8], 8); } } ICV_out = load_be(A.data(), 0); return R; } } std::vector nist_key_wrap(const uint8_t input[], size_t input_len, const BlockCipher& bc) { if(bc.block_size() != 16) throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); if(input_len % 8 != 0) throw Invalid_Argument("Bad input size for NIST key wrap"); return raw_nist_key_wrap(input, input_len, bc, 0xA6A6A6A6A6A6A6A6); } secure_vector nist_key_unwrap(const uint8_t input[], size_t input_len, const BlockCipher& bc) { if(bc.block_size() != 16) throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); if(input_len < 16 || input_len % 8 != 0) throw Invalid_Argument("Bad input size for NIST key unwrap"); uint64_t ICV_out = 0; secure_vector R = raw_nist_key_unwrap(input, input_len, bc, ICV_out); if(ICV_out != 0xA6A6A6A6A6A6A6A6) throw Invalid_Authentication_Tag("NIST key unwrap failed"); return R; } std::vector nist_key_wrap_padded(const uint8_t input[], size_t input_len, const BlockCipher& bc) { if(bc.block_size() != 16) throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); const uint64_t ICV = 0xA65959A600000000 | static_cast(input_len); if(input_len <= 8) { /* * Special case for small inputs: if input <= 8 bytes just use ECB */ std::vector block(16); store_be(ICV, block.data()); copy_mem(block.data() + 8, input, input_len); bc.encrypt(block); return block; } else { return raw_nist_key_wrap(input, input_len, bc, ICV); } } secure_vector nist_key_unwrap_padded(const uint8_t input[], size_t input_len, const BlockCipher& bc) { if(bc.block_size() != 16) throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); if(input_len < 16 || input_len % 8 != 0) throw Invalid_Argument("Bad input size for NIST key unwrap"); uint64_t ICV_out = 0; secure_vector R; if(input_len == 16) { secure_vector block(input, input + input_len); bc.decrypt(block); ICV_out = load_be(block.data(), 0); R.resize(8); copy_mem(R.data(), block.data() + 8, 8); } else { R = raw_nist_key_unwrap(input, input_len, bc, ICV_out); } if((ICV_out >> 32) != 0xA65959A6) throw Invalid_Authentication_Tag("NIST key unwrap failed"); const size_t len = (ICV_out & 0xFFFFFFFF); if(R.size() < 8 || len > R.size() || len < R.size() - 8) throw Invalid_Authentication_Tag("NIST key unwrap failed"); const size_t padding = R.size() - len; for(size_t i = 0; i != padding; ++i) { if(R[R.size() - i - 1] != 0) throw Invalid_Authentication_Tag("NIST key unwrap failed"); } R.resize(R.size() - padding); return R; } } /* * Noekeon * (C) 1999-2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Noekeon's Theta Operation */ inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3, const uint32_t EK[4]) { uint32_t T = A0 ^ A2; T ^= rotl<8>(T) ^ rotr<8>(T); A1 ^= T; A3 ^= T; A0 ^= EK[0]; A1 ^= EK[1]; A2 ^= EK[2]; A3 ^= EK[3]; T = A1 ^ A3; T ^= rotl<8>(T) ^ rotr<8>(T); A0 ^= T; A2 ^= T; } /* * Theta With Null Key */ inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) { uint32_t T = A0 ^ A2; T ^= rotl<8>(T) ^ rotr<8>(T); A1 ^= T; A3 ^= T; T = A1 ^ A3; T ^= rotl<8>(T) ^ rotr<8>(T); A0 ^= T; A2 ^= T; } /* * Noekeon's Gamma S-Box Layer */ inline void gamma(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) { A1 ^= ~A3 & ~A2; A0 ^= A2 & A1; uint32_t T = A3; A3 = A0; A0 = T; A2 ^= A0 ^ A1 ^ A3; A1 ^= ~A3 & ~A2; A0 ^= A2 & A1; } } size_t Noekeon::parallelism() const { #if defined(BOTAN_HAS_NOEKEON_SIMD) if(CPUID::has_simd_32()) { return 4; } #endif return 1; } std::string Noekeon::provider() const { #if defined(BOTAN_HAS_NOEKEON_SIMD) if(CPUID::has_simd_32()) { return "simd"; } #endif return "base"; } /* * Noekeon Round Constants */ const uint8_t Noekeon::RC[] = { 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4 }; /* * Noekeon Encryption */ void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); #if defined(BOTAN_HAS_NOEKEON_SIMD) if(CPUID::has_simd_32()) { while(blocks >= 4) { simd_encrypt_4(in, out); in += 4 * BLOCK_SIZE; out += 4 * BLOCK_SIZE; blocks -= 4; } } #endif for(size_t i = 0; i != blocks; ++i) { uint32_t A0 = load_be(in, 0); uint32_t A1 = load_be(in, 1); uint32_t A2 = load_be(in, 2); uint32_t A3 = load_be(in, 3); for(size_t j = 0; j != 16; ++j) { A0 ^= RC[j]; theta(A0, A1, A2, A3, m_EK.data()); A1 = rotl<1>(A1); A2 = rotl<5>(A2); A3 = rotl<2>(A3); gamma(A0, A1, A2, A3); A1 = rotr<1>(A1); A2 = rotr<5>(A2); A3 = rotr<2>(A3); } A0 ^= RC[16]; theta(A0, A1, A2, A3, m_EK.data()); store_be(out, A0, A1, A2, A3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * Noekeon Encryption */ void Noekeon::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_DK.empty() == false); #if defined(BOTAN_HAS_NOEKEON_SIMD) if(CPUID::has_simd_32()) { while(blocks >= 4) { simd_decrypt_4(in, out); in += 4 * BLOCK_SIZE; out += 4 * BLOCK_SIZE; blocks -= 4; } } #endif for(size_t i = 0; i != blocks; ++i) { uint32_t A0 = load_be(in, 0); uint32_t A1 = load_be(in, 1); uint32_t A2 = load_be(in, 2); uint32_t A3 = load_be(in, 3); for(size_t j = 16; j != 0; --j) { theta(A0, A1, A2, A3, m_DK.data()); A0 ^= RC[j]; A1 = rotl<1>(A1); A2 = rotl<5>(A2); A3 = rotl<2>(A3); gamma(A0, A1, A2, A3); A1 = rotr<1>(A1); A2 = rotr<5>(A2); A3 = rotr<2>(A3); } theta(A0, A1, A2, A3, m_DK.data()); A0 ^= RC[0]; store_be(out, A0, A1, A2, A3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * Noekeon Key Schedule */ void Noekeon::key_schedule(const uint8_t key[], size_t) { uint32_t A0 = load_be(key, 0); uint32_t A1 = load_be(key, 1); uint32_t A2 = load_be(key, 2); uint32_t A3 = load_be(key, 3); for(size_t i = 0; i != 16; ++i) { A0 ^= RC[i]; theta(A0, A1, A2, A3); A1 = rotl<1>(A1); A2 = rotl<5>(A2); A3 = rotl<2>(A3); gamma(A0, A1, A2, A3); A1 = rotr<1>(A1); A2 = rotr<5>(A2); A3 = rotr<2>(A3); } A0 ^= RC[16]; m_DK.resize(4); m_DK[0] = A0; m_DK[1] = A1; m_DK[2] = A2; m_DK[3] = A3; theta(A0, A1, A2, A3); m_EK.resize(4); m_EK[0] = A0; m_EK[1] = A1; m_EK[2] = A2; m_EK[3] = A3; } /* * Clear memory of sensitive data */ void Noekeon::clear() { zap(m_EK); zap(m_DK); } } /* * Noekeon in SIMD * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Noekeon's Theta Operation */ #define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3) \ do { \ SIMD_4x32 T = A0 ^ A2; \ T ^= T.rotl<8>() ^ T.rotr<8>(); \ A1 ^= T; \ A3 ^= T; \ \ A0 ^= K0; \ A1 ^= K1; \ A2 ^= K2; \ A3 ^= K3; \ \ T = A1 ^ A3; \ T ^= T.rotl<8>() ^ T.rotr<8>(); \ A0 ^= T; \ A2 ^= T; \ } while(0) /* * Noekeon's Gamma S-Box Layer */ #define NOK_SIMD_GAMMA(A0, A1, A2, A3) \ do \ { \ A1 ^= A3.andc(~A2); \ A0 ^= A2 & A1; \ \ SIMD_4x32 T = A3; \ A3 = A0; \ A0 = T; \ \ A2 ^= A0 ^ A1 ^ A3; \ \ A1 ^= A3.andc(~A2); \ A0 ^= A2 & A1; \ } while(0) /* * Noekeon Encryption */ void Noekeon::simd_encrypt_4(const uint8_t in[], uint8_t out[]) const { const SIMD_4x32 K0 = SIMD_4x32::splat(m_EK[0]); const SIMD_4x32 K1 = SIMD_4x32::splat(m_EK[1]); const SIMD_4x32 K2 = SIMD_4x32::splat(m_EK[2]); const SIMD_4x32 K3 = SIMD_4x32::splat(m_EK[3]); SIMD_4x32 A0 = SIMD_4x32::load_be(in ); SIMD_4x32 A1 = SIMD_4x32::load_be(in + 16); SIMD_4x32 A2 = SIMD_4x32::load_be(in + 32); SIMD_4x32 A3 = SIMD_4x32::load_be(in + 48); SIMD_4x32::transpose(A0, A1, A2, A3); for(size_t i = 0; i != 16; ++i) { A0 ^= SIMD_4x32::splat(RC[i]); NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); A1 = A1.rotl<1>(); A2 = A2.rotl<5>(); A3 = A3.rotl<2>(); NOK_SIMD_GAMMA(A0, A1, A2, A3); A1 = A1.rotr<1>(); A2 = A2.rotr<5>(); A3 = A3.rotr<2>(); } A0 ^= SIMD_4x32::splat(RC[16]); NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); SIMD_4x32::transpose(A0, A1, A2, A3); A0.store_be(out); A1.store_be(out + 16); A2.store_be(out + 32); A3.store_be(out + 48); } /* * Noekeon Encryption */ void Noekeon::simd_decrypt_4(const uint8_t in[], uint8_t out[]) const { const SIMD_4x32 K0 = SIMD_4x32::splat(m_DK[0]); const SIMD_4x32 K1 = SIMD_4x32::splat(m_DK[1]); const SIMD_4x32 K2 = SIMD_4x32::splat(m_DK[2]); const SIMD_4x32 K3 = SIMD_4x32::splat(m_DK[3]); SIMD_4x32 A0 = SIMD_4x32::load_be(in ); SIMD_4x32 A1 = SIMD_4x32::load_be(in + 16); SIMD_4x32 A2 = SIMD_4x32::load_be(in + 32); SIMD_4x32 A3 = SIMD_4x32::load_be(in + 48); SIMD_4x32::transpose(A0, A1, A2, A3); for(size_t i = 0; i != 16; ++i) { NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); A0 ^= SIMD_4x32::splat(RC[16-i]); A1 = A1.rotl<1>(); A2 = A2.rotl<5>(); A3 = A3.rotl<2>(); NOK_SIMD_GAMMA(A0, A1, A2, A3); A1 = A1.rotr<1>(); A2 = A2.rotr<5>(); A3 = A3.rotr<2>(); } NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); A0 ^= SIMD_4x32::splat(RC[0]); SIMD_4x32::transpose(A0, A1, A2, A3); A0.store_be(out); A1.store_be(out + 16); A2.store_be(out + 32); A3.store_be(out + 48); } } /* * DSA Parameter Generation * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Check if this size is allowed by FIPS 186-3 */ bool fips186_3_valid_size(size_t pbits, size_t qbits) { if(qbits == 160) return (pbits == 1024); if(qbits == 224) return (pbits == 2048); if(qbits == 256) return (pbits == 2048 || pbits == 3072); return false; } } /* * Attempt DSA prime generation with given seed */ bool generate_dsa_primes(RandomNumberGenerator& rng, BigInt& p, BigInt& q, size_t pbits, size_t qbits, const std::vector& seed_c, size_t offset) { if(!fips186_3_valid_size(pbits, qbits)) throw Invalid_Argument( "FIPS 186-3 does not allow DSA domain parameters of " + std::to_string(pbits) + "/" + std::to_string(qbits) + " bits long"); if(seed_c.size() * 8 < qbits) throw Invalid_Argument( "Generating a DSA parameter set with a " + std::to_string(qbits) + " bit long q requires a seed at least as many bits long"); const std::string hash_name = "SHA-" + std::to_string(qbits); std::unique_ptr hash(HashFunction::create_or_throw(hash_name)); const size_t HASH_SIZE = hash->output_length(); class Seed final { public: explicit Seed(const std::vector& s) : m_seed(s) {} const std::vector& value() const { return m_seed; } Seed& operator++() { for(size_t j = m_seed.size(); j > 0; --j) if(++m_seed[j-1]) break; return (*this); } private: std::vector m_seed; }; Seed seed(seed_c); q.binary_decode(hash->process(seed.value())); q.set_bit(qbits-1); q.set_bit(0); if(!is_prime(q, rng, 128, true)) return false; const size_t n = (pbits-1) / (HASH_SIZE * 8), b = (pbits-1) % (HASH_SIZE * 8); BigInt X; std::vector V(HASH_SIZE * (n+1)); Modular_Reducer mod_2q(2*q); for(size_t j = 0; j != 4*pbits; ++j) { for(size_t k = 0; k <= n; ++k) { ++seed; hash->update(seed.value()); hash->final(&V[HASH_SIZE * (n-k)]); } if(j >= offset) { X.binary_decode(&V[HASH_SIZE - 1 - b/8], V.size() - (HASH_SIZE - 1 - b/8)); X.set_bit(pbits-1); p = X - (mod_2q.reduce(X) - 1); if(p.bits() == pbits && is_prime(p, rng, 128, true)) return true; } } return false; } /* * Generate DSA Primes */ std::vector generate_dsa_primes(RandomNumberGenerator& rng, BigInt& p, BigInt& q, size_t pbits, size_t qbits) { while(true) { std::vector seed(qbits / 8); rng.randomize(seed.data(), seed.size()); if(generate_dsa_primes(rng, p, q, pbits, qbits, seed)) return seed; } } } /* * Jacobi Function * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Calculate the Jacobi symbol */ int32_t jacobi(const BigInt& a, const BigInt& n) { if(n.is_even() || n < 2) throw Invalid_Argument("jacobi: second argument must be odd and > 1"); BigInt x = a % n; BigInt y = n; int32_t J = 1; while(y > 1) { x %= y; if(x > y / 2) { x = y - x; if(y % 4 == 3) J = -J; } if(x.is_zero()) return 0; size_t shifts = low_zero_bits(x); x >>= shifts; if(shifts % 2) { word y_mod_8 = y % 8; if(y_mod_8 == 3 || y_mod_8 == 5) J = -J; } if(x % 4 == 3 && y % 4 == 3) J = -J; std::swap(x, y); } return J; } } /* * Prime Generation * (C) 1999-2007,2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { class Prime_Sieve final { public: Prime_Sieve(const BigInt& init_value, size_t sieve_size) : m_sieve(std::min(sieve_size, PRIME_TABLE_SIZE)) { for(size_t i = 0; i != m_sieve.size(); ++i) m_sieve[i] = static_cast(init_value % PRIMES[i]); } void step(word increment) { for(size_t i = 0; i != m_sieve.size(); ++i) { m_sieve[i] = (m_sieve[i] + increment) % PRIMES[i]; } } bool passes(bool check_2p1 = false) const { for(size_t i = 0; i != m_sieve.size(); ++i) { /* In this case, p is a multiple of PRIMES[i] */ if(m_sieve[i] == 0) return false; if(check_2p1) { /* In this case, 2*p+1 will be a multiple of PRIMES[i] So if potentially generating a safe prime, we want to avoid this value because 2*p+1 will certainly not be prime. See "Safe Prime Generation with a Combined Sieve" M. Wiener https://eprint.iacr.org/2003/186.pdf */ if(m_sieve[i] == (PRIMES[i] - 1) / 2) return false; } } return true; } private: std::vector m_sieve; }; } /* * Generate a random prime */ BigInt random_prime(RandomNumberGenerator& rng, size_t bits, const BigInt& coprime, size_t equiv, size_t modulo, size_t prob) { if(bits <= 1) { throw Invalid_Argument("random_prime: Can't make a prime of " + std::to_string(bits) + " bits"); } if(coprime.is_negative() || (!coprime.is_zero() && coprime.is_even()) || coprime.bits() >= bits) { throw Invalid_Argument("random_prime: invalid coprime"); } if(modulo == 0) { throw Invalid_Argument("random_prime: Invalid modulo value"); } equiv %= modulo; if(equiv == 0) throw Invalid_Argument("random_prime Invalid value for equiv/modulo"); // Handle small values: if(bits <= 16) { if(equiv != 1 || modulo != 2 || coprime != 0) throw Not_Implemented("random_prime equiv/modulo/coprime options not usable for small primes"); if(bits == 2) { return ((rng.next_byte() % 2) ? 2 : 3); } else if(bits == 3) { return ((rng.next_byte() % 2) ? 5 : 7); } else if(bits == 4) { return ((rng.next_byte() % 2) ? 11 : 13); } else { for(;;) { // This is slightly biased, but for small primes it does not seem to matter uint8_t b[4]; rng.randomize(b, 4); const size_t idx = load_le(b, 0) % PRIME_TABLE_SIZE; const uint16_t small_prime = PRIMES[idx]; if(high_bit(small_prime) == bits) return small_prime; } } } const size_t MAX_ATTEMPTS = 32*1024; const size_t mr_trials = miller_rabin_test_iterations(bits, prob, true); while(true) { BigInt p(rng, bits); // Force lowest and two top bits on p.set_bit(bits - 1); p.set_bit(bits - 2); p.set_bit(0); // Force p to be equal to equiv mod modulo p += (modulo - (p % modulo)) + equiv; Prime_Sieve sieve(p, bits); for(size_t attempt = 0; attempt <= MAX_ATTEMPTS; ++attempt) { p += modulo; sieve.step(modulo); // p can be even if modulo is odd, continue on in that case if(p.is_even() || sieve.passes(true) == false) continue; Modular_Reducer mod_p(p); if(coprime > 1) { /* First do a single M-R iteration to quickly elimate most non-primes, before doing the coprimality check which is expensive */ if(is_miller_rabin_probable_prime(p, mod_p, rng, 1) == false) continue; /* * Check if p - 1 and coprime are relatively prime, using gcd. * The gcd computation is const-time */ if(gcd(p - 1, coprime) > 1) continue; } if(p.bits() > bits) break; if(is_miller_rabin_probable_prime(p, mod_p, rng, mr_trials) == false) continue; if(prob > 32 && !is_lucas_probable_prime(p, mod_p)) continue; return p; } } } BigInt generate_rsa_prime(RandomNumberGenerator& keygen_rng, RandomNumberGenerator& prime_test_rng, size_t bits, const BigInt& coprime, size_t prob) { if(bits < 512) throw Invalid_Argument("generate_rsa_prime bits too small"); /* * The restriction on coprime <= 64 bits is arbitrary but generally speaking * very large RSA public exponents are a bad idea both for performance and due * to attacks on small d. */ if(coprime <= 1 || coprime.is_even() || coprime.bits() > 64) throw Invalid_Argument("generate_rsa_prime coprime must be small odd positive integer"); const size_t MAX_ATTEMPTS = 32*1024; const size_t mr_trials = miller_rabin_test_iterations(bits, prob, true); while(true) { BigInt p(keygen_rng, bits); // Force high two bits so multiplication always results in expected n bit integer p.set_bit(bits - 1); p.set_bit(bits - 2); p.set_bit(0); const word step = 2; Prime_Sieve sieve(p, bits); for(size_t attempt = 0; attempt <= MAX_ATTEMPTS; ++attempt) { p += step; sieve.step(step); if(sieve.passes() == false) continue; Modular_Reducer mod_p(p); /* * Do a single primality test first before checking coprimality, since * currently a single Miller-Rabin test is faster than computing gcd, * and this eliminates almost all wasted gcd computations. */ if(is_miller_rabin_probable_prime(p, mod_p, prime_test_rng, 1) == false) continue; /* * Check if p - 1 and coprime are relatively prime. */ if(gcd(p - 1, coprime) > 1) continue; if(p.bits() > bits) break; if(is_miller_rabin_probable_prime(p, mod_p, prime_test_rng, mr_trials) == true) return p; } } } /* * Generate a random safe prime */ BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) { if(bits <= 64) throw Invalid_Argument("random_safe_prime: Can't make a prime of " + std::to_string(bits) + " bits"); const size_t error_bound = 128; BigInt q, p; for(;;) { /* Generate q == 2 (mod 3), since otherwise [in the case of q == 1 (mod 3)], 2*q+1 == 3 (mod 3) and so certainly not prime. */ q = random_prime(rng, bits - 1, 0, 2, 3, error_bound); p = (q << 1) + 1; if(is_prime(p, rng, error_bound, true)) { return p; } } } } /* * (C) 1999-2011,2016,2018,2019,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* Sets result to a^-1 * 2^k mod a with n <= k <= 2n Returns k "The Montgomery Modular Inverse - Revisited" Çetin Koç, E. Savas https://citeseerx.ist.psu.edu/viewdoc/citations?doi=10.1.1.75.8377 A const time implementation of this algorithm is described in "Constant Time Modular Inversion" Joppe W. Bos http://www.joppebos.com/files/CTInversion.pdf */ size_t almost_montgomery_inverse(BigInt& result, const BigInt& a, const BigInt& p) { size_t k = 0; BigInt u = p, v = a, r = 0, s = 1; while(v > 0) { if(u.is_even()) { u >>= 1; s <<= 1; } else if(v.is_even()) { v >>= 1; r <<= 1; } else if(u > v) { u -= v; u >>= 1; r += s; s <<= 1; } else { v -= u; v >>= 1; s += r; r <<= 1; } ++k; } if(r >= p) { r -= p; } result = p - r; return k; } BigInt normalized_montgomery_inverse(const BigInt& a, const BigInt& p) { BigInt r; size_t k = almost_montgomery_inverse(r, a, p); for(size_t i = 0; i != k; ++i) { if(r.is_odd()) r += p; r >>= 1; } return r; } namespace { BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) { // Caller should assure these preconditions: BOTAN_DEBUG_ASSERT(n.is_positive()); BOTAN_DEBUG_ASSERT(mod.is_positive()); BOTAN_DEBUG_ASSERT(n < mod); BOTAN_DEBUG_ASSERT(mod >= 3 && mod.is_odd()); /* This uses a modular inversion algorithm designed by Niels Möller and implemented in Nettle. The same algorithm was later also adapted to GMP in mpn_sec_invert. It can be easily implemented in a way that does not depend on secret branches or memory lookups, providing resistance against some forms of side channel attack. There is also a description of the algorithm in Appendix 5 of "Fast Software Polynomial Multiplication on ARM Processors using the NEON Engine" by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo Dahab in LNCS 8182 https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf Thanks to Niels for creating the algorithm, explaining some things about it, and the reference to the paper. */ const size_t mod_words = mod.sig_words(); BOTAN_ASSERT(mod_words > 0, "Not empty"); secure_vector tmp_mem(5*mod_words); word* v_w = &tmp_mem[0]; word* u_w = &tmp_mem[1*mod_words]; word* b_w = &tmp_mem[2*mod_words]; word* a_w = &tmp_mem[3*mod_words]; word* mp1o2 = &tmp_mem[4*mod_words]; CT::poison(tmp_mem.data(), tmp_mem.size()); copy_mem(a_w, n.data(), std::min(n.size(), mod_words)); copy_mem(b_w, mod.data(), std::min(mod.size(), mod_words)); u_w[0] = 1; // v_w = 0 // compute (mod + 1) / 2 which [because mod is odd] is equal to // (mod / 2) + 1 copy_mem(mp1o2, mod.data(), std::min(mod.size(), mod_words)); bigint_shr1(mp1o2, mod_words, 0, 1); word carry = bigint_add2_nc(mp1o2, mod_words, u_w, 1); BOTAN_ASSERT_NOMSG(carry == 0); // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n const size_t execs = 2 * mod.bits(); for(size_t i = 0; i != execs; ++i) { const word odd_a = a_w[0] & 1; //if(odd_a) a -= b word underflow = bigint_cnd_sub(odd_a, a_w, b_w, mod_words); //if(underflow) { b -= a; a = abs(a); swap(u, v); } bigint_cnd_add(underflow, b_w, a_w, mod_words); bigint_cnd_abs(underflow, a_w, mod_words); bigint_cnd_swap(underflow, u_w, v_w, mod_words); // a >>= 1 bigint_shr1(a_w, mod_words, 0, 1); //if(odd_a) u -= v; word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words); // if(borrow) u += p bigint_cnd_add(borrow, u_w, mod.data(), mod_words); const word odd_u = u_w[0] & 1; // u >>= 1 bigint_shr1(u_w, mod_words, 0, 1); //if(odd_u) u += mp1o2; bigint_cnd_add(odd_u, u_w, mp1o2, mod_words); } auto a_is_0 = CT::Mask::set(); for(size_t i = 0; i != mod_words; ++i) a_is_0 &= CT::Mask::is_zero(a_w[i]); auto b_is_1 = CT::Mask::is_equal(b_w[0], 1); for(size_t i = 1; i != mod_words; ++i) b_is_1 &= CT::Mask::is_zero(b_w[i]); BOTAN_ASSERT(a_is_0.is_set(), "A is zero"); // if b != 1 then gcd(n,mod) > 1 and inverse does not exist // in which case zero out the result to indicate this (~b_is_1).if_set_zero_out(v_w, mod_words); /* * We've placed the result in the lowest words of the temp buffer. * So just clear out the other values and then give that buffer to a * BigInt. */ clear_mem(&tmp_mem[mod_words], 4*mod_words); CT::unpoison(tmp_mem.data(), tmp_mem.size()); BigInt r; r.swap_reg(tmp_mem); return r; } BigInt inverse_mod_pow2(const BigInt& a1, size_t k) { /* * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç * https://eprint.iacr.org/2017/411.pdf sections 5 and 7. */ if(a1.is_even()) return 0; BigInt a = a1; a.mask_bits(k); BigInt b = 1; BigInt X = 0; BigInt newb; const size_t a_words = a.sig_words(); X.grow_to(round_up(k, BOTAN_MP_WORD_BITS) / BOTAN_MP_WORD_BITS); b.grow_to(a_words); /* Hide the exact value of k. k is anyway known to word length granularity because of the length of a, so no point in doing more than this. */ const size_t iter = round_up(k, BOTAN_MP_WORD_BITS); for(size_t i = 0; i != iter; ++i) { const bool b0 = b.get_bit(0); X.conditionally_set_bit(i, b0); newb = b - a; b.ct_cond_assign(b0, newb); b >>= 1; } X.mask_bits(k); X.const_time_unpoison(); return X; } } BigInt inverse_mod(const BigInt& n, const BigInt& mod) { if(mod.is_zero()) throw BigInt::DivideByZero(); if(mod.is_negative() || n.is_negative()) throw Invalid_Argument("inverse_mod: arguments must be non-negative"); if(n.is_zero() || (n.is_even() && mod.is_even())) return 0; if(mod.is_odd()) { /* Fastpath for common case. This leaks information if n > mod but we don't guarantee const time behavior in that case. */ if(n < mod) return inverse_mod_odd_modulus(n, mod); else return inverse_mod_odd_modulus(ct_modulo(n, mod), mod); } const size_t mod_lz = low_zero_bits(mod); BOTAN_ASSERT_NOMSG(mod_lz > 0); const size_t mod_bits = mod.bits(); BOTAN_ASSERT_NOMSG(mod_bits > mod_lz); if(mod_lz == mod_bits - 1) { // In this case we are performing an inversion modulo 2^k return inverse_mod_pow2(n, mod_lz); } /* * In this case we are performing an inversion modulo 2^k*o for * some k > 1 and some odd (not necessarily prime) integer. * Compute the inversions modulo 2^k and modulo o, then combine them * using CRT, which is possible because 2^k and o are relatively prime. */ const BigInt o = mod >> mod_lz; const BigInt n_redc = ct_modulo(n, o); const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o); const BigInt inv_2k = inverse_mod_pow2(n, mod_lz); // No modular inverse in this case: if(inv_o == 0 || inv_2k == 0) return 0; const BigInt m2k = BigInt::power_of_2(mod_lz); // Compute the CRT parameter const BigInt c = inverse_mod_pow2(o, mod_lz); // Compute h = c*(inv_2k-inv_o) mod 2^k BigInt h = c * (inv_2k - inv_o); const bool h_neg = h.is_negative(); h.set_sign(BigInt::Positive); h.mask_bits(mod_lz); const bool h_nonzero = h.is_nonzero(); h.ct_cond_assign(h_nonzero && h_neg, m2k - h); // Return result inv_o + h * o h *= o; h += inv_o; return h; } // Deprecated forwarding functions: BigInt inverse_euclid(const BigInt& x, const BigInt& modulus) { return inverse_mod(x, modulus); } BigInt ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) { return inverse_mod_odd_modulus(n, mod); } word monty_inverse(word a) { if(a % 2 == 0) throw Invalid_Argument("monty_inverse only valid for odd integers"); /* * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç * https://eprint.iacr.org/2017/411.pdf sections 5 and 7. */ word b = 1; word r = 0; for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i) { const word bi = b % 2; r >>= 1; r += bi << (BOTAN_MP_WORD_BITS - 1); b -= a * bi; b >>= 1; } // Now invert in addition space r = (MP_WORD_MAX - r) + 1; return r; } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Montgomery_Params::Montgomery_Params(const BigInt& p, const Modular_Reducer& mod_p) { if(p.is_even() || p < 3) throw Invalid_Argument("Montgomery_Params invalid modulus"); m_p = p; m_p_words = m_p.sig_words(); m_p_dash = monty_inverse(m_p.word_at(0)); const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); m_r1 = mod_p.reduce(r); m_r2 = mod_p.square(m_r1); m_r3 = mod_p.multiply(m_r1, m_r2); } Montgomery_Params::Montgomery_Params(const BigInt& p) { if(p.is_negative() || p.is_even()) throw Invalid_Argument("Montgomery_Params invalid modulus"); m_p = p; m_p_words = m_p.sig_words(); m_p_dash = monty_inverse(m_p.word_at(0)); const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); // It might be faster to use ct_modulo here vs setting up Barrett reduction? Modular_Reducer mod_p(p); m_r1 = mod_p.reduce(r); m_r2 = mod_p.square(m_r1); m_r3 = mod_p.multiply(m_r1, m_r2); } BigInt Montgomery_Params::inv_mod_p(const BigInt& x) const { // TODO use Montgomery inverse here? return inverse_mod(x, p()); } BigInt Montgomery_Params::redc(const BigInt& x, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < output_size) ws.resize(output_size); BigInt z = x; z.grow_to(output_size); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); return z; } BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < output_size) ws.resize(output_size); BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); BigInt z(BigInt::Positive, output_size); bigint_mul(z.mutable_data(), z.size(), x.data(), x.size(), std::min(m_p_words, x.size()), y.data(), y.size(), std::min(m_p_words, y.size()), ws.data(), ws.size()); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); return z; } BigInt Montgomery_Params::mul(const BigInt& x, const secure_vector& y, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < output_size) ws.resize(output_size); BigInt z(BigInt::Positive, output_size); BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); bigint_mul(z.mutable_data(), z.size(), x.data(), x.size(), std::min(m_p_words, x.size()), y.data(), y.size(), std::min(m_p_words, y.size()), ws.data(), ws.size()); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); return z; } void Montgomery_Params::mul_by(BigInt& x, const secure_vector& y, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < 2*output_size) ws.resize(2*output_size); word* z_data = &ws[0]; word* ws_data = &ws[output_size]; BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); bigint_mul(z_data, output_size, x.data(), x.size(), std::min(m_p_words, x.size()), y.data(), y.size(), std::min(m_p_words, y.size()), ws_data, output_size); bigint_monty_redc(z_data, m_p.data(), m_p_words, m_p_dash, ws_data, output_size); if(x.size() < output_size) x.grow_to(output_size); copy_mem(x.mutable_data(), z_data, output_size); } void Montgomery_Params::mul_by(BigInt& x, const BigInt& y, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < 2*output_size) ws.resize(2*output_size); word* z_data = &ws[0]; word* ws_data = &ws[output_size]; BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); bigint_mul(z_data, output_size, x.data(), x.size(), std::min(m_p_words, x.size()), y.data(), y.size(), std::min(m_p_words, y.size()), ws_data, output_size); bigint_monty_redc(z_data, m_p.data(), m_p_words, m_p_dash, ws_data, output_size); if(x.size() < output_size) x.grow_to(output_size); copy_mem(x.mutable_data(), z_data, output_size); } BigInt Montgomery_Params::sqr(const BigInt& x, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < output_size) ws.resize(output_size); BigInt z(BigInt::Positive, output_size); BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); bigint_sqr(z.mutable_data(), z.size(), x.data(), x.size(), std::min(m_p_words, x.size()), ws.data(), ws.size()); bigint_monty_redc(z.mutable_data(), m_p.data(), m_p_words, m_p_dash, ws.data(), ws.size()); return z; } void Montgomery_Params::square_this(BigInt& x, secure_vector& ws) const { const size_t output_size = 2*m_p_words + 2; if(ws.size() < 2*output_size) ws.resize(2*output_size); word* z_data = &ws[0]; word* ws_data = &ws[output_size]; BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); bigint_sqr(z_data, output_size, x.data(), x.size(), std::min(m_p_words, x.size()), ws_data, output_size); bigint_monty_redc(z_data, m_p.data(), m_p_words, m_p_dash, ws_data, output_size); if(x.size() < output_size) x.grow_to(output_size); copy_mem(x.mutable_data(), z_data, output_size); } Montgomery_Int::Montgomery_Int(const std::shared_ptr params, const BigInt& v, bool redc_needed) : m_params(params) { if(redc_needed == false) { m_v = v; } else { BOTAN_ASSERT_NOMSG(m_v < m_params->p()); secure_vector ws; m_v = m_params->mul(v, m_params->R2(), ws); } } Montgomery_Int::Montgomery_Int(std::shared_ptr params, const uint8_t bits[], size_t len, bool redc_needed) : m_params(params), m_v(bits, len) { if(redc_needed) { BOTAN_ASSERT_NOMSG(m_v < m_params->p()); secure_vector ws; m_v = m_params->mul(m_v, m_params->R2(), ws); } } Montgomery_Int::Montgomery_Int(std::shared_ptr params, const word words[], size_t len, bool redc_needed) : m_params(params), m_v(words, len) { if(redc_needed) { BOTAN_ASSERT_NOMSG(m_v < m_params->p()); secure_vector ws; m_v = m_params->mul(m_v, m_params->R2(), ws); } } void Montgomery_Int::fix_size() { const size_t p_words = m_params->p_words(); if(m_v.sig_words() > p_words) throw Internal_Error("Montgomery_Int::fix_size v too large"); m_v.grow_to(p_words); } bool Montgomery_Int::operator==(const Montgomery_Int& other) const { return m_v == other.m_v && m_params->p() == other.m_params->p(); } std::vector Montgomery_Int::serialize() const { std::vector v(size()); BigInt::encode_1363(v.data(), v.size(), value()); return v; } size_t Montgomery_Int::size() const { return m_params->p().bytes(); } bool Montgomery_Int::is_one() const { return m_v == m_params->R1(); } bool Montgomery_Int::is_zero() const { return m_v.is_zero(); } BigInt Montgomery_Int::value() const { secure_vector ws; return m_params->redc(m_v, ws); } Montgomery_Int Montgomery_Int::operator+(const Montgomery_Int& other) const { secure_vector ws; BigInt z = m_v; z.mod_add(other.m_v, m_params->p(), ws); return Montgomery_Int(m_params, z, false); } Montgomery_Int Montgomery_Int::operator-(const Montgomery_Int& other) const { secure_vector ws; BigInt z = m_v; z.mod_sub(other.m_v, m_params->p(), ws); return Montgomery_Int(m_params, z, false); } Montgomery_Int& Montgomery_Int::operator+=(const Montgomery_Int& other) { secure_vector ws; return this->add(other, ws); } Montgomery_Int& Montgomery_Int::add(const Montgomery_Int& other, secure_vector& ws) { m_v.mod_add(other.m_v, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::operator-=(const Montgomery_Int& other) { secure_vector ws; return this->sub(other, ws); } Montgomery_Int& Montgomery_Int::sub(const Montgomery_Int& other, secure_vector& ws) { m_v.mod_sub(other.m_v, m_params->p(), ws); return (*this); } Montgomery_Int Montgomery_Int::operator*(const Montgomery_Int& other) const { secure_vector ws; return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false); } Montgomery_Int Montgomery_Int::mul(const Montgomery_Int& other, secure_vector& ws) const { return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false); } Montgomery_Int& Montgomery_Int::mul_by(const Montgomery_Int& other, secure_vector& ws) { m_params->mul_by(m_v, other.m_v, ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by(const secure_vector& other, secure_vector& ws) { m_params->mul_by(m_v, other, ws); return (*this); } Montgomery_Int& Montgomery_Int::operator*=(const Montgomery_Int& other) { secure_vector ws; return mul_by(other, ws); } Montgomery_Int& Montgomery_Int::operator*=(const secure_vector& other) { secure_vector ws; return mul_by(other, ws); } Montgomery_Int& Montgomery_Int::square_this_n_times(secure_vector& ws, size_t n) { for(size_t i = 0; i != n; ++i) m_params->square_this(m_v, ws); return (*this); } Montgomery_Int& Montgomery_Int::square_this(secure_vector& ws) { m_params->square_this(m_v, ws); return (*this); } Montgomery_Int Montgomery_Int::square(secure_vector& ws) const { return Montgomery_Int(m_params, m_params->sqr(m_v, ws), false); } Montgomery_Int Montgomery_Int::multiplicative_inverse() const { secure_vector ws; const BigInt iv = m_params->mul(m_params->inv_mod_p(m_v), m_params->R3(), ws); return Montgomery_Int(m_params, iv, false); } Montgomery_Int Montgomery_Int::additive_inverse() const { return Montgomery_Int(m_params, m_params->p()) - (*this); } Montgomery_Int& Montgomery_Int::mul_by_2(secure_vector& ws) { m_v.mod_mul(2, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by_3(secure_vector& ws) { m_v.mod_mul(3, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by_4(secure_vector& ws) { m_v.mod_mul(4, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by_8(secure_vector& ws) { m_v.mod_mul(8, m_params->p(), ws); return (*this); } } /* * Montgomery Exponentiation * (C) 1999-2010,2012,2018 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { class Montgomery_Exponentation_State { public: Montgomery_Exponentation_State(std::shared_ptr params, const BigInt& g, size_t window_bits, bool const_time); BigInt exponentiation(const BigInt& k, size_t max_k_bits) const; BigInt exponentiation_vartime(const BigInt& k) const; private: std::shared_ptr m_params; std::vector m_g; size_t m_window_bits; bool m_const_time; }; Montgomery_Exponentation_State::Montgomery_Exponentation_State(std::shared_ptr params, const BigInt& g, size_t window_bits, bool const_time) : m_params(params), m_window_bits(window_bits == 0 ? 4 : window_bits), m_const_time(const_time) { BOTAN_ARG_CHECK(g < m_params->p(), "Montgomery base too big"); if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ... throw Invalid_Argument("Invalid window bits for Montgomery exponentiation"); const size_t window_size = (static_cast(1) << m_window_bits); m_g.reserve(window_size); m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false)); m_g.push_back(Montgomery_Int(m_params, g)); for(size_t i = 2; i != window_size; ++i) { m_g.push_back(m_g[1] * m_g[i - 1]); } // Resize each element to exactly p words for(size_t i = 0; i != window_size; ++i) { m_g[i].fix_size(); if(const_time) m_g[i].const_time_poison(); } } namespace { void const_time_lookup(secure_vector& output, const std::vector& g, size_t nibble) { BOTAN_ASSERT_NOMSG(g.size() % 2 == 0); // actually a power of 2 const size_t words = output.size(); clear_mem(output.data(), output.size()); for(size_t i = 0; i != g.size(); i += 2) { const secure_vector& vec_0 = g[i ].repr().get_word_vector(); const secure_vector& vec_1 = g[i+1].repr().get_word_vector(); BOTAN_ASSERT_NOMSG(vec_0.size() >= words && vec_1.size() >= words); const auto mask_0 = CT::Mask::is_equal(nibble, i); const auto mask_1 = CT::Mask::is_equal(nibble, i+1); for(size_t w = 0; w != words; ++w) { output[w] |= mask_0.if_set_return(vec_0[w]); output[w] |= mask_1.if_set_return(vec_1[w]); } } } } BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const { BOTAN_DEBUG_ASSERT(scalar.bits() <= max_k_bits); // TODO add a const-time implementation of above assert and use it in release builds const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits; if(exp_nibbles == 0) return 1; secure_vector e_bits(m_params->p_words()); secure_vector ws; const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)); Montgomery_Int x(m_params, e_bits.data(), e_bits.size(), false); for(size_t i = exp_nibbles - 1; i > 0; --i) { x.square_this_n_times(ws, m_window_bits); const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(i-1), m_window_bits)); x.mul_by(e_bits, ws); } x.const_time_unpoison(); return x.value(); } BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const { BOTAN_ASSERT_NOMSG(m_const_time == false); const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits; secure_vector ws; if(exp_nibbles == 0) return 1; Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)]; for(size_t i = exp_nibbles - 1; i > 0; --i) { x.square_this_n_times(ws, m_window_bits); const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits); if(nibble > 0) x.mul_by(m_g[nibble], ws); } x.const_time_unpoison(); return x.value(); } std::shared_ptr monty_precompute(std::shared_ptr params, const BigInt& g, size_t window_bits, bool const_time) { return std::make_shared(params, g, window_bits, const_time); } BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k, size_t max_k_bits) { return precomputed_state.exponentiation(k, max_k_bits); } BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k) { return precomputed_state.exponentiation_vartime(k); } BigInt monty_multi_exp(std::shared_ptr params_p, const BigInt& x_bn, const BigInt& z1, const BigInt& y_bn, const BigInt& z2) { if(z1.is_negative() || z2.is_negative()) throw Invalid_Argument("multi_exponentiate exponents must be positive"); const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); secure_vector ws; const Montgomery_Int one(params_p, params_p->R1(), false); //const Montgomery_Int one(params_p, 1); const Montgomery_Int x1(params_p, x_bn); const Montgomery_Int x2 = x1.square(ws); const Montgomery_Int x3 = x2.mul(x1, ws); const Montgomery_Int y1(params_p, y_bn); const Montgomery_Int y2 = y1.square(ws); const Montgomery_Int y3 = y2.mul(y1, ws); const Montgomery_Int y1x1 = y1.mul(x1, ws); const Montgomery_Int y1x2 = y1.mul(x2, ws); const Montgomery_Int y1x3 = y1.mul(x3, ws); const Montgomery_Int y2x1 = y2.mul(x1, ws); const Montgomery_Int y2x2 = y2.mul(x2, ws); const Montgomery_Int y2x3 = y2.mul(x3, ws); const Montgomery_Int y3x1 = y3.mul(x1, ws); const Montgomery_Int y3x2 = y3.mul(x2, ws); const Montgomery_Int y3x3 = y3.mul(x3, ws); const Montgomery_Int* M[16] = { &one, &x1, // 0001 &x2, // 0010 &x3, // 0011 &y1, // 0100 &y1x1, &y1x2, &y1x3, &y2, // 1000 &y2x1, &y2x2, &y2x3, &y3, // 1100 &y3x1, &y3x2, &y3x3 }; Montgomery_Int H = one; for(size_t i = 0; i != z_bits; i += 2) { if(i > 0) { H.square_this(ws); H.square_this(ws); } const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2); const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2); const uint32_t z12 = (4*z2_b) + z1_b; H.mul_by(*M[z12], ws); } return H.value(); } } /* * Fused and Important MP Algorithms * (C) 1999-2007 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Square a BigInt */ BigInt square(const BigInt& x) { BigInt z = x; secure_vector ws; z.square(ws); return z; } /* * Multiply-Add Operation */ BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c) { if(c.is_negative()) throw Invalid_Argument("mul_add: Third argument must be > 0"); BigInt::Sign sign = BigInt::Positive; if(a.sign() != b.sign()) sign = BigInt::Negative; const size_t a_sw = a.sig_words(); const size_t b_sw = b.sig_words(); const size_t c_sw = c.sig_words(); BigInt r(sign, std::max(a_sw + b_sw, c_sw) + 1); secure_vector workspace(r.size()); bigint_mul(r.mutable_data(), r.size(), a.data(), a.size(), a_sw, b.data(), b.size(), b_sw, workspace.data(), workspace.size()); const size_t r_size = std::max(r.sig_words(), c_sw); bigint_add2(r.mutable_data(), r_size, c.data(), c_sw); return r; } /* * Subtract-Multiply Operation */ BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c) { if(a.is_negative() || b.is_negative()) throw Invalid_Argument("sub_mul: First two arguments must be >= 0"); BigInt r = a; r -= b; r *= c; return r; } /* * Multiply-Subtract Operation */ BigInt mul_sub(const BigInt& a, const BigInt& b, const BigInt& c) { if(c.is_negative() || c.is_zero()) throw Invalid_Argument("mul_sub: Third argument must be > 0"); BigInt r = a; r *= b; r -= c; return r; } } /* * NIST prime reductions * (C) 2014,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { const BigInt& prime_p521() { static const BigInt p521("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); return p521; } void redc_p521(BigInt& x, secure_vector& ws) { const size_t p_full_words = 521 / BOTAN_MP_WORD_BITS; const size_t p_top_bits = 521 % BOTAN_MP_WORD_BITS; const size_t p_words = p_full_words + 1; #if (BOTAN_MP_WORD_BITS == 64) static const word p521_words[p_words] = { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x1FF }; #else static const word p521_words[p_words] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x1FF }; #endif if(ws.size() < p_words + 1) ws.resize(p_words + 1); clear_mem(ws.data(), ws.size()); bigint_shr2(ws.data(), x.data(), std::min(x.size(), 2*p_words), p_full_words, p_top_bits); x.mask_bits(521); x.grow_to(p_words); // Word-level carry will be zero word carry = bigint_add3_nc(x.mutable_data(), x.data(), p_words, ws.data(), p_words); BOTAN_ASSERT_EQUAL(carry, 0, "Final carry in P-521 reduction"); const word top_word = x.word_at(p_full_words); /* * Check if we need to reduce modulo P * There are two possible cases: * - The result overflowed past 521 bits, in which case bit 522 will be set * - The result is exactly 2**521 - 1 */ const auto bit_522_set = CT::Mask::expand(top_word >> p_top_bits); word and_512 = MP_WORD_MAX; for(size_t i = 0; i != p_full_words; ++i) and_512 &= x.word_at(i); const auto all_512_low_bits_set = CT::Mask::is_equal(and_512, MP_WORD_MAX); const auto has_p521_top_word = CT::Mask::is_equal(top_word, 0x1FF); const auto is_p521 = all_512_low_bits_set & has_p521_top_word; const auto needs_reduction = is_p521 | bit_522_set; bigint_cnd_sub(needs_reduction.value(), x.mutable_data(), p521_words, p_words); } namespace { /** * Treating this MPI as a sequence of 32-bit words in big-endian * order, return word i. The array is assumed to be large enough. */ inline uint32_t get_uint32(const word xw[], size_t i) { #if (BOTAN_MP_WORD_BITS == 32) return xw[i]; #else return static_cast(xw[i/2] >> ((i % 2)*32)); #endif } inline void set_words(word x[], size_t i, uint32_t R0, uint32_t R1) { #if (BOTAN_MP_WORD_BITS == 32) x[i] = R0; x[i+1] = R1; #else x[i/2] = (static_cast(R1) << 32) | R0; #endif } } const BigInt& prime_p192() { static const BigInt p192("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); return p192; } void redc_p192(BigInt& x, secure_vector& ws) { BOTAN_UNUSED(ws); static const size_t p192_limbs = 192 / BOTAN_MP_WORD_BITS; x.grow_to(2*p192_limbs); word* xw = x.mutable_data(); const uint64_t X00 = get_uint32(xw, 0); const uint64_t X01 = get_uint32(xw, 1); const uint64_t X02 = get_uint32(xw, 2); const uint64_t X03 = get_uint32(xw, 3); const uint64_t X04 = get_uint32(xw, 4); const uint64_t X05 = get_uint32(xw, 5); const uint64_t X06 = get_uint32(xw, 6); const uint64_t X07 = get_uint32(xw, 7); const uint64_t X08 = get_uint32(xw, 8); const uint64_t X09 = get_uint32(xw, 9); const uint64_t X10 = get_uint32(xw, 10); const uint64_t X11 = get_uint32(xw, 11); const uint64_t S0 = X00 + X06 + X10; const uint64_t S1 = X01 + X07 + X11; const uint64_t S2 = X02 + X06 + X08 + X10; const uint64_t S3 = X03 + X07 + X09 + X11; const uint64_t S4 = X04 + X08 + X10; const uint64_t S5 = X05 + X09 + X11; uint64_t S = 0; uint32_t R0 = 0, R1 = 0; S += S0; R0 = static_cast(S); S >>= 32; S += S1; R1 = static_cast(S); S >>= 32; set_words(xw, 0, R0, R1); S += S2; R0 = static_cast(S); S >>= 32; S += S3; R1 = static_cast(S); S >>= 32; set_words(xw, 2, R0, R1); S += S4; R0 = static_cast(S); S >>= 32; S += S5; R1 = static_cast(S); S >>= 32; set_words(xw, 4, R0, R1); // No underflow possible /* This is a table of (i*P-192) % 2**192 for i in 1...3 */ static const word p192_mults[3][p192_limbs] = { #if (BOTAN_MP_WORD_BITS == 64) {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF}, {0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFF}, {0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFF}, #else {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, #endif }; CT::unpoison(S); BOTAN_ASSERT(S <= 2, "Expected overflow"); BOTAN_ASSERT_NOMSG(x.size() >= p192_limbs + 1); x.mask_bits(192); word borrow = bigint_sub2(x.mutable_data(), p192_limbs + 1, p192_mults[S], p192_limbs); BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); bigint_cnd_add(borrow, x.mutable_data(), p192_limbs + 1, p192_mults[0], p192_limbs); } const BigInt& prime_p224() { static const BigInt p224("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); return p224; } void redc_p224(BigInt& x, secure_vector& ws) { static const size_t p224_limbs = (BOTAN_MP_WORD_BITS == 32) ? 7 : 4; BOTAN_UNUSED(ws); x.grow_to(2*p224_limbs); word* xw = x.mutable_data(); const int64_t X00 = get_uint32(xw, 0); const int64_t X01 = get_uint32(xw, 1); const int64_t X02 = get_uint32(xw, 2); const int64_t X03 = get_uint32(xw, 3); const int64_t X04 = get_uint32(xw, 4); const int64_t X05 = get_uint32(xw, 5); const int64_t X06 = get_uint32(xw, 6); const int64_t X07 = get_uint32(xw, 7); const int64_t X08 = get_uint32(xw, 8); const int64_t X09 = get_uint32(xw, 9); const int64_t X10 = get_uint32(xw, 10); const int64_t X11 = get_uint32(xw, 11); const int64_t X12 = get_uint32(xw, 12); const int64_t X13 = get_uint32(xw, 13); // One full copy of P224 is added, so the result is always positive const int64_t S0 = 0x00000001 + X00 - X07 - X11; const int64_t S1 = 0x00000000 + X01 - X08 - X12; const int64_t S2 = 0x00000000 + X02 - X09 - X13; const int64_t S3 = 0xFFFFFFFF + X03 + X07 + X11 - X10; const int64_t S4 = 0xFFFFFFFF + X04 + X08 + X12 - X11; const int64_t S5 = 0xFFFFFFFF + X05 + X09 + X13 - X12; const int64_t S6 = 0xFFFFFFFF + X06 + X10 - X13; int64_t S = 0; uint32_t R0 = 0, R1 = 0; S += S0; R0 = static_cast(S); S >>= 32; S += S1; R1 = static_cast(S); S >>= 32; set_words(xw, 0, R0, R1); S += S2; R0 = static_cast(S); S >>= 32; S += S3; R1 = static_cast(S); S >>= 32; set_words(xw, 2, R0, R1); S += S4; R0 = static_cast(S); S >>= 32; S += S5; R1 = static_cast(S); S >>= 32; set_words(xw, 4, R0, R1); S += S6; R0 = static_cast(S); S >>= 32; set_words(xw, 6, R0, 0); static const word p224_mults[3][p224_limbs] = { #if (BOTAN_MP_WORD_BITS == 64) {0x0000000000000001, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, {0x0000000000000002, 0xFFFFFFFE00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, {0x0000000000000003, 0xFFFFFFFD00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, #else {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0x00000003, 0x00000000, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} #endif }; CT::unpoison(S); BOTAN_ASSERT(S >= 0 && S <= 2, "Expected overflow"); BOTAN_ASSERT_NOMSG(x.size() >= p224_limbs + 1); x.mask_bits(224); word borrow = bigint_sub2(x.mutable_data(), p224_limbs + 1, p224_mults[S], p224_limbs); BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); bigint_cnd_add(borrow, x.mutable_data(), p224_limbs + 1, p224_mults[0], p224_limbs); } const BigInt& prime_p256() { static const BigInt p256("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); return p256; } void redc_p256(BigInt& x, secure_vector& ws) { static const size_t p256_limbs = (BOTAN_MP_WORD_BITS == 32) ? 8 : 4; BOTAN_UNUSED(ws); x.grow_to(2*p256_limbs); word* xw = x.mutable_data(); const int64_t X00 = get_uint32(xw, 0); const int64_t X01 = get_uint32(xw, 1); const int64_t X02 = get_uint32(xw, 2); const int64_t X03 = get_uint32(xw, 3); const int64_t X04 = get_uint32(xw, 4); const int64_t X05 = get_uint32(xw, 5); const int64_t X06 = get_uint32(xw, 6); const int64_t X07 = get_uint32(xw, 7); const int64_t X08 = get_uint32(xw, 8); const int64_t X09 = get_uint32(xw, 9); const int64_t X10 = get_uint32(xw, 10); const int64_t X11 = get_uint32(xw, 11); const int64_t X12 = get_uint32(xw, 12); const int64_t X13 = get_uint32(xw, 13); const int64_t X14 = get_uint32(xw, 14); const int64_t X15 = get_uint32(xw, 15); // Adds 6 * P-256 to prevent underflow const int64_t S0 = 0xFFFFFFFA + X00 + X08 + X09 - (X11 + X12 + X13) - X14; const int64_t S1 = 0xFFFFFFFF + X01 + X09 + X10 - X12 - (X13 + X14 + X15); const int64_t S2 = 0xFFFFFFFF + X02 + X10 + X11 - (X13 + X14 + X15); const int64_t S3 = 0x00000005 + X03 + (X11 + X12)*2 + X13 - X15 - X08 - X09; const int64_t S4 = 0x00000000 + X04 + (X12 + X13)*2 + X14 - X09 - X10; const int64_t S5 = 0x00000000 + X05 + (X13 + X14)*2 + X15 - X10 - X11; const int64_t S6 = 0x00000006 + X06 + X13 + X14*3 + X15*2 - X08 - X09; const int64_t S7 = 0xFFFFFFFA + X07 + X15*3 + X08 - X10 - (X11 + X12 + X13); int64_t S = 0; uint32_t R0 = 0, R1 = 0; S += S0; R0 = static_cast(S); S >>= 32; S += S1; R1 = static_cast(S); S >>= 32; set_words(xw, 0, R0, R1); S += S2; R0 = static_cast(S); S >>= 32; S += S3; R1 = static_cast(S); S >>= 32; set_words(xw, 2, R0, R1); S += S4; R0 = static_cast(S); S >>= 32; S += S5; R1 = static_cast(S); S >>= 32; set_words(xw, 4, R0, R1); S += S6; R0 = static_cast(S); S >>= 32; S += S7; R1 = static_cast(S); S >>= 32; set_words(xw, 6, R0, R1); S += 5; // the top digits of 6*P-256 /* This is a table of (i*P-256) % 2**256 for i in 1...10 */ static const word p256_mults[11][p256_limbs] = { #if (BOTAN_MP_WORD_BITS == 64) {0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF, 0x0000000000000000, 0xFFFFFFFF00000001}, {0xFFFFFFFFFFFFFFFE, 0x00000001FFFFFFFF, 0x0000000000000000, 0xFFFFFFFE00000002}, {0xFFFFFFFFFFFFFFFD, 0x00000002FFFFFFFF, 0x0000000000000000, 0xFFFFFFFD00000003}, {0xFFFFFFFFFFFFFFFC, 0x00000003FFFFFFFF, 0x0000000000000000, 0xFFFFFFFC00000004}, {0xFFFFFFFFFFFFFFFB, 0x00000004FFFFFFFF, 0x0000000000000000, 0xFFFFFFFB00000005}, {0xFFFFFFFFFFFFFFFA, 0x00000005FFFFFFFF, 0x0000000000000000, 0xFFFFFFFA00000006}, {0xFFFFFFFFFFFFFFF9, 0x00000006FFFFFFFF, 0x0000000000000000, 0xFFFFFFF900000007}, {0xFFFFFFFFFFFFFFF8, 0x00000007FFFFFFFF, 0x0000000000000000, 0xFFFFFFF800000008}, {0xFFFFFFFFFFFFFFF7, 0x00000008FFFFFFFF, 0x0000000000000000, 0xFFFFFFF700000009}, {0xFFFFFFFFFFFFFFF6, 0x00000009FFFFFFFF, 0x0000000000000000, 0xFFFFFFF60000000A}, {0xFFFFFFFFFFFFFFF5, 0x0000000AFFFFFFFF, 0x0000000000000000, 0xFFFFFFF50000000B}, #else {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}, {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000000, 0x00000002, 0xFFFFFFFE}, {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000002, 0x00000000, 0x00000000, 0x00000003, 0xFFFFFFFD}, {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFC}, {0xFFFFFFFB, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000004, 0x00000000, 0x00000000, 0x00000005, 0xFFFFFFFB}, {0xFFFFFFFA, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000005, 0x00000000, 0x00000000, 0x00000006, 0xFFFFFFFA}, {0xFFFFFFF9, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000006, 0x00000000, 0x00000000, 0x00000007, 0xFFFFFFF9}, {0xFFFFFFF8, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000, 0x00000000, 0x00000008, 0xFFFFFFF8}, {0xFFFFFFF7, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000008, 0x00000000, 0x00000000, 0x00000009, 0xFFFFFFF7}, {0xFFFFFFF6, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000009, 0x00000000, 0x00000000, 0x0000000A, 0xFFFFFFF6}, {0xFFFFFFF5, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000A, 0x00000000, 0x00000000, 0x0000000B, 0xFFFFFFF5}, #endif }; CT::unpoison(S); BOTAN_ASSERT(S >= 0 && S <= 10, "Expected overflow"); BOTAN_ASSERT_NOMSG(x.size() >= p256_limbs + 1); x.mask_bits(256); word borrow = bigint_sub2(x.mutable_data(), p256_limbs + 1, p256_mults[S], p256_limbs); BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); bigint_cnd_add(borrow, x.mutable_data(), p256_limbs + 1, p256_mults[0], p256_limbs); } const BigInt& prime_p384() { static const BigInt p384("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); return p384; } void redc_p384(BigInt& x, secure_vector& ws) { BOTAN_UNUSED(ws); static const size_t p384_limbs = (BOTAN_MP_WORD_BITS == 32) ? 12 : 6; x.grow_to(2*p384_limbs); word* xw = x.mutable_data(); const int64_t X00 = get_uint32(xw, 0); const int64_t X01 = get_uint32(xw, 1); const int64_t X02 = get_uint32(xw, 2); const int64_t X03 = get_uint32(xw, 3); const int64_t X04 = get_uint32(xw, 4); const int64_t X05 = get_uint32(xw, 5); const int64_t X06 = get_uint32(xw, 6); const int64_t X07 = get_uint32(xw, 7); const int64_t X08 = get_uint32(xw, 8); const int64_t X09 = get_uint32(xw, 9); const int64_t X10 = get_uint32(xw, 10); const int64_t X11 = get_uint32(xw, 11); const int64_t X12 = get_uint32(xw, 12); const int64_t X13 = get_uint32(xw, 13); const int64_t X14 = get_uint32(xw, 14); const int64_t X15 = get_uint32(xw, 15); const int64_t X16 = get_uint32(xw, 16); const int64_t X17 = get_uint32(xw, 17); const int64_t X18 = get_uint32(xw, 18); const int64_t X19 = get_uint32(xw, 19); const int64_t X20 = get_uint32(xw, 20); const int64_t X21 = get_uint32(xw, 21); const int64_t X22 = get_uint32(xw, 22); const int64_t X23 = get_uint32(xw, 23); // One copy of P-384 is added to prevent underflow const int64_t S0 = 0xFFFFFFFF + X00 + X12 + X20 + X21 - X23; const int64_t S1 = 0x00000000 + X01 + X13 + X22 + X23 - X12 - X20; const int64_t S2 = 0x00000000 + X02 + X14 + X23 - X13 - X21; const int64_t S3 = 0xFFFFFFFF + X03 + X12 + X15 + X20 + X21 - X14 - X22 - X23; const int64_t S4 = 0xFFFFFFFE + X04 + X12 + X13 + X16 + X20 + X21*2 + X22 - X15 - X23*2; const int64_t S5 = 0xFFFFFFFF + X05 + X13 + X14 + X17 + X21 + X22*2 + X23 - X16; const int64_t S6 = 0xFFFFFFFF + X06 + X14 + X15 + X18 + X22 + X23*2 - X17; const int64_t S7 = 0xFFFFFFFF + X07 + X15 + X16 + X19 + X23 - X18; const int64_t S8 = 0xFFFFFFFF + X08 + X16 + X17 + X20 - X19; const int64_t S9 = 0xFFFFFFFF + X09 + X17 + X18 + X21 - X20; const int64_t SA = 0xFFFFFFFF + X10 + X18 + X19 + X22 - X21; const int64_t SB = 0xFFFFFFFF + X11 + X19 + X20 + X23 - X22; int64_t S = 0; uint32_t R0 = 0, R1 = 0; S += S0; R0 = static_cast(S); S >>= 32; S += S1; R1 = static_cast(S); S >>= 32; set_words(xw, 0, R0, R1); S += S2; R0 = static_cast(S); S >>= 32; S += S3; R1 = static_cast(S); S >>= 32; set_words(xw, 2, R0, R1); S += S4; R0 = static_cast(S); S >>= 32; S += S5; R1 = static_cast(S); S >>= 32; set_words(xw, 4, R0, R1); S += S6; R0 = static_cast(S); S >>= 32; S += S7; R1 = static_cast(S); S >>= 32; set_words(xw, 6, R0, R1); S += S8; R0 = static_cast(S); S >>= 32; S += S9; R1 = static_cast(S); S >>= 32; set_words(xw, 8, R0, R1); S += SA; R0 = static_cast(S); S >>= 32; S += SB; R1 = static_cast(S); S >>= 32; set_words(xw, 10, R0, R1); /* This is a table of (i*P-384) % 2**384 for i in 1...4 */ static const word p384_mults[5][p384_limbs] = { #if (BOTAN_MP_WORD_BITS == 64) {0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, {0x00000001FFFFFFFE, 0xFFFFFFFE00000000, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, {0x00000002FFFFFFFD, 0xFFFFFFFD00000000, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, {0x00000003FFFFFFFC, 0xFFFFFFFC00000000, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, {0x00000004FFFFFFFB, 0xFFFFFFFB00000000, 0xFFFFFFFFFFFFFFFA, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, #else {0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFE, 0x00000001, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFD, 0x00000002, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFC, 0x00000003, 0x00000000, 0xFFFFFFFC, 0xFFFFFFFB, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFB, 0x00000004, 0x00000000, 0xFFFFFFFB, 0xFFFFFFFA, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, #endif }; CT::unpoison(S); BOTAN_ASSERT(S >= 0 && S <= 4, "Expected overflow"); BOTAN_ASSERT_NOMSG(x.size() >= p384_limbs + 1); x.mask_bits(384); word borrow = bigint_sub2(x.mutable_data(), p384_limbs + 1, p384_mults[S], p384_limbs); BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); bigint_cnd_add(borrow, x.mutable_data(), p384_limbs + 1, p384_mults[0], p384_limbs); } } /* * Number Theory Functions * (C) 1999-2011,2016,2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void sub_abs(BigInt& z, const BigInt& x, const BigInt& y) { const size_t x_sw = x.sig_words(); const size_t y_sw = y.sig_words(); z.resize(std::max(x_sw, y_sw)); bigint_sub_abs(z.mutable_data(), x.data(), x_sw, y.data(), y_sw); } } /* * Return the number of 0 bits at the end of n */ size_t low_zero_bits(const BigInt& n) { size_t low_zero = 0; auto seen_nonempty_word = CT::Mask::cleared(); for(size_t i = 0; i != n.size(); ++i) { const word x = n.word_at(i); // ctz(0) will return sizeof(word) const size_t tz_x = ctz(x); // if x > 0 we want to count tz_x in total but not any // further words, so set the mask after the addition low_zero += seen_nonempty_word.if_not_set_return(tz_x); seen_nonempty_word |= CT::Mask::expand(x); } // if we saw no words with x > 0 then n == 0 and the value we have // computed is meaningless. Instead return 0 in that case. return seen_nonempty_word.if_set_return(low_zero); } namespace { size_t safegcd_loop_bound(size_t f_bits, size_t g_bits) { const size_t d = std::max(f_bits, g_bits); if(d < 46) return (49*d + 80) / 17; else return (49*d + 57) / 17; } } /* * Calculate the GCD */ BigInt gcd(const BigInt& a, const BigInt& b) { if(a.is_zero()) return abs(b); if(b.is_zero()) return abs(a); if(a == 1 || b == 1) return 1; // See https://gcd.cr.yp.to/safegcd-20190413.pdf fig 1.2 BigInt f = a; BigInt g = b; f.const_time_poison(); g.const_time_poison(); f.set_sign(BigInt::Positive); g.set_sign(BigInt::Positive); const size_t common2s = std::min(low_zero_bits(f), low_zero_bits(g)); CT::unpoison(common2s); f >>= common2s; g >>= common2s; f.ct_cond_swap(f.is_even(), g); int32_t delta = 1; const size_t loop_cnt = safegcd_loop_bound(f.bits(), g.bits()); BigInt newg, t; for(size_t i = 0; i != loop_cnt; ++i) { sub_abs(newg, f, g); const bool need_swap = (g.is_odd() && delta > 0); // if(need_swap) { delta *= -1 } else { delta *= 1 } delta *= CT::Mask::expand(need_swap).if_not_set_return(2) - 1; f.ct_cond_swap(need_swap, g); g.ct_cond_swap(need_swap, newg); delta += 1; g.ct_cond_add(g.is_odd(), f); g >>= 1; } f <<= common2s; f.const_time_unpoison(); g.const_time_unpoison(); BOTAN_ASSERT_NOMSG(g.is_zero()); return f; } /* * Calculate the LCM */ BigInt lcm(const BigInt& a, const BigInt& b) { return ct_divide(a * b, gcd(a, b)); } /* * Modular Exponentiation */ BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) { if(mod.is_negative() || mod == 1) { return 0; } if(base.is_zero() || mod.is_zero()) { if(exp.is_zero()) return 1; return 0; } Modular_Reducer reduce_mod(mod); const size_t exp_bits = exp.bits(); if(mod.is_odd()) { const size_t powm_window = 4; auto monty_mod = std::make_shared(mod, reduce_mod); auto powm_base_mod = monty_precompute(monty_mod, reduce_mod.reduce(base), powm_window); return monty_execute(*powm_base_mod, exp, exp_bits); } /* Support for even modulus is just a convenience and not considered cryptographically important, so this implementation is slow ... */ BigInt accum = 1; BigInt g = reduce_mod.reduce(base); BigInt t; for(size_t i = 0; i != exp_bits; ++i) { t = reduce_mod.multiply(g, accum); g = reduce_mod.square(g); accum.ct_cond_assign(exp.get_bit(i), t); } return accum; } BigInt is_perfect_square(const BigInt& C) { if(C < 1) throw Invalid_Argument("is_perfect_square requires C >= 1"); if(C == 1) return 1; const size_t n = C.bits(); const size_t m = (n + 1) / 2; const BigInt B = C + BigInt::power_of_2(m); BigInt X = BigInt::power_of_2(m) - 1; BigInt X2 = (X*X); for(;;) { X = (X2 + C) / (2*X); X2 = (X*X); if(X2 < B) break; } if(X2 == C) return X; else return 0; } /* * Test for primality using Miller-Rabin */ bool is_prime(const BigInt& n, RandomNumberGenerator& rng, size_t prob, bool is_random) { if(n == 2) return true; if(n <= 1 || n.is_even()) return false; const size_t n_bits = n.bits(); // Fast path testing for small numbers (<= 65521) if(n_bits <= 16) { const uint16_t num = static_cast(n.word_at(0)); return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num); } Modular_Reducer mod_n(n); if(rng.is_seeded()) { const size_t t = miller_rabin_test_iterations(n_bits, prob, is_random); if(is_miller_rabin_probable_prime(n, mod_n, rng, t) == false) return false; if(is_random) return true; else return is_lucas_probable_prime(n, mod_n); } else { return is_bailie_psw_probable_prime(n, mod_n); } } } /* * Modular Exponentiation Proxy * (C) 1999-2007,2012,2018,2019 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { class Modular_Exponentiator { public: virtual void set_base(const BigInt&) = 0; virtual void set_exponent(const BigInt&) = 0; virtual BigInt execute() const = 0; virtual Modular_Exponentiator* copy() const = 0; Modular_Exponentiator() = default; Modular_Exponentiator(const Modular_Exponentiator&) = default; Modular_Exponentiator & operator=(const Modular_Exponentiator&) = default; virtual ~Modular_Exponentiator() = default; }; namespace { /** * Fixed Window Exponentiator */ class Fixed_Window_Exponentiator final : public Modular_Exponentiator { public: void set_exponent(const BigInt& e) override { m_exp = e; } void set_base(const BigInt&) override; BigInt execute() const override; Modular_Exponentiator* copy() const override { return new Fixed_Window_Exponentiator(*this); } Fixed_Window_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); private: Modular_Reducer m_reducer; BigInt m_exp; size_t m_window_bits; std::vector m_g; Power_Mod::Usage_Hints m_hints; }; void Fixed_Window_Exponentiator::set_base(const BigInt& base) { m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints); m_g.resize(static_cast(1) << m_window_bits); m_g[0] = 1; m_g[1] = m_reducer.reduce(base); for(size_t i = 2; i != m_g.size(); ++i) m_g[i] = m_reducer.multiply(m_g[i-1], m_g[1]); } BigInt Fixed_Window_Exponentiator::execute() const { const size_t exp_nibbles = (m_exp.bits() + m_window_bits - 1) / m_window_bits; BigInt x = 1; for(size_t i = exp_nibbles; i > 0; --i) { for(size_t j = 0; j != m_window_bits; ++j) x = m_reducer.square(x); const uint32_t nibble = m_exp.get_substring(m_window_bits*(i-1), m_window_bits); // not const time: x = m_reducer.multiply(x, m_g[nibble]); } return x; } /* * Fixed_Window_Exponentiator Constructor */ Fixed_Window_Exponentiator::Fixed_Window_Exponentiator(const BigInt& n, Power_Mod::Usage_Hints hints) : m_reducer{Modular_Reducer(n)}, m_exp{}, m_window_bits{}, m_g{}, m_hints{hints} {} class Montgomery_Exponentiator final : public Modular_Exponentiator { public: void set_exponent(const BigInt& e) override { m_e = e; } void set_base(const BigInt&) override; BigInt execute() const override; Modular_Exponentiator* copy() const override { return new Montgomery_Exponentiator(*this); } Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); private: BigInt m_p; Modular_Reducer m_mod_p; std::shared_ptr m_monty_params; std::shared_ptr m_monty; BigInt m_e; Power_Mod::Usage_Hints m_hints; }; void Montgomery_Exponentiator::set_base(const BigInt& base) { size_t window_bits = Power_Mod::window_bits(m_e.bits(), base.bits(), m_hints); m_monty = monty_precompute(m_monty_params, m_mod_p.reduce(base), window_bits); } BigInt Montgomery_Exponentiator::execute() const { /* This leaks size of e via loop iterations, not possible to fix without breaking this API. Round up to avoid leaking fine details. */ return monty_execute(*m_monty, m_e, round_up(m_e.bits(), 8)); } Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, Power_Mod::Usage_Hints hints) : m_p(mod), m_mod_p(mod), m_monty_params(std::make_shared(m_p, m_mod_p)), m_hints(hints) { } } /* * Power_Mod Constructor */ Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints, bool disable_monty) { set_modulus(n, hints, disable_monty); } Power_Mod::~Power_Mod() { /* for ~unique_ptr */ } /* * Power_Mod Copy Constructor */ Power_Mod::Power_Mod(const Power_Mod& other) { if(other.m_core.get()) m_core.reset(other.m_core->copy()); } /* * Power_Mod Assignment Operator */ Power_Mod& Power_Mod::operator=(const Power_Mod& other) { if(this != &other) { if(other.m_core) m_core.reset(other.m_core->copy()); else m_core.reset(); } return (*this); } /* * Set the modulus */ void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints, bool disable_monty) const { // Allow set_modulus(0) to mean "drop old state" m_core.reset(); if(n != 0) { if(n.is_odd() && disable_monty == false) m_core.reset(new Montgomery_Exponentiator(n, hints)); else m_core.reset(new Fixed_Window_Exponentiator(n, hints)); } } /* * Set the base */ void Power_Mod::set_base(const BigInt& b) const { if(b.is_negative()) throw Invalid_Argument("Power_Mod::set_base: arg must be non-negative"); if(!m_core) throw Internal_Error("Power_Mod::set_base: m_core was NULL"); m_core->set_base(b); } /* * Set the exponent */ void Power_Mod::set_exponent(const BigInt& e) const { if(e.is_negative()) throw Invalid_Argument("Power_Mod::set_exponent: arg must be > 0"); if(!m_core) throw Internal_Error("Power_Mod::set_exponent: m_core was NULL"); m_core->set_exponent(e); } /* * Compute the result */ BigInt Power_Mod::execute() const { if(!m_core) throw Internal_Error("Power_Mod::execute: m_core was NULL"); return m_core->execute(); } /* * Try to choose a good window size */ size_t Power_Mod::window_bits(size_t exp_bits, size_t, Power_Mod::Usage_Hints hints) { static const size_t wsize[][2] = { { 1434, 7 }, { 539, 6 }, { 197, 4 }, { 70, 3 }, { 17, 2 }, { 0, 0 } }; size_t window_bits = 1; if(exp_bits) { for(size_t j = 0; wsize[j][0]; ++j) { if(exp_bits >= wsize[j][0]) { window_bits += wsize[j][1]; break; } } } if(hints & Power_Mod::BASE_IS_FIXED) window_bits += 2; if(hints & Power_Mod::EXP_IS_LARGE) ++window_bits; return window_bits; } namespace { /* * Choose potentially useful hints */ Power_Mod::Usage_Hints choose_base_hints(const BigInt& b, const BigInt& n) { if(b == 2) return Power_Mod::Usage_Hints(Power_Mod::BASE_IS_2 | Power_Mod::BASE_IS_SMALL); const size_t b_bits = b.bits(); const size_t n_bits = n.bits(); if(b_bits < n_bits / 32) return Power_Mod::BASE_IS_SMALL; if(b_bits > n_bits / 4) return Power_Mod::BASE_IS_LARGE; return Power_Mod::NO_HINTS; } /* * Choose potentially useful hints */ Power_Mod::Usage_Hints choose_exp_hints(const BigInt& e, const BigInt& n) { const size_t e_bits = e.bits(); const size_t n_bits = n.bits(); if(e_bits < n_bits / 32) return Power_Mod::BASE_IS_SMALL; if(e_bits > n_bits / 4) return Power_Mod::BASE_IS_LARGE; return Power_Mod::NO_HINTS; } } /* * Fixed_Exponent_Power_Mod Constructor */ Fixed_Exponent_Power_Mod::Fixed_Exponent_Power_Mod(const BigInt& e, const BigInt& n, Usage_Hints hints) : Power_Mod(n, Usage_Hints(hints | EXP_IS_FIXED | choose_exp_hints(e, n))) { set_exponent(e); } /* * Fixed_Base_Power_Mod Constructor */ Fixed_Base_Power_Mod::Fixed_Base_Power_Mod(const BigInt& b, const BigInt& n, Usage_Hints hints) : Power_Mod(n, Usage_Hints(hints | BASE_IS_FIXED | choose_base_hints(b, n))) { set_base(b); } } /* * (C) 2016,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { bool is_lucas_probable_prime(const BigInt& C, const Modular_Reducer& mod_C) { if(C <= 1) return false; else if(C == 2) return true; else if(C.is_even()) return false; else if(C == 3 || C == 5 || C == 7 || C == 11 || C == 13) return true; BigInt D = 5; for(;;) { int32_t j = jacobi(D, C); if(j == 0) return false; if(j == -1) break; // Check 5, -7, 9, -11, 13, -15, 17, ... if(D.is_negative()) { D.flip_sign(); D += 2; } else { D += 2; D.flip_sign(); } if(D == 17 && is_perfect_square(C).is_nonzero()) return false; } const BigInt K = C + 1; const size_t K_bits = K.bits() - 1; BigInt U = 1; BigInt V = 1; BigInt Ut, Vt, U2, V2; for(size_t i = 0; i != K_bits; ++i) { const bool k_bit = K.get_bit(K_bits - 1 - i); Ut = mod_C.multiply(U, V); Vt = mod_C.reduce(mod_C.square(V) + mod_C.multiply(D, mod_C.square(U))); Vt.ct_cond_add(Vt.is_odd(), C); Vt >>= 1; Vt = mod_C.reduce(Vt); U = Ut; V = Vt; U2 = mod_C.reduce(Ut + Vt); U2.ct_cond_add(U2.is_odd(), C); U2 >>= 1; V2 = mod_C.reduce(Vt + Ut*D); V2.ct_cond_add(V2.is_odd(), C); V2 >>= 1; U.ct_cond_assign(k_bit, U2); V.ct_cond_assign(k_bit, V2); } return (U == 0); } bool is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n) { auto monty_n = std::make_shared(n, mod_n); return passes_miller_rabin_test(n, mod_n, monty_n, 2) && is_lucas_probable_prime(n, mod_n); } bool is_bailie_psw_probable_prime(const BigInt& n) { Modular_Reducer mod_n(n); return is_bailie_psw_probable_prime(n, mod_n); } bool passes_miller_rabin_test(const BigInt& n, const Modular_Reducer& mod_n, const std::shared_ptr& monty_n, const BigInt& a) { BOTAN_ASSERT_NOMSG(n > 1); const BigInt n_minus_1 = n - 1; const size_t s = low_zero_bits(n_minus_1); const BigInt nm1_s = n_minus_1 >> s; const size_t n_bits = n.bits(); const size_t powm_window = 4; auto powm_a_n = monty_precompute(monty_n, a, powm_window); BigInt y = monty_execute(*powm_a_n, nm1_s, n_bits); if(y == 1 || y == n_minus_1) return true; for(size_t i = 1; i != s; ++i) { y = mod_n.square(y); if(y == 1) // found a non-trivial square root return false; /* -1 is the trivial square root of unity, so ``a`` is not a witness for this number - give up */ if(y == n_minus_1) return true; } return false; } bool is_miller_rabin_probable_prime(const BigInt& n, const Modular_Reducer& mod_n, RandomNumberGenerator& rng, size_t test_iterations) { BOTAN_ASSERT_NOMSG(n > 1); auto monty_n = std::make_shared(n, mod_n); for(size_t i = 0; i != test_iterations; ++i) { const BigInt a = BigInt::random_integer(rng, 2, n); if(!passes_miller_rabin_test(n, mod_n, monty_n, a)) return false; } // Failed to find a counterexample return true; } size_t miller_rabin_test_iterations(size_t n_bits, size_t prob, bool random) { const size_t base = (prob + 2) / 2; // worst case 4^-t error rate /* * If the candidate prime was maliciously constructed, we can't rely * on arguments based on p being random. */ if(random == false) return base; /* * For randomly chosen numbers we can use the estimates from * http://www.math.dartmouth.edu/~carlp/PDF/paper88.pdf * * These values are derived from the inequality for p(k,t) given on * the second page. */ if(prob <= 128) { if(n_bits >= 1536) return 4; // < 2^-133 if(n_bits >= 1024) return 6; // < 2^-133 if(n_bits >= 512) return 12; // < 2^-129 if(n_bits >= 256) return 29; // < 2^-128 } /* If the user desires a smaller error probability than we have precomputed error estimates for, just fall back to using the worst case error rate. */ return base; } } /* * Small Primes Table * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { const uint16_t PRIMES[PRIME_TABLE_SIZE+1] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521, 0 }; } /* * Modular Reducer * (C) 1999-2011,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Modular_Reducer Constructor */ Modular_Reducer::Modular_Reducer(const BigInt& mod) { if(mod < 0) throw Invalid_Argument("Modular_Reducer: modulus must be positive"); // Left uninitialized if mod == 0 m_mod_words = 0; if(mod > 0) { m_modulus = mod; m_mod_words = m_modulus.sig_words(); // Compute mu = floor(2^{2k} / m) m_mu.set_bit(2 * BOTAN_MP_WORD_BITS * m_mod_words); m_mu = ct_divide(m_mu, m_modulus); } } BigInt Modular_Reducer::reduce(const BigInt& x) const { BigInt r; secure_vector ws; reduce(r, x, ws); return r; } namespace { /* * Like if(cnd) x.rev_sub(...) but in const time */ void cnd_rev_sub(bool cnd, BigInt& x, const word y[], size_t y_sw, secure_vector& ws) { if(x.sign() != BigInt::Positive) throw Invalid_State("BigInt::sub_rev requires this is positive"); const size_t x_sw = x.sig_words(); const size_t max_words = std::max(x_sw, y_sw); ws.resize(std::max(x_sw, y_sw)); clear_mem(ws.data(), ws.size()); x.grow_to(max_words); const int32_t relative_size = bigint_sub_abs(ws.data(), x.data(), x_sw, y, y_sw); x.cond_flip_sign((relative_size > 0) && cnd); bigint_cnd_swap(cnd, x.mutable_data(), ws.data(), max_words); } } void Modular_Reducer::reduce(BigInt& t1, const BigInt& x, secure_vector& ws) const { if(&t1 == &x) throw Invalid_State("Modular_Reducer arguments cannot alias"); if(m_mod_words == 0) throw Invalid_State("Modular_Reducer: Never initalized"); const size_t x_sw = x.sig_words(); if(x_sw > 2*m_mod_words) { // too big, fall back to slow boat division t1 = ct_modulo(x, m_modulus); return; } t1 = x; t1.set_sign(BigInt::Positive); t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words - 1)); t1.mul(m_mu, ws); t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words + 1)); // TODO add masked mul to avoid computing high bits t1.mul(m_modulus, ws); t1.mask_bits(BOTAN_MP_WORD_BITS * (m_mod_words + 1)); t1.rev_sub(x.data(), std::min(x_sw, m_mod_words + 1), ws); /* * If t1 < 0 then we must add b^(k+1) where b = 2^w. To avoid a * side channel perform the addition unconditionally, with ws set * to either b^(k+1) or else 0. */ const word t1_neg = t1.is_negative(); if(ws.size() < m_mod_words + 2) ws.resize(m_mod_words + 2); clear_mem(ws.data(), ws.size()); ws[m_mod_words + 1] = t1_neg; t1.add(ws.data(), m_mod_words + 2, BigInt::Positive); // Per HAC this step requires at most 2 subtractions t1.ct_reduce_below(m_modulus, ws, 2); cnd_rev_sub(t1.is_nonzero() && x.is_negative(), t1, m_modulus.data(), m_modulus.size(), ws); } } /* * (C) 2007,2008 Falko Strenzke, FlexSecure GmbH * (C) 2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Tonelli-Shanks algorithm */ BigInt ressol(const BigInt& a, const BigInt& p) { if(p <= 1 || p.is_even()) throw Invalid_Argument("ressol: invalid prime"); if(a == 0) return 0; else if(a < 0) throw Invalid_Argument("ressol: value to solve for must be positive"); else if(a >= p) throw Invalid_Argument("ressol: value to solve for must be less than p"); if(p == 2) return a; if(jacobi(a, p) != 1) // not a quadratic residue return -BigInt(1); if(p % 4 == 3) // The easy case { return power_mod(a, ((p+1) >> 2), p); } size_t s = low_zero_bits(p - 1); BigInt q = p >> s; q -= 1; q >>= 1; Modular_Reducer mod_p(p); BigInt r = power_mod(a, q, p); BigInt n = mod_p.multiply(a, mod_p.square(r)); r = mod_p.multiply(r, a); if(n == 1) return r; // find random quadratic nonresidue z word z = 2; for(;;) { if(jacobi(z, p) == -1) // found one break; z += 1; // try next z /* * The expected number of tests to find a non-residue modulo a * prime is 2. If we have not found one after 256 then almost * certainly we have been given a non-prime p. */ if(z >= 256) return -BigInt(1); } BigInt c = power_mod(z, (q << 1) + 1, p); while(n > 1) { q = n; size_t i = 0; while(q != 1) { q = mod_p.square(q); ++i; if(i >= s) { return -BigInt(1); } } c = power_mod(c, BigInt::power_of_2(s-i-1), p); r = mod_p.multiply(r, c); c = mod_p.square(c); n = mod_p.multiply(n, c); s = i; } return r; } } /* * OCB Mode * (C) 2013,2017 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { // Has to be in Botan namespace so unique_ptr can reference it class L_computer final { public: explicit L_computer(const BlockCipher& cipher) : m_BS(cipher.block_size()), m_max_blocks(cipher.parallel_bytes() / m_BS) { m_L_star.resize(m_BS); cipher.encrypt(m_L_star); m_L_dollar = poly_double(star()); m_L.push_back(poly_double(dollar())); while(m_L.size() < 8) m_L.push_back(poly_double(m_L.back())); m_offset_buf.resize(m_BS * m_max_blocks); } void init(const secure_vector& offset) { m_offset = offset; } bool initialized() const { return m_offset.empty() == false; } const secure_vector& star() const { return m_L_star; } const secure_vector& dollar() const { return m_L_dollar; } const secure_vector& offset() const { return m_offset; } const secure_vector& get(size_t i) const { while(m_L.size() <= i) m_L.push_back(poly_double(m_L.back())); return m_L[i]; } const uint8_t* compute_offsets(size_t block_index, size_t blocks) { BOTAN_ASSERT(blocks <= m_max_blocks, "OCB offsets"); uint8_t* offsets = m_offset_buf.data(); if(block_index % 4 == 0) { const secure_vector& L0 = get(0); const secure_vector& L1 = get(1); while(blocks >= 4) { // ntz(4*i+1) == 0 // ntz(4*i+2) == 1 // ntz(4*i+3) == 0 block_index += 4; const size_t ntz4 = var_ctz32(static_cast(block_index)); xor_buf(offsets, m_offset.data(), L0.data(), m_BS); offsets += m_BS; xor_buf(offsets, offsets - m_BS, L1.data(), m_BS); offsets += m_BS; xor_buf(m_offset.data(), L1.data(), m_BS); copy_mem(offsets, m_offset.data(), m_BS); offsets += m_BS; xor_buf(m_offset.data(), get(ntz4).data(), m_BS); copy_mem(offsets, m_offset.data(), m_BS); offsets += m_BS; blocks -= 4; } } for(size_t i = 0; i != blocks; ++i) { // could be done in parallel const size_t ntz = var_ctz32(static_cast(block_index + i + 1)); xor_buf(m_offset.data(), get(ntz).data(), m_BS); copy_mem(offsets, m_offset.data(), m_BS); offsets += m_BS; } return m_offset_buf.data(); } private: secure_vector poly_double(const secure_vector& in) const { secure_vector out(in.size()); poly_double_n(out.data(), in.data(), out.size()); return out; } const size_t m_BS, m_max_blocks; secure_vector m_L_dollar, m_L_star; secure_vector m_offset; mutable std::vector> m_L; secure_vector m_offset_buf; }; namespace { /* * OCB's HASH */ secure_vector ocb_hash(const L_computer& L, const BlockCipher& cipher, const uint8_t ad[], size_t ad_len) { const size_t BS = cipher.block_size(); secure_vector sum(BS); secure_vector offset(BS); secure_vector buf(BS); const size_t ad_blocks = (ad_len / BS); const size_t ad_remainder = (ad_len % BS); for(size_t i = 0; i != ad_blocks; ++i) { // this loop could run in parallel offset ^= L.get(var_ctz32(static_cast(i+1))); buf = offset; xor_buf(buf.data(), &ad[BS*i], BS); cipher.encrypt(buf); sum ^= buf; } if(ad_remainder) { offset ^= L.star(); buf = offset; xor_buf(buf.data(), &ad[BS*ad_blocks], ad_remainder); buf[ad_remainder] ^= 0x80; cipher.encrypt(buf); sum ^= buf; } return sum; } } OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) : m_cipher(cipher), m_checksum(m_cipher->parallel_bytes()), m_ad_hash(m_cipher->block_size()), m_tag_size(tag_size), m_block_size(m_cipher->block_size()), m_par_blocks(m_cipher->parallel_bytes() / m_block_size) { const size_t BS = block_size(); /* * draft-krovetz-ocb-wide-d1 specifies OCB for several other block * sizes but only 128, 192, 256 and 512 bit are currently supported * by this implementation. */ BOTAN_ARG_CHECK(BS == 16 || BS == 24 || BS == 32 || BS == 64, "Invalid block size for OCB"); BOTAN_ARG_CHECK(m_tag_size % 4 == 0 && m_tag_size >= 8 && m_tag_size <= BS && m_tag_size <= 32, "Invalid OCB tag length"); } OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ } void OCB_Mode::clear() { m_cipher->clear(); m_L.reset(); // add clear here? reset(); } void OCB_Mode::reset() { m_block_index = 0; zeroise(m_ad_hash); zeroise(m_checksum); m_last_nonce.clear(); m_stretch.clear(); } bool OCB_Mode::valid_nonce_length(size_t length) const { if(length == 0) return false; if(block_size() == 16) return length < 16; else return length < (block_size() - 1); } std::string OCB_Mode::name() const { return m_cipher->name() + "/OCB"; // include tag size? } size_t OCB_Mode::update_granularity() const { return (m_par_blocks * block_size()); } Key_Length_Specification OCB_Mode::key_spec() const { return m_cipher->key_spec(); } void OCB_Mode::key_schedule(const uint8_t key[], size_t length) { m_cipher->set_key(key, length); m_L.reset(new L_computer(*m_cipher)); } void OCB_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) { verify_key_set(m_L != nullptr); m_ad_hash = ocb_hash(*m_L, *m_cipher, ad, ad_len); } const secure_vector& OCB_Mode::update_nonce(const uint8_t nonce[], size_t nonce_len) { const size_t BS = block_size(); BOTAN_ASSERT(BS == 16 || BS == 24 || BS == 32 || BS == 64, "OCB block size is supported"); const size_t MASKLEN = (BS == 16 ? 6 : ((BS == 24) ? 7 : 8)); const uint8_t BOTTOM_MASK = static_cast((static_cast(1) << MASKLEN) - 1); m_nonce_buf.resize(BS); clear_mem(&m_nonce_buf[0], m_nonce_buf.size()); copy_mem(&m_nonce_buf[BS - nonce_len], nonce, nonce_len); m_nonce_buf[0] = static_cast(((tag_size()*8) % (BS*8)) << (BS <= 16 ? 1 : 0)); m_nonce_buf[BS - nonce_len - 1] ^= 1; const uint8_t bottom = m_nonce_buf[BS-1] & BOTTOM_MASK; m_nonce_buf[BS-1] &= ~BOTTOM_MASK; const bool need_new_stretch = (m_last_nonce != m_nonce_buf); if(need_new_stretch) { m_last_nonce = m_nonce_buf; m_cipher->encrypt(m_nonce_buf); /* The loop bounds (BS vs BS/2) are derived from the relation between the block size and the MASKLEN. Using the terminology of draft-krovetz-ocb-wide, we have to derive enough bits in ShiftedKtop to read up to BLOCKLEN+bottom bits from Stretch. +----------+---------+-------+---------+ | BLOCKLEN | RESIDUE | SHIFT | MASKLEN | +----------+---------+-------+---------+ | 32 | 141 | 17 | 4 | | 64 | 27 | 25 | 5 | | 96 | 1601 | 33 | 6 | | 128 | 135 | 8 | 6 | | 192 | 135 | 40 | 7 | | 256 | 1061 | 1 | 8 | | 384 | 4109 | 80 | 8 | | 512 | 293 | 176 | 8 | | 1024 | 524355 | 352 | 9 | +----------+---------+-------+---------+ */ if(BS == 16) { for(size_t i = 0; i != BS / 2; ++i) m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+1]); } else if(BS == 24) { for(size_t i = 0; i != 16; ++i) m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+5]); } else if(BS == 32) { for(size_t i = 0; i != BS; ++i) m_nonce_buf.push_back(m_nonce_buf[i] ^ (m_nonce_buf[i] << 1) ^ (m_nonce_buf[i+1] >> 7)); } else if(BS == 64) { for(size_t i = 0; i != BS / 2; ++i) m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+22]); } m_stretch = m_nonce_buf; } // now set the offset from stretch and bottom const size_t shift_bytes = bottom / 8; const size_t shift_bits = bottom % 8; BOTAN_ASSERT(m_stretch.size() >= BS + shift_bytes + 1, "Size ok"); m_offset.resize(BS); for(size_t i = 0; i != BS; ++i) { m_offset[i] = (m_stretch[i+shift_bytes] << shift_bits); m_offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits)); } return m_offset; } void OCB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); verify_key_set(m_L != nullptr); m_L->init(update_nonce(nonce, nonce_len)); zeroise(m_checksum); m_block_index = 0; } void OCB_Encryption::encrypt(uint8_t buffer[], size_t blocks) { verify_key_set(m_L != nullptr); BOTAN_STATE_CHECK(m_L->initialized()); const size_t BS = block_size(); while(blocks) { const size_t proc_blocks = std::min(blocks, par_blocks()); const size_t proc_bytes = proc_blocks * BS; const uint8_t* offsets = m_L->compute_offsets(m_block_index, proc_blocks); xor_buf(m_checksum.data(), buffer, proc_bytes); m_cipher->encrypt_n_xex(buffer, offsets, proc_blocks); buffer += proc_bytes; blocks -= proc_blocks; m_block_index += proc_blocks; } } size_t OCB_Encryption::process(uint8_t buf[], size_t sz) { BOTAN_ASSERT(sz % update_granularity() == 0, "Invalid OCB input size"); encrypt(buf, sz / block_size()); return sz; } void OCB_Encryption::finish(secure_vector& buffer, size_t offset) { verify_key_set(m_L != nullptr); const size_t BS = block_size(); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; secure_vector mac(BS); if(sz) { const size_t final_full_blocks = sz / BS; const size_t remainder_bytes = sz - (final_full_blocks * BS); encrypt(buf, final_full_blocks); mac = m_L->offset(); if(remainder_bytes) { BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left"); uint8_t* remainder = &buf[sz - remainder_bytes]; xor_buf(m_checksum.data(), remainder, remainder_bytes); m_checksum[remainder_bytes] ^= 0x80; // Offset_* mac ^= m_L->star(); secure_vector pad(BS); m_cipher->encrypt(mac, pad); xor_buf(remainder, pad.data(), remainder_bytes); } } else { mac = m_L->offset(); } // now compute the tag // fold checksum for(size_t i = 0; i != m_checksum.size(); i += BS) { xor_buf(mac.data(), m_checksum.data() + i, BS); } xor_buf(mac.data(), m_L->dollar().data(), BS); m_cipher->encrypt(mac); xor_buf(mac.data(), m_ad_hash.data(), BS); buffer += std::make_pair(mac.data(), tag_size()); zeroise(m_checksum); m_block_index = 0; } void OCB_Decryption::decrypt(uint8_t buffer[], size_t blocks) { verify_key_set(m_L != nullptr); BOTAN_STATE_CHECK(m_L->initialized()); const size_t BS = block_size(); while(blocks) { const size_t proc_blocks = std::min(blocks, par_blocks()); const size_t proc_bytes = proc_blocks * BS; const uint8_t* offsets = m_L->compute_offsets(m_block_index, proc_blocks); m_cipher->decrypt_n_xex(buffer, offsets, proc_blocks); xor_buf(m_checksum.data(), buffer, proc_bytes); buffer += proc_bytes; blocks -= proc_blocks; m_block_index += proc_blocks; } } size_t OCB_Decryption::process(uint8_t buf[], size_t sz) { BOTAN_ASSERT(sz % update_granularity() == 0, "Invalid OCB input size"); decrypt(buf, sz / block_size()); return sz; } void OCB_Decryption::finish(secure_vector& buffer, size_t offset) { verify_key_set(m_L != nullptr); const size_t BS = block_size(); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); const size_t remaining = sz - tag_size(); secure_vector mac(BS); if(remaining) { const size_t final_full_blocks = remaining / BS; const size_t final_bytes = remaining - (final_full_blocks * BS); decrypt(buf, final_full_blocks); mac ^= m_L->offset(); if(final_bytes) { BOTAN_ASSERT(final_bytes < BS, "Only a partial block left"); uint8_t* remainder = &buf[remaining - final_bytes]; mac ^= m_L->star(); secure_vector pad(BS); m_cipher->encrypt(mac, pad); // P_* xor_buf(remainder, pad.data(), final_bytes); xor_buf(m_checksum.data(), remainder, final_bytes); m_checksum[final_bytes] ^= 0x80; } } else mac = m_L->offset(); // compute the mac // fold checksum for(size_t i = 0; i != m_checksum.size(); i += BS) { xor_buf(mac.data(), m_checksum.data() + i, BS); } mac ^= m_L->dollar(); m_cipher->encrypt(mac); mac ^= m_ad_hash; // reset state zeroise(m_checksum); m_block_index = 0; // compare mac const uint8_t* included_tag = &buf[remaining]; if(!constant_time_compare(mac.data(), included_tag, tag_size())) throw Invalid_Authentication_Tag("OCB tag check failed"); // remove tag from end of message buffer.resize(remaining + offset); } } /* * OFB Mode * (C) 1999-2007,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { OFB::OFB(BlockCipher* cipher) : m_cipher(cipher), m_buffer(m_cipher->block_size()), m_buf_pos(0) { } void OFB::clear() { m_cipher->clear(); zeroise(m_buffer); m_buf_pos = 0; } void OFB::key_schedule(const uint8_t key[], size_t key_len) { m_cipher->set_key(key, key_len); // Set a default all-zeros IV set_iv(nullptr, 0); } std::string OFB::name() const { return "OFB(" + m_cipher->name() + ")"; } size_t OFB::default_iv_length() const { return m_cipher->block_size(); } bool OFB::valid_iv_length(size_t iv_len) const { return (iv_len <= m_cipher->block_size()); } Key_Length_Specification OFB::key_spec() const { return m_cipher->key_spec(); } OFB* OFB::clone() const { return new OFB(m_cipher->clone()); } void OFB::cipher(const uint8_t in[], uint8_t out[], size_t length) { while(length >= m_buffer.size() - m_buf_pos) { xor_buf(out, in, &m_buffer[m_buf_pos], m_buffer.size() - m_buf_pos); length -= (m_buffer.size() - m_buf_pos); in += (m_buffer.size() - m_buf_pos); out += (m_buffer.size() - m_buf_pos); m_cipher->encrypt(m_buffer); m_buf_pos = 0; } xor_buf(out, in, &m_buffer[m_buf_pos], length); m_buf_pos += length; } void OFB::set_iv(const uint8_t iv[], size_t iv_len) { if(!valid_iv_length(iv_len)) throw Invalid_IV_Length(name(), iv_len); zeroise(m_buffer); buffer_insert(m_buffer, 0, iv, iv_len); m_cipher->encrypt(m_buffer); m_buf_pos = 0; } void OFB::seek(uint64_t) { throw Not_Implemented("OFB does not support seeking"); } } /* * Parallel Hash * (C) 1999-2009 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Parallel::add_data(const uint8_t input[], size_t length) { for(auto&& hash : m_hashes) hash->update(input, length); } void Parallel::final_result(uint8_t out[]) { size_t offset = 0; for(auto&& hash : m_hashes) { hash->final(out + offset); offset += hash->output_length(); } } size_t Parallel::output_length() const { size_t sum = 0; for(auto&& hash : m_hashes) sum += hash->output_length(); return sum; } std::string Parallel::name() const { std::vector names; for(auto&& hash : m_hashes) names.push_back(hash->name()); return "Parallel(" + string_join(names, ',') + ")"; } HashFunction* Parallel::clone() const { std::vector> hash_copies; for(auto&& hash : m_hashes) hash_copies.push_back(std::unique_ptr(hash->clone())); return new Parallel(hash_copies); } std::unique_ptr Parallel::copy_state() const { std::vector> hash_clones; for(const std::unique_ptr& hash : m_hashes) { hash_clones.push_back(hash->copy_state()); } return std::unique_ptr(new Parallel(hash_clones)); } void Parallel::clear() { for(auto&& hash : m_hashes) hash->clear(); } Parallel::Parallel(std::vector>& h) { for(size_t i = 0; i != h.size(); ++i) { m_hashes.push_back(std::unique_ptr(h[i].release())); } } } /* * Passhash9 Password Hashing * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { const std::string MAGIC_PREFIX = "$9$"; const size_t WORKFACTOR_BYTES = 2; const size_t ALGID_BYTES = 1; const size_t SALT_BYTES = 12; // 96 bits of salt const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output const size_t WORK_FACTOR_SCALE = 10000; std::unique_ptr get_pbkdf_prf(uint8_t alg_id) { if(alg_id == 0) return MessageAuthenticationCode::create("HMAC(SHA-1)"); else if(alg_id == 1) return MessageAuthenticationCode::create("HMAC(SHA-256)"); else if(alg_id == 2) return MessageAuthenticationCode::create("CMAC(Blowfish)"); else if(alg_id == 3) return MessageAuthenticationCode::create("HMAC(SHA-384)"); else if(alg_id == 4) return MessageAuthenticationCode::create("HMAC(SHA-512)"); return nullptr; } } std::string generate_passhash9(const std::string& pass, RandomNumberGenerator& rng, uint16_t work_factor, uint8_t alg_id) { BOTAN_ARG_CHECK(work_factor > 0 && work_factor < 512, "Invalid Passhash9 work factor"); std::unique_ptr prf = get_pbkdf_prf(alg_id); if(!prf) throw Invalid_Argument("Passhash9: Algorithm id " + std::to_string(alg_id) + " is not defined"); PKCS5_PBKDF2 kdf(prf.release()); // takes ownership of pointer secure_vector salt(SALT_BYTES); rng.randomize(salt.data(), salt.size()); const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; secure_vector blob; blob.push_back(alg_id); blob.push_back(get_byte(0, work_factor)); blob.push_back(get_byte(1, work_factor)); blob += salt; blob += kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN, pass, salt.data(), salt.size(), kdf_iterations).bits_of(); return MAGIC_PREFIX + base64_encode(blob); } bool check_passhash9(const std::string& pass, const std::string& hash) { const size_t BINARY_LENGTH = ALGID_BYTES + WORKFACTOR_BYTES + PASSHASH9_PBKDF_OUTPUT_LEN + SALT_BYTES; const size_t BASE64_LENGTH = MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6; if(hash.size() != BASE64_LENGTH) return false; for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) if(hash[i] != MAGIC_PREFIX[i]) return false; secure_vector bin = base64_decode(hash.c_str() + MAGIC_PREFIX.size()); if(bin.size() != BINARY_LENGTH) return false; uint8_t alg_id = bin[0]; const size_t work_factor = load_be(&bin[ALGID_BYTES], 0); // Bug in the format, bad states shouldn't be representable, but are... if(work_factor == 0) return false; if(work_factor > 512) throw Invalid_Argument("Requested passhash9 work factor " + std::to_string(work_factor) + " is too large"); const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; std::unique_ptr pbkdf_prf = get_pbkdf_prf(alg_id); if(!pbkdf_prf) return false; // unknown algorithm, reject PKCS5_PBKDF2 kdf(pbkdf_prf.release()); // takes ownership of pointer secure_vector cmp = kdf.derive_key( PASSHASH9_PBKDF_OUTPUT_LEN, pass, &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES, kdf_iterations).bits_of(); return constant_time_compare(cmp.data(), &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES], PASSHASH9_PBKDF_OUTPUT_LEN); } bool is_passhash9_alg_supported(uint8_t alg_id) { if (get_pbkdf_prf(alg_id)) { return true; } return false; } } /* * PKCS #5 PBES2 * (C) 1999-2008,2014 Jack Lloyd * (C) 2018 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_SCRYPT) #endif namespace Botan { namespace { bool known_pbes_cipher_mode(const std::string& mode) { return (mode == "CBC" || mode == "GCM" || mode == "SIV"); } SymmetricKey derive_key(const std::string& passphrase, const AlgorithmIdentifier& kdf_algo, size_t default_key_size) { if(kdf_algo.get_oid() == OID::from_string("PKCS5.PBKDF2")) { secure_vector salt; size_t iterations = 0, key_length = 0; AlgorithmIdentifier prf_algo; BER_Decoder(kdf_algo.get_parameters()) .start_cons(SEQUENCE) .decode(salt, OCTET_STRING) .decode(iterations) .decode_optional(key_length, INTEGER, UNIVERSAL) .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED, AlgorithmIdentifier("HMAC(SHA-160)", AlgorithmIdentifier::USE_NULL_PARAM)) .end_cons(); if(salt.size() < 8) throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); if(key_length == 0) key_length = default_key_size; const std::string prf = OIDS::oid2str_or_throw(prf_algo.get_oid()); std::unique_ptr pbkdf(get_pbkdf("PBKDF2(" + prf + ")")); return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations); } #if defined(BOTAN_HAS_SCRYPT) else if(kdf_algo.get_oid() == OID::from_string("Scrypt")) { secure_vector salt; size_t N = 0, r = 0, p = 0; size_t key_length = 0; AlgorithmIdentifier prf_algo; BER_Decoder(kdf_algo.get_parameters()) .start_cons(SEQUENCE) .decode(salt, OCTET_STRING) .decode(N) .decode(r) .decode(p) .decode_optional(key_length, INTEGER, UNIVERSAL) .end_cons(); if(key_length == 0) key_length = default_key_size; secure_vector output(key_length); scrypt(output.data(), output.size(), passphrase, salt.data(), salt.size(), N, r, p); return SymmetricKey(output); } #endif else throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + kdf_algo.get_oid().to_string()); } secure_vector derive_key(const std::string& passphrase, const std::string& digest, RandomNumberGenerator& rng, size_t* msec_in_iterations_out, size_t iterations_if_msec_null, size_t key_length, AlgorithmIdentifier& kdf_algo) { const secure_vector salt = rng.random_vec(12); if(digest == "Scrypt") { #if defined(BOTAN_HAS_SCRYPT) std::unique_ptr pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt"); std::unique_ptr pwhash; if(msec_in_iterations_out) { const std::chrono::milliseconds msec(*msec_in_iterations_out); pwhash = pwhash_fam->tune(key_length, msec); } else { pwhash = pwhash_fam->from_iterations(iterations_if_msec_null); } secure_vector key(key_length); pwhash->derive_key(key.data(), key.size(), passphrase.c_str(), passphrase.size(), salt.data(), salt.size()); const size_t N = pwhash->memory_param(); const size_t r = pwhash->iterations(); const size_t p = pwhash->parallelism(); if(msec_in_iterations_out) *msec_in_iterations_out = 0; std::vector scrypt_params; DER_Encoder(scrypt_params) .start_cons(SEQUENCE) .encode(salt, OCTET_STRING) .encode(N) .encode(r) .encode(p) .encode(key_length) .end_cons(); kdf_algo = AlgorithmIdentifier(OID::from_string("Scrypt"), scrypt_params); return key; #else throw Not_Implemented("Scrypt is not available in this build"); #endif } else { const std::string prf = "HMAC(" + digest + ")"; const std::string pbkdf_name = "PBKDF2(" + prf + ")"; std::unique_ptr pwhash_fam = PasswordHashFamily::create(pbkdf_name); if(!pwhash_fam) throw Invalid_Argument("Unknown password hash digest " + digest); std::unique_ptr pwhash; if(msec_in_iterations_out) { const std::chrono::milliseconds msec(*msec_in_iterations_out); pwhash = pwhash_fam->tune(key_length, msec); } else { pwhash = pwhash_fam->from_iterations(iterations_if_msec_null); } secure_vector key(key_length); pwhash->derive_key(key.data(), key.size(), passphrase.c_str(), passphrase.size(), salt.data(), salt.size()); std::vector pbkdf2_params; const size_t iterations = pwhash->iterations(); if(msec_in_iterations_out) *msec_in_iterations_out = iterations; DER_Encoder(pbkdf2_params) .start_cons(SEQUENCE) .encode(salt, OCTET_STRING) .encode(iterations) .encode(key_length) .encode_if(prf != "HMAC(SHA-160)", AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM)) .end_cons(); kdf_algo = AlgorithmIdentifier("PKCS5.PBKDF2", pbkdf2_params); return key; } } /* * PKCS#5 v2.0 PBE Encryption */ std::pair> pbes2_encrypt_shared(const secure_vector& key_bits, const std::string& passphrase, size_t* msec_in_iterations_out, size_t iterations_if_msec_null, const std::string& cipher, const std::string& prf, RandomNumberGenerator& rng) { const std::vector cipher_spec = split_on(cipher, '/'); if(cipher_spec.size() != 2) throw Encoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); if(!known_pbes_cipher_mode(cipher_spec[1])) throw Encoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); const OID cipher_oid = OIDS::str2oid_or_empty(cipher); if(cipher_oid.empty()) throw Encoding_Error("PBE-PKCS5 v2.0: No OID assigned for " + cipher); std::unique_ptr enc = Cipher_Mode::create(cipher, ENCRYPTION); if(!enc) throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher); const size_t key_length = enc->key_spec().maximum_keylength(); const secure_vector iv = rng.random_vec(enc->default_nonce_length()); AlgorithmIdentifier kdf_algo; const secure_vector derived_key = derive_key(passphrase, prf, rng, msec_in_iterations_out, iterations_if_msec_null, key_length, kdf_algo); enc->set_key(derived_key); enc->start(iv); secure_vector ctext = key_bits; enc->finish(ctext); std::vector encoded_iv; DER_Encoder(encoded_iv).encode(iv, OCTET_STRING); std::vector pbes2_params; DER_Encoder(pbes2_params) .start_cons(SEQUENCE) .encode(kdf_algo) .encode(AlgorithmIdentifier(cipher, encoded_iv)) .end_cons(); AlgorithmIdentifier id(OID::from_string("PBE-PKCS5v20"), pbes2_params); return std::make_pair(id, unlock(ctext)); } } std::pair> pbes2_encrypt(const secure_vector& key_bits, const std::string& passphrase, std::chrono::milliseconds msec, const std::string& cipher, const std::string& digest, RandomNumberGenerator& rng) { size_t msec_in_iterations_out = static_cast(msec.count()); return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng); // return value msec_in_iterations_out discarded } std::pair> pbes2_encrypt_msec(const secure_vector& key_bits, const std::string& passphrase, std::chrono::milliseconds msec, size_t* out_iterations_if_nonnull, const std::string& cipher, const std::string& digest, RandomNumberGenerator& rng) { size_t msec_in_iterations_out = static_cast(msec.count()); auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng); if(out_iterations_if_nonnull) *out_iterations_if_nonnull = msec_in_iterations_out; return ret; } std::pair> pbes2_encrypt_iter(const secure_vector& key_bits, const std::string& passphrase, size_t pbkdf_iter, const std::string& cipher, const std::string& digest, RandomNumberGenerator& rng) { return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng); } secure_vector pbes2_decrypt(const secure_vector& key_bits, const std::string& passphrase, const std::vector& params) { AlgorithmIdentifier kdf_algo, enc_algo; BER_Decoder(params) .start_cons(SEQUENCE) .decode(kdf_algo) .decode(enc_algo) .end_cons(); const std::string cipher = OIDS::oid2str_or_throw(enc_algo.get_oid()); const std::vector cipher_spec = split_on(cipher, '/'); if(cipher_spec.size() != 2) throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); if(!known_pbes_cipher_mode(cipher_spec[1])) throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); secure_vector iv; BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end(); std::unique_ptr dec = Cipher_Mode::create(cipher, DECRYPTION); if(!dec) throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher); dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength())); dec->start(iv); secure_vector buf = key_bits; dec->finish(buf); return buf; } } /* * PBKDF * (C) 2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_PBKDF1) #endif #if defined(BOTAN_HAS_PBKDF2) #endif #if defined(BOTAN_HAS_PGP_S2K) #endif namespace Botan { std::unique_ptr PBKDF::create(const std::string& algo_spec, const std::string& provider) { const SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_PBKDF2) if(req.algo_name() == "PBKDF2") { // TODO OpenSSL if(provider.empty() || provider == "base") { if(auto mac = MessageAuthenticationCode::create(req.arg(0))) return std::unique_ptr(new PKCS5_PBKDF2(mac.release())); if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) return std::unique_ptr(new PKCS5_PBKDF2(mac.release())); } return nullptr; } #endif #if defined(BOTAN_HAS_PBKDF1) if(req.algo_name() == "PBKDF1" && req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) return std::unique_ptr(new PKCS5_PBKDF1(hash.release())); } #endif #if defined(BOTAN_HAS_PGP_S2K) if(req.algo_name() == "OpenPGP-S2K" && req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) return std::unique_ptr(new OpenPGP_S2K(hash.release())); } #endif BOTAN_UNUSED(req); BOTAN_UNUSED(provider); return nullptr; } //static std::unique_ptr PBKDF::create_or_throw(const std::string& algo, const std::string& provider) { if(auto pbkdf = PBKDF::create(algo, provider)) { return pbkdf; } throw Lookup_Error("PBKDF", algo, provider); } std::vector PBKDF::providers(const std::string& algo_spec) { return probe_providers_of(algo_spec, { "base", "openssl" }); } void PBKDF::pbkdf_timed(uint8_t out[], size_t out_len, const std::string& passphrase, const uint8_t salt[], size_t salt_len, std::chrono::milliseconds msec, size_t& iterations) const { iterations = pbkdf(out, out_len, passphrase, salt, salt_len, 0, msec); } void PBKDF::pbkdf_iterations(uint8_t out[], size_t out_len, const std::string& passphrase, const uint8_t salt[], size_t salt_len, size_t iterations) const { if(iterations == 0) throw Invalid_Argument(name() + ": Invalid iteration count"); const size_t iterations_run = pbkdf(out, out_len, passphrase, salt, salt_len, iterations, std::chrono::milliseconds(0)); BOTAN_ASSERT_EQUAL(iterations, iterations_run, "Expected PBKDF iterations"); } secure_vector PBKDF::pbkdf_iterations(size_t out_len, const std::string& passphrase, const uint8_t salt[], size_t salt_len, size_t iterations) const { secure_vector out(out_len); pbkdf_iterations(out.data(), out_len, passphrase, salt, salt_len, iterations); return out; } secure_vector PBKDF::pbkdf_timed(size_t out_len, const std::string& passphrase, const uint8_t salt[], size_t salt_len, std::chrono::milliseconds msec, size_t& iterations) const { secure_vector out(out_len); pbkdf_timed(out.data(), out_len, passphrase, salt, salt_len, msec, iterations); return out; } } /* * (C) 2018 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_PBKDF2) #endif #if defined(BOTAN_HAS_PGP_S2K) #endif #if defined(BOTAN_HAS_SCRYPT) #endif #if defined(BOTAN_HAS_ARGON2) #endif #if defined(BOTAN_HAS_PBKDF_BCRYPT) #endif namespace Botan { std::unique_ptr PasswordHashFamily::create(const std::string& algo_spec, const std::string& provider) { const SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_PBKDF2) if(req.algo_name() == "PBKDF2") { // TODO OpenSSL if(provider.empty() || provider == "base") { if(auto mac = MessageAuthenticationCode::create(req.arg(0))) return std::unique_ptr(new PBKDF2_Family(mac.release())); if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) return std::unique_ptr(new PBKDF2_Family(mac.release())); } return nullptr; } #endif #if defined(BOTAN_HAS_SCRYPT) if(req.algo_name() == "Scrypt") { return std::unique_ptr(new Scrypt_Family); } #endif #if defined(BOTAN_HAS_ARGON2) if(req.algo_name() == "Argon2d") { return std::unique_ptr(new Argon2_Family(0)); } else if(req.algo_name() == "Argon2i") { return std::unique_ptr(new Argon2_Family(1)); } else if(req.algo_name() == "Argon2id") { return std::unique_ptr(new Argon2_Family(2)); } #endif #if defined(BOTAN_HAS_PBKDF_BCRYPT) if(req.algo_name() == "Bcrypt-PBKDF") { return std::unique_ptr(new Bcrypt_PBKDF_Family); } #endif #if defined(BOTAN_HAS_PGP_S2K) if(req.algo_name() == "OpenPGP-S2K" && req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) { return std::unique_ptr(new RFC4880_S2K_Family(hash.release())); } } #endif BOTAN_UNUSED(req); BOTAN_UNUSED(provider); return nullptr; } //static std::unique_ptr PasswordHashFamily::create_or_throw(const std::string& algo, const std::string& provider) { if(auto pbkdf = PasswordHashFamily::create(algo, provider)) { return pbkdf; } throw Lookup_Error("PasswordHashFamily", algo, provider); } std::vector PasswordHashFamily::providers(const std::string& algo_spec) { return probe_providers_of(algo_spec, { "base", "openssl" }); } } /* * PBKDF1 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t PKCS5_PBKDF1::pbkdf(uint8_t output_buf[], size_t output_len, const std::string& passphrase, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec) const { if(output_len > m_hash->output_length()) throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long"); m_hash->update(passphrase); m_hash->update(salt, salt_len); secure_vector key = m_hash->final(); const auto start = std::chrono::high_resolution_clock::now(); size_t iterations_performed = 1; while(true) { if(iterations == 0) { if(iterations_performed % 10000 == 0) { auto time_taken = std::chrono::high_resolution_clock::now() - start; auto msec_taken = std::chrono::duration_cast(time_taken); if(msec_taken > msec) break; } } else if(iterations_performed == iterations) break; m_hash->update(key); m_hash->final(key.data()); ++iterations_performed; } copy_mem(output_buf, key.data(), output_len); return iterations_performed; } } /* * PBKDF2 * (C) 1999-2007 Jack Lloyd * (C) 2018 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void pbkdf2_set_key(MessageAuthenticationCode& prf, const char* password, size_t password_len) { try { prf.set_key(cast_char_ptr_to_uint8(password), password_len); } catch(Invalid_Key_Length&) { throw Invalid_Argument("PBKDF2 cannot accept passphrase of the given size"); } } } size_t pbkdf2(MessageAuthenticationCode& prf, uint8_t out[], size_t out_len, const std::string& password, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec) { if(iterations == 0) { iterations = PBKDF2(prf, out_len, msec).iterations(); } PBKDF2 pbkdf2(prf, iterations); pbkdf2.derive_key(out, out_len, password.c_str(), password.size(), salt, salt_len); return iterations; } namespace { size_t tune_pbkdf2(MessageAuthenticationCode& prf, size_t output_length, uint32_t msec) { if(output_length == 0) output_length = 1; const size_t prf_sz = prf.output_length(); BOTAN_ASSERT_NOMSG(prf_sz > 0); secure_vector U(prf_sz); const size_t trial_iterations = 2000; // Short output ensures we only need a single PBKDF2 block Timer timer("PBKDF2"); const auto tune_time = BOTAN_PBKDF_TUNING_TIME; prf.set_key(nullptr, 0); timer.run_until_elapsed(tune_time, [&]() { uint8_t out[12] = { 0 }; uint8_t salt[12] = { 0 }; pbkdf2(prf, out, sizeof(out), salt, sizeof(salt), trial_iterations); }); if(timer.events() == 0) return trial_iterations; const uint64_t duration_nsec = timer.value() / timer.events(); const uint64_t desired_nsec = static_cast(msec) * 1000000; if(duration_nsec > desired_nsec) return trial_iterations; const size_t blocks_needed = (output_length + prf_sz - 1) / prf_sz; const size_t multiplier = static_cast(desired_nsec / duration_nsec / blocks_needed); if(multiplier == 0) return trial_iterations; else return trial_iterations * multiplier; } } void pbkdf2(MessageAuthenticationCode& prf, uint8_t out[], size_t out_len, const uint8_t salt[], size_t salt_len, size_t iterations) { if(iterations == 0) throw Invalid_Argument("PBKDF2: Invalid iteration count"); clear_mem(out, out_len); if(out_len == 0) return; const size_t prf_sz = prf.output_length(); BOTAN_ASSERT_NOMSG(prf_sz > 0); secure_vector U(prf_sz); uint32_t counter = 1; while(out_len) { const size_t prf_output = std::min(prf_sz, out_len); prf.update(salt, salt_len); prf.update_be(counter++); prf.final(U.data()); xor_buf(out, U.data(), prf_output); for(size_t i = 1; i != iterations; ++i) { prf.update(U); prf.final(U.data()); xor_buf(out, U.data(), prf_output); } out_len -= prf_output; out += prf_output; } } // PBKDF interface size_t PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len, const std::string& password, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec) const { if(iterations == 0) { iterations = PBKDF2(*m_mac, key_len, msec).iterations(); } PBKDF2 pbkdf2(*m_mac, iterations); pbkdf2.derive_key(key, key_len, password.c_str(), password.size(), salt, salt_len); return iterations; } std::string PKCS5_PBKDF2::name() const { return "PBKDF2(" + m_mac->name() + ")"; } PBKDF* PKCS5_PBKDF2::clone() const { return new PKCS5_PBKDF2(m_mac->clone()); } // PasswordHash interface PBKDF2::PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec) : m_prf(prf.clone()), m_iterations(tune_pbkdf2(*m_prf, olen, static_cast(msec.count()))) {} std::string PBKDF2::to_string() const { return "PBKDF2(" + m_prf->name() + "," + std::to_string(m_iterations) + ")"; } void PBKDF2::derive_key(uint8_t out[], size_t out_len, const char* password, const size_t password_len, const uint8_t salt[], size_t salt_len) const { pbkdf2_set_key(*m_prf, password, password_len); pbkdf2(*m_prf, out, out_len, salt, salt_len, m_iterations); } std::string PBKDF2_Family::name() const { return "PBKDF2(" + m_prf->name() + ")"; } std::unique_ptr PBKDF2_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const { return std::unique_ptr(new PBKDF2(*m_prf, output_len, msec)); } std::unique_ptr PBKDF2_Family::default_params() const { return std::unique_ptr(new PBKDF2(*m_prf, 150000)); } std::unique_ptr PBKDF2_Family::from_params(size_t iter, size_t, size_t) const { return std::unique_ptr(new PBKDF2(*m_prf, iter)); } std::unique_ptr PBKDF2_Family::from_iterations(size_t iter) const { return std::unique_ptr(new PBKDF2(*m_prf, iter)); } } /* * PEM Encoding/Decoding * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace PEM_Code { namespace { std::string linewrap(size_t width, const std::string& in) { std::string out; for(size_t i = 0; i != in.size(); ++i) { if(i > 0 && i % width == 0) { out.push_back('\n'); } out.push_back(in[i]); } if(out.size() > 0 && out[out.size()-1] != '\n') { out.push_back('\n'); } return out; } } /* * PEM encode BER/DER-encoded objects */ std::string encode(const uint8_t der[], size_t length, const std::string& label, size_t width) { const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; const std::string PEM_TRAILER = "-----END " + label + "-----\n"; return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER); } /* * Decode PEM down to raw BER/DER */ secure_vector decode_check_label(DataSource& source, const std::string& label_want) { std::string label_got; secure_vector ber = decode(source, label_got); if(label_got != label_want) throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + ", got " + label_got); return ber; } /* * Decode PEM down to raw BER/DER */ secure_vector decode(DataSource& source, std::string& label) { const size_t RANDOM_CHAR_LIMIT = 8; label.clear(); const std::string PEM_HEADER1 = "-----BEGIN "; const std::string PEM_HEADER2 = "-----"; size_t position = 0; while(position != PEM_HEADER1.length()) { uint8_t b; if(!source.read_byte(b)) throw Decoding_Error("PEM: No PEM header found"); if(b == PEM_HEADER1[position]) ++position; else if(position >= RANDOM_CHAR_LIMIT) throw Decoding_Error("PEM: Malformed PEM header"); else position = 0; } position = 0; while(position != PEM_HEADER2.length()) { uint8_t b; if(!source.read_byte(b)) throw Decoding_Error("PEM: No PEM header found"); if(b == PEM_HEADER2[position]) ++position; else if(position) throw Decoding_Error("PEM: Malformed PEM header"); if(position == 0) label += static_cast(b); } std::vector b64; const std::string PEM_TRAILER = "-----END " + label + "-----"; position = 0; while(position != PEM_TRAILER.length()) { uint8_t b; if(!source.read_byte(b)) throw Decoding_Error("PEM: No PEM trailer found"); if(b == PEM_TRAILER[position]) ++position; else if(position) throw Decoding_Error("PEM: Malformed PEM trailer"); if(position == 0) b64.push_back(b); } return base64_decode(b64.data(), b64.size()); } secure_vector decode_check_label(const std::string& pem, const std::string& label_want) { DataSource_Memory src(pem); return decode_check_label(src, label_want); } secure_vector decode(const std::string& pem, std::string& label) { DataSource_Memory src(pem); return decode(src, label); } /* * Search for a PEM signature */ bool matches(DataSource& source, const std::string& extra, size_t search_range) { const std::string PEM_HEADER = "-----BEGIN " + extra; secure_vector search_buf(search_range); size_t got = source.peek(search_buf.data(), search_buf.size(), 0); if(got < PEM_HEADER.length()) return false; size_t index = 0; for(size_t j = 0; j != got; ++j) { if(search_buf[j] == PEM_HEADER[index]) ++index; else index = 0; if(index == PEM_HEADER.size()) return true; } return false; } } } /* * OpenPGP S2K * (C) 1999-2007,2017 Jack Lloyd * (C) 2018 Ribose Inc * * Distributed under the terms of the Botan license */ namespace Botan { /* PGP stores the iteration count as a single byte Thus it can only actually take on one of 256 values, based on the formula in RFC 4880 section 3.6.1.3 */ static const uint32_t OPENPGP_S2K_ITERS[256] = { 1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728, 1792, 1856, 1920, 1984, 2048, 2176, 2304, 2432, 2560, 2688, 2816, 2944, 3072, 3200, 3328, 3456, 3584, 3712, 3840, 3968, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936, 8192, 8704, 9216, 9728, 10240, 10752, 11264, 11776, 12288, 12800, 13312, 13824, 14336, 14848, 15360, 15872, 16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, 29696, 30720, 31744, 32768, 34816, 36864, 38912, 40960, 43008, 45056, 47104, 49152, 51200, 53248, 55296, 57344, 59392, 61440, 63488, 65536, 69632, 73728, 77824, 81920, 86016, 90112, 94208, 98304, 102400, 106496, 110592, 114688, 118784, 122880, 126976, 131072, 139264, 147456, 155648, 163840, 172032, 180224, 188416, 196608, 204800, 212992, 221184, 229376, 237568, 245760, 253952, 262144, 278528, 294912, 311296, 327680, 344064, 360448, 376832, 393216, 409600, 425984, 442368, 458752, 475136, 491520, 507904, 524288, 557056, 589824, 622592, 655360, 688128, 720896, 753664, 786432, 819200, 851968, 884736, 917504, 950272, 983040, 1015808, 1048576, 1114112, 1179648, 1245184, 1310720, 1376256, 1441792, 1507328, 1572864, 1638400, 1703936, 1769472, 1835008, 1900544, 1966080, 2031616, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512, 2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088, 3932160, 4063232, 4194304, 4456448, 4718592, 4980736, 5242880, 5505024, 5767168, 6029312, 6291456, 6553600, 6815744, 7077888, 7340032, 7602176, 7864320, 8126464, 8388608, 8912896, 9437184, 9961472, 10485760, 11010048, 11534336, 12058624, 12582912, 13107200, 13631488, 14155776, 14680064, 15204352, 15728640, 16252928, 16777216, 17825792, 18874368, 19922944, 20971520, 22020096, 23068672, 24117248, 25165824, 26214400, 27262976, 28311552, 29360128, 30408704, 31457280, 32505856, 33554432, 35651584, 37748736, 39845888, 41943040, 44040192, 46137344, 48234496, 50331648, 52428800, 54525952, 56623104, 58720256, 60817408, 62914560, 65011712 }; uint8_t RFC4880_encode_count(size_t desired_iterations) { if(desired_iterations <= OPENPGP_S2K_ITERS[0]) return 0; if(desired_iterations >= OPENPGP_S2K_ITERS[255]) return 255; auto i = std::lower_bound(OPENPGP_S2K_ITERS, OPENPGP_S2K_ITERS + 256, desired_iterations); return static_cast(i - OPENPGP_S2K_ITERS); } size_t RFC4880_decode_count(uint8_t iter) { return OPENPGP_S2K_ITERS[iter]; } namespace { void pgp_s2k(HashFunction& hash, uint8_t output_buf[], size_t output_len, const char* password, const size_t password_size, const uint8_t salt[], size_t salt_len, size_t iterations) { if(iterations > 1 && salt_len == 0) throw Invalid_Argument("OpenPGP S2K requires a salt in iterated mode"); secure_vector input_buf(salt_len + password_size); if(salt_len > 0) { copy_mem(&input_buf[0], salt, salt_len); } if(password_size > 0) { copy_mem(&input_buf[salt_len], cast_char_ptr_to_uint8(password), password_size); } secure_vector hash_buf(hash.output_length()); size_t pass = 0; size_t generated = 0; while(generated != output_len) { const size_t output_this_pass = std::min(hash_buf.size(), output_len - generated); // Preload some number of zero bytes (empty first iteration) std::vector zero_padding(pass); hash.update(zero_padding); // The input is always fully processed even if iterations is very small if(input_buf.empty() == false) { size_t left = std::max(iterations, input_buf.size()); while(left > 0) { const size_t input_to_take = std::min(left, input_buf.size()); hash.update(input_buf.data(), input_to_take); left -= input_to_take; } } hash.final(hash_buf.data()); copy_mem(output_buf + generated, hash_buf.data(), output_this_pass); generated += output_this_pass; ++pass; } } } size_t OpenPGP_S2K::pbkdf(uint8_t output_buf[], size_t output_len, const std::string& password, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec) const { std::unique_ptr pwdhash; if(iterations == 0) { RFC4880_S2K_Family s2k_params(m_hash->clone()); iterations = s2k_params.tune(output_len, msec, 0)->iterations(); } pgp_s2k(*m_hash, output_buf, output_len, password.c_str(), password.size(), salt, salt_len, iterations); return iterations; } std::string RFC4880_S2K_Family::name() const { return "OpenPGP-S2K(" + m_hash->name() + ")"; } std::unique_ptr RFC4880_S2K_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const { const auto tune_time = BOTAN_PBKDF_TUNING_TIME; const size_t buf_size = 1024; std::vector buffer(buf_size); Timer timer("RFC4880_S2K", buf_size); timer.run_until_elapsed(tune_time, [&]() { m_hash->update(buffer); }); const double hash_bytes_per_second = timer.bytes_per_second(); const uint64_t desired_nsec = msec.count() * 1000000; const size_t hash_size = m_hash->output_length(); const size_t blocks_required = (output_len <= hash_size ? 1 : (output_len + hash_size - 1) / hash_size); const double bytes_to_be_hashed = (hash_bytes_per_second * (desired_nsec / 1000000000.0)) / blocks_required; const size_t iterations = RFC4880_round_iterations(static_cast(bytes_to_be_hashed)); return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), iterations)); } std::unique_ptr RFC4880_S2K_Family::from_params(size_t iter, size_t, size_t) const { return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), iter)); } std::unique_ptr RFC4880_S2K_Family::default_params() const { return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), 50331648)); } std::unique_ptr RFC4880_S2K_Family::from_iterations(size_t iter) const { return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), iter)); } RFC4880_S2K::RFC4880_S2K(HashFunction* hash, size_t iterations) : m_hash(hash), m_iterations(iterations) { } std::string RFC4880_S2K::to_string() const { return "OpenPGP-S2K(" + m_hash->name() + "," + std::to_string(m_iterations) + ")"; } void RFC4880_S2K::derive_key(uint8_t out[], size_t out_len, const char* password, const size_t password_len, const uint8_t salt[], size_t salt_len) const { pgp_s2k(*m_hash, out, out_len, password, password_len, salt, salt_len, m_iterations); } } /* * EME Base Class * (C) 1999-2008 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_EME_OAEP) #endif #if defined(BOTAN_HAS_EME_PKCS1) #endif #if defined(BOTAN_HAS_EME_RAW) #endif namespace Botan { EME* get_eme(const std::string& algo_spec) { #if defined(BOTAN_HAS_EME_RAW) if(algo_spec == "Raw") return new EME_Raw; #endif #if defined(BOTAN_HAS_EME_PKCS1) if(algo_spec == "PKCS1v15" || algo_spec == "EME-PKCS1-v1_5") return new EME_PKCS1v15; #endif #if defined(BOTAN_HAS_EME_OAEP) SCAN_Name req(algo_spec); if(req.algo_name() == "OAEP" || req.algo_name() == "EME-OAEP" || req.algo_name() == "EME1") { if(req.arg_count() == 1 || ((req.arg_count() == 2 || req.arg_count() == 3) && req.arg(1) == "MGF1")) { if(auto hash = HashFunction::create(req.arg(0))) return new OAEP(hash.release(), req.arg(2, "")); } else if(req.arg_count() == 2 || req.arg_count() == 3) { auto mgf_params = parse_algorithm_name(req.arg(1)); if(mgf_params.size() == 2 && mgf_params[0] == "MGF1") { auto hash = HashFunction::create(req.arg(0)); auto mgf1_hash = HashFunction::create(mgf_params[1]); if(hash && mgf1_hash) { return new OAEP(hash.release(), mgf1_hash.release(), req.arg(2, "")); } } } } #endif throw Algorithm_Not_Found(algo_spec); } /* * Encode a message */ secure_vector EME::encode(const uint8_t msg[], size_t msg_len, size_t key_bits, RandomNumberGenerator& rng) const { return pad(msg, msg_len, key_bits, rng); } /* * Encode a message */ secure_vector EME::encode(const secure_vector& msg, size_t key_bits, RandomNumberGenerator& rng) const { return pad(msg.data(), msg.size(), key_bits, rng); } } /* * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_EMSA1) #endif #if defined(BOTAN_HAS_EMSA_X931) #endif #if defined(BOTAN_HAS_EMSA_PKCS1) #endif #if defined(BOTAN_HAS_EMSA_PSSR) #endif #if defined(BOTAN_HAS_EMSA_RAW) #endif #if defined(BOTAN_HAS_ISO_9796) #endif namespace Botan { AlgorithmIdentifier EMSA::config_for_x509(const Private_Key&, const std::string&) const { throw Not_Implemented("Encoding " + name() + " not supported for signing X509 objects"); } EMSA* get_emsa(const std::string& algo_spec) { SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_EMSA1) if(req.algo_name() == "EMSA1" && req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) return new EMSA1(hash.release()); } #endif #if defined(BOTAN_HAS_EMSA_PKCS1) if(req.algo_name() == "EMSA_PKCS1" || req.algo_name() == "PKCS1v15" || req.algo_name() == "EMSA-PKCS1-v1_5" || req.algo_name() == "EMSA3") { if(req.arg_count() == 2 && req.arg(0) == "Raw") { return new EMSA_PKCS1v15_Raw(req.arg(1)); } else if(req.arg_count() == 1) { if(req.arg(0) == "Raw") { return new EMSA_PKCS1v15_Raw; } else { if(auto hash = HashFunction::create(req.arg(0))) { return new EMSA_PKCS1v15(hash.release()); } } } } #endif #if defined(BOTAN_HAS_EMSA_PSSR) if(req.algo_name() == "PSS_Raw" || req.algo_name() == "PSSR_Raw") { if(req.arg_count_between(1, 3) && req.arg(1, "MGF1") == "MGF1") { if(auto h = HashFunction::create(req.arg(0))) { if(req.arg_count() == 3) { const size_t salt_size = req.arg_as_integer(2, 0); return new PSSR_Raw(h.release(), salt_size); } else { return new PSSR_Raw(h.release()); } } } } if(req.algo_name() == "PSS" || req.algo_name() == "PSSR" || req.algo_name() == "EMSA-PSS" || req.algo_name() == "PSS-MGF1" || req.algo_name() == "EMSA4") { if(req.arg_count_between(1, 3) && req.arg(1, "MGF1") == "MGF1") { if(auto h = HashFunction::create(req.arg(0))) { if(req.arg_count() == 3) { const size_t salt_size = req.arg_as_integer(2, 0); return new PSSR(h.release(), salt_size); } else { return new PSSR(h.release()); } } } } #endif #if defined(BOTAN_HAS_ISO_9796) if(req.algo_name() == "ISO_9796_DS2") { if(req.arg_count_between(1, 3)) { if(auto h = HashFunction::create(req.arg(0))) { const size_t salt_size = req.arg_as_integer(2, h->output_length()); const bool implicit = req.arg(1, "exp") == "imp"; return new ISO_9796_DS2(h.release(), implicit, salt_size); } } } //ISO-9796-2 DS 3 is deterministic and DS2 without a salt if(req.algo_name() == "ISO_9796_DS3") { if(req.arg_count_between(1, 2)) { if(auto h = HashFunction::create(req.arg(0))) { const bool implicit = req.arg(1, "exp") == "imp"; return new ISO_9796_DS3(h.release(), implicit); } } } #endif #if defined(BOTAN_HAS_EMSA_X931) if(req.algo_name() == "EMSA_X931" || req.algo_name() == "EMSA2" || req.algo_name() == "X9.31") { if(req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) { return new EMSA_X931(hash.release()); } } } #endif #if defined(BOTAN_HAS_EMSA_RAW) if(req.algo_name() == "Raw") { if(req.arg_count() == 0) { return new EMSA_Raw; } else { auto hash = HashFunction::create(req.arg(0)); if(hash) return new EMSA_Raw(hash->output_length()); } } #endif throw Algorithm_Not_Found(algo_spec); } std::string hash_for_emsa(const std::string& algo_spec) { SCAN_Name emsa_name(algo_spec); if(emsa_name.arg_count() > 0) { const std::string pos_hash = emsa_name.arg(0); return pos_hash; } // If we don't understand what this is return a safe default #if defined(BOTAN_HAS_SHA2_64) return "SHA-512"; #else return "SHA-256"; #endif } } /* * Sets of allowed padding schemes for public key types * * This file was automatically generated by ./src/scripts/oids.py on 2017-12-20 * * All manual edits to this file will be lost. Edit the script * then regenerate this source file. * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { const std::map> allowed_signature_paddings = { { "DSA", {"EMSA1"} }, { "ECDSA", {"EMSA1"} }, { "ECGDSA", {"EMSA1"} }, { "ECKCDSA", {"EMSA1"} }, { "GOST-34.10", {"EMSA1"} }, { "GOST-34.10-2012-256", {"EMSA1"} }, { "GOST-34.10-2012-512", {"EMSA1"} }, { "RSA", {"EMSA4", "EMSA3"} }, }; const std::vector get_sig_paddings(const std::string algo) { if(allowed_signature_paddings.count(algo) > 0) return allowed_signature_paddings.at(algo); return {}; } bool sig_algo_and_pad_ok(const std::string algo, const std::string padding) { std::vector pads = get_sig_paddings(algo); return std::find(pads.begin(), pads.end(), padding) != pads.end(); } } /* * PKCS#11 * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace PKCS11 { ReturnValue* ThrowException = reinterpret_cast< ReturnValue* >(-1); namespace { /// @param function_result Return value of the PKCS11 module function /// @param return_value if (`ThrowException`) is passed the function throws an exception, otherwise if a non-NULL pointer is passed: /// return_value receives the return value of the PKCS#11 function and no exception is thrown. /// @return true if function call was successful, false otherwise bool handle_return_value(const CK_RV function_result, ReturnValue* return_value) { if(return_value == ThrowException) { if(static_cast< ReturnValue >(function_result) != ReturnValue::OK) { // caller wants exception throw PKCS11_ReturnError(static_cast< ReturnValue >(function_result)); } } else if(return_value != nullptr) { // caller wants return value *return_value = static_cast< ReturnValue >(function_result); } return static_cast< ReturnValue >(function_result) == ReturnValue::OK; } } void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin) { slot.initialize(label, so_pin); set_pin(slot, so_pin, pin); } void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin) { Session session(slot, false); session.login(UserType::User, old_pin); session.set_pin(old_pin, new_pin); } void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin) { Session session(slot, false); session.login(UserType::SO, old_so_pin); session.set_pin(old_so_pin, new_so_pin); } void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin) { Session session(slot, false); session.login(UserType::SO, so_pin); session.init_pin(pin); } LowLevel::LowLevel(FunctionListPtr ptr) : m_func_list_ptr(ptr) { if(m_func_list_ptr == nullptr) { throw Invalid_Argument("Invalid PKCS#11 function list ptr"); } } /****************************** General purpose functions ******************************/ bool LowLevel::C_Initialize(VoidPtr init_args, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Initialize(init_args), return_value); } bool LowLevel::C_Finalize(VoidPtr reserved, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Finalize(reserved), return_value); } bool LowLevel::C_GetInfo(Info* info_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetInfo(info_ptr), return_value); } bool LowLevel::C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr, ReturnValue* return_value) { using get_function_list = CK_RV(*)(FunctionListPtr*); get_function_list get_function_list_ptr = pkcs11_module.resolve("C_GetFunctionList"); return handle_return_value(get_function_list_ptr(function_list_ptr_ptr), return_value); } /****************************** Slot and token management functions ******************************/ bool LowLevel::C_GetSlotList(Bbool token_present, SlotId* slot_list_ptr, Ulong* count_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetSlotList(token_present, slot_list_ptr, count_ptr), return_value); } bool LowLevel::C_GetSlotList(bool token_present, std::vector& slot_ids, ReturnValue* return_value) const { slot_ids.clear(); // first get available slots Ulong number_slots = 0; bool success = C_GetSlotList(token_present, nullptr, &number_slots, return_value); if(!success || !number_slots) { return success; } // get actual slot ids slot_ids.resize(number_slots); return C_GetSlotList(token_present, slot_ids.data(), &number_slots, return_value); } bool LowLevel::C_GetSlotInfo(SlotId slot_id, SlotInfo* info_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetSlotInfo(slot_id, info_ptr), return_value); } bool LowLevel::C_GetTokenInfo(SlotId slot_id, TokenInfo* info_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetTokenInfo(slot_id, info_ptr), return_value); } bool LowLevel::C_WaitForSlotEvent(Flags flags, SlotId* slot_ptr, VoidPtr reserved, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_WaitForSlotEvent(flags, slot_ptr, reserved), return_value); } bool LowLevel::C_GetMechanismList(SlotId slot_id, MechanismType* mechanism_list_ptr, Ulong* count_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetMechanismList(slot_id, reinterpret_cast< CK_MECHANISM_TYPE_PTR >(mechanism_list_ptr), count_ptr), return_value); } bool LowLevel::C_GetMechanismList(SlotId slot_id, std::vector& mechanisms, ReturnValue* return_value) const { mechanisms.clear(); // first get number of mechanisms Ulong number_mechanisms = 0; bool success = C_GetMechanismList(slot_id, nullptr, &number_mechanisms, return_value); if(!success || !number_mechanisms) { return success; } // get actual mechanisms mechanisms.resize(number_mechanisms); return C_GetMechanismList(slot_id, reinterpret_cast< MechanismType* >(mechanisms.data()), &number_mechanisms, return_value); } bool LowLevel::C_GetMechanismInfo(SlotId slot_id, MechanismType type, MechanismInfo* info_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetMechanismInfo(slot_id, static_cast< CK_MECHANISM_TYPE >(type), info_ptr), return_value); } bool LowLevel::C_InitToken(SlotId slot_id, Utf8Char* so_pin_ptr, Ulong so_pin_len, Utf8Char* label_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_InitToken(slot_id, so_pin_ptr, so_pin_len, label_ptr), return_value); } bool LowLevel::C_InitPIN(SessionHandle session, Utf8Char* pin_ptr, Ulong pin_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_InitPIN(session, pin_ptr, pin_len), return_value); } bool LowLevel::C_SetPIN(SessionHandle session, Utf8Char* old_pin_ptr, Ulong old_len, Utf8Char* new_pin_ptr, Ulong new_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SetPIN(session, old_pin_ptr, old_len, new_pin_ptr, new_len), return_value); } /****************************** Session management ******************************/ bool LowLevel::C_OpenSession(SlotId slot_id, Flags flags, VoidPtr application, Notify notify, SessionHandle* session_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_OpenSession(slot_id, flags, application, notify, session_ptr), return_value); } bool LowLevel::C_CloseSession(SessionHandle session, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_CloseSession(session), return_value); } bool LowLevel::C_CloseAllSessions(SlotId slot_id, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_CloseAllSessions(slot_id), return_value); } bool LowLevel::C_GetSessionInfo(SessionHandle session, SessionInfo* info_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetSessionInfo(session, info_ptr), return_value); } bool LowLevel::C_GetOperationState(SessionHandle session, Byte* operation_state_ptr, Ulong* operation_state_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetOperationState(session, operation_state_ptr, operation_state_len_ptr), return_value); } bool LowLevel::C_SetOperationState(SessionHandle session, Byte* operation_state_ptr, Ulong operation_state_len, ObjectHandle encryption_key, ObjectHandle authentication_key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SetOperationState(session, operation_state_ptr, operation_state_len, encryption_key, authentication_key), return_value); } bool LowLevel::C_Login(SessionHandle session, UserType user_type, Utf8Char* pin_ptr, Ulong pin_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Login(session, static_cast< CK_USER_TYPE >(user_type), pin_ptr, pin_len), return_value); } bool LowLevel::C_Logout(SessionHandle session, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Logout(session), return_value); } /****************************** Object management functions ******************************/ bool LowLevel::C_CreateObject(SessionHandle session, Attribute* attribute_template_ptr, Ulong count, ObjectHandle* object_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_CreateObject(session, attribute_template_ptr, count, object_ptr), return_value); } bool LowLevel::C_CopyObject(SessionHandle session, ObjectHandle object, Attribute* attribute_template_ptr, Ulong count, ObjectHandle* new_object_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_CopyObject(session, object, attribute_template_ptr, count, new_object_ptr), return_value); } bool LowLevel::C_DestroyObject(SessionHandle session, ObjectHandle object, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DestroyObject(session, object), return_value); } bool LowLevel::C_GetObjectSize(SessionHandle session, ObjectHandle object, Ulong* size_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetObjectSize(session, object, size_ptr), return_value); } bool LowLevel::C_GetAttributeValue(SessionHandle session, ObjectHandle object, Attribute* attribute_template_ptr, Ulong count, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetAttributeValue(session, object, attribute_template_ptr, count), return_value); } bool LowLevel::C_SetAttributeValue(SessionHandle session, ObjectHandle object, Attribute* attribute_template_ptr, Ulong count, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SetAttributeValue(session, object, attribute_template_ptr, count), return_value); } bool LowLevel::C_FindObjectsInit(SessionHandle session, Attribute* attribute_template_ptr, Ulong count, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_FindObjectsInit(session, attribute_template_ptr, count), return_value); } bool LowLevel::C_FindObjects(SessionHandle session, ObjectHandle* object_ptr, Ulong max_object_count, Ulong* object_count_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_FindObjects(session, object_ptr, max_object_count, object_count_ptr), return_value); } bool LowLevel::C_FindObjectsFinal(SessionHandle session, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_FindObjectsFinal(session), return_value); } /****************************** Encryption functions ******************************/ bool LowLevel::C_EncryptInit(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_EncryptInit(session, mechanism_ptr, key), return_value); } bool LowLevel::C_Encrypt(SessionHandle session, Byte* data_ptr, Ulong data_len, Byte* encrypted_data_ptr, Ulong* encrypted_data_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Encrypt(session, data_ptr, data_len, encrypted_data_ptr, encrypted_data_len_ptr), return_value); } bool LowLevel::C_EncryptUpdate(SessionHandle session, Byte* part_ptr, Ulong part_len, Byte* encrypted_part_ptr, Ulong* encrypted_part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_EncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr, encrypted_part_len_ptr), return_value); } bool LowLevel::C_EncryptFinal(SessionHandle session, Byte* last_encrypted_part_ptr, Ulong* last_encrypted_part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_EncryptFinal(session, last_encrypted_part_ptr, last_encrypted_part_len_ptr), return_value); } /****************************** Decryption functions ******************************/ bool LowLevel::C_DecryptInit(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DecryptInit(session, mechanism_ptr, key), return_value); } bool LowLevel::C_Decrypt(SessionHandle session, Byte* encrypted_data_ptr, Ulong encrypted_data_len, Byte* data_ptr, Ulong* data_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Decrypt(session, encrypted_data_ptr, encrypted_data_len, data_ptr, data_len_ptr), return_value); } bool LowLevel::C_DecryptUpdate(SessionHandle session, Byte* encrypted_part_ptr, Ulong encrypted_part_len, Byte* part_ptr, Ulong* part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DecryptUpdate(session, encrypted_part_ptr, encrypted_part_len, part_ptr, part_len_ptr), return_value); } bool LowLevel::C_DecryptFinal(SessionHandle session, Byte* last_part_ptr, Ulong* last_part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DecryptFinal(session, last_part_ptr, last_part_len_ptr), return_value); } /****************************** Message digesting functions ******************************/ bool LowLevel::C_DigestInit(SessionHandle session, Mechanism* mechanism, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DigestInit(session, mechanism), return_value); } bool LowLevel::C_Digest(SessionHandle session, Byte* data_ptr, Ulong data_len, Byte* digest_ptr, Ulong* digest_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Digest(session, data_ptr, data_len, digest_ptr, digest_len_ptr), return_value); } bool LowLevel::C_DigestUpdate(SessionHandle session, Byte* part_ptr, Ulong part_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DigestUpdate(session, part_ptr, part_len), return_value); } bool LowLevel::C_DigestKey(SessionHandle session, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DigestKey(session, key), return_value); } bool LowLevel::C_DigestFinal(SessionHandle session, Byte* digest_ptr, Ulong* digest_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DigestFinal(session, digest_ptr, digest_len_ptr), return_value); } /****************************** Signing and MACing functions ******************************/ bool LowLevel::C_SignInit(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SignInit(session, mechanism_ptr, key), return_value); } bool LowLevel::C_Sign(SessionHandle session, Byte* data_ptr, Ulong data_len, Byte* signature_ptr, Ulong* signature_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Sign(session, data_ptr, data_len, signature_ptr, signature_len_ptr), return_value); } bool LowLevel::C_SignUpdate(SessionHandle session, Byte* part_ptr, Ulong part_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SignUpdate(session, part_ptr, part_len), return_value); } bool LowLevel::C_SignFinal(SessionHandle session, Byte* signature_ptr, Ulong* signature_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SignFinal(session, signature_ptr, signature_len_ptr), return_value); } bool LowLevel::C_SignRecoverInit(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SignRecoverInit(session, mechanism_ptr, key), return_value); } bool LowLevel::C_SignRecover(SessionHandle session, Byte* data, Ulong data_len, Byte* signature, Ulong* signature_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SignRecover(session, data, data_len, signature, signature_len), return_value); } /****************************** Functions for verifying signatures and MACs ******************************/ bool LowLevel::C_VerifyInit(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_VerifyInit(session, mechanism_ptr, key), return_value); } bool LowLevel::C_Verify(SessionHandle session, Byte* data_ptr, Ulong data_len, Byte* signature_ptr, Ulong signature_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_Verify(session, data_ptr, data_len, signature_ptr, signature_len), return_value); } bool LowLevel::C_VerifyUpdate(SessionHandle session, Byte* part_ptr, Ulong part_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_VerifyUpdate(session, part_ptr, part_len), return_value); } bool LowLevel::C_VerifyFinal(SessionHandle session, Byte* signature_ptr, Ulong signature_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_VerifyFinal(session, signature_ptr, signature_len), return_value); } bool LowLevel::C_VerifyRecoverInit(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle key, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_VerifyRecoverInit(session, mechanism_ptr, key), return_value); } bool LowLevel::C_VerifyRecover(SessionHandle session, Byte* signature_ptr, Ulong signature_len, Byte* data_ptr, Ulong* data_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_VerifyRecover(session, signature_ptr, signature_len, data_ptr, data_len_ptr), return_value); } /****************************** Dual-purpose cryptographic functions ******************************/ bool LowLevel::C_DigestEncryptUpdate(SessionHandle session, Byte* part_ptr, Ulong part_len, Byte* encrypted_part_ptr, Ulong* encrypted_part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DigestEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr, encrypted_part_len_ptr), return_value); } bool LowLevel::C_DecryptDigestUpdate(SessionHandle session, Byte* encrypted_part_ptr, Ulong encrypted_part_len, Byte* part_ptr, Ulong* part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DecryptDigestUpdate(session, encrypted_part_ptr, encrypted_part_len, part_ptr, part_len_ptr), return_value); } bool LowLevel::C_SignEncryptUpdate(SessionHandle session, Byte* part_ptr, Ulong part_len, Byte* encrypted_part_ptr, Ulong* encrypted_part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SignEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr, encrypted_part_len_ptr), return_value); } bool LowLevel::C_DecryptVerifyUpdate(SessionHandle session, Byte* encrypted_part_ptr, Ulong encrypted_part_len, Byte* part_ptr, Ulong* part_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DecryptVerifyUpdate(session, encrypted_part_ptr, encrypted_part_len, part_ptr, part_len_ptr), return_value); } /****************************** Key management functions ******************************/ bool LowLevel::C_GenerateKey(SessionHandle session, Mechanism* mechanism_ptr, Attribute* attribute_template_ptr, Ulong count, ObjectHandle* key_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GenerateKey(session, mechanism_ptr, attribute_template_ptr, count, key_ptr), return_value); } bool LowLevel::C_GenerateKeyPair(SessionHandle session, Mechanism* mechanism_ptr, Attribute* public_key_template_ptr, Ulong public_key_attribute_count, Attribute* private_key_template_ptr, Ulong private_key_attribute_count, ObjectHandle* public_key_ptr, ObjectHandle* private_key_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GenerateKeyPair(session, mechanism_ptr, public_key_template_ptr, public_key_attribute_count, private_key_template_ptr, private_key_attribute_count, public_key_ptr, private_key_ptr), return_value); } bool LowLevel::C_WrapKey(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle wrapping_key, ObjectHandle key, Byte* wrapped_key_ptr, Ulong* wrapped_key_len_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_WrapKey(session, mechanism_ptr, wrapping_key, key, wrapped_key_ptr, wrapped_key_len_ptr), return_value); } bool LowLevel::C_UnwrapKey(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle unwrapping_key, Byte* wrapped_key_ptr, Ulong wrapped_key_len, Attribute* attribute_template_ptr, Ulong attribute_count, ObjectHandle* key_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_UnwrapKey(session, mechanism_ptr, unwrapping_key, wrapped_key_ptr, wrapped_key_len, attribute_template_ptr, attribute_count, key_ptr), return_value); } bool LowLevel::C_DeriveKey(SessionHandle session, Mechanism* mechanism_ptr, ObjectHandle base_key, Attribute* attribute_template_ptr, Ulong attribute_count, ObjectHandle* key_ptr, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_DeriveKey(session, mechanism_ptr, base_key, attribute_template_ptr, attribute_count, key_ptr), return_value); } /****************************** Random number generation functions ******************************/ bool LowLevel::C_SeedRandom(SessionHandle session, Byte* seed_ptr, Ulong seed_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_SeedRandom(session, seed_ptr, seed_len), return_value); } bool LowLevel::C_GenerateRandom(SessionHandle session, Byte* random_data_ptr, Ulong random_len, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GenerateRandom(session, random_data_ptr, random_len), return_value); } /****************************** Parallel function management functions ******************************/ bool LowLevel::C_GetFunctionStatus(SessionHandle session, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_GetFunctionStatus(session), return_value); } bool LowLevel::C_CancelFunction(SessionHandle session, ReturnValue* return_value) const { return handle_return_value(m_func_list_ptr->C_CancelFunction(session), return_value); } } } /* * PKCS#11 ECC * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) namespace Botan { namespace PKCS11 { namespace { /// Converts a DER-encoded ANSI X9.62 ECPoint to PointGFp PointGFp decode_public_point(const secure_vector& ec_point_data, const EC_Group& group) { secure_vector ec_point; BER_Decoder(ec_point_data).decode(ec_point, OCTET_STRING); return group.OS2ECP(ec_point); } } EC_PublicKeyGenerationProperties::EC_PublicKeyGenerationProperties(const std::vector& ec_params) : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params) { add_binary(AttributeType::EcParams, m_ec_params); } EC_PublicKeyImportProperties::EC_PublicKeyImportProperties(const std::vector& ec_params, const std::vector& ec_point) : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_ec_point(ec_point) { add_binary(AttributeType::EcParams, m_ec_params); add_binary(AttributeType::EcPoint, m_ec_point); } PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, ObjectHandle handle) : Object(session, handle) { secure_vector ec_parameters = get_attribute_value(AttributeType::EcParams); m_domain_params = EC_Group(unlock(ec_parameters)); m_public_key = decode_public_point(get_attribute_value(AttributeType::EcPoint), m_domain_params); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; } PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) : Object(session, props) { m_domain_params = EC_Group(props.ec_params()); secure_vector ec_point; BER_Decoder(props.ec_point()).decode(ec_point, OCTET_STRING); m_public_key = m_domain_params.OS2ECP(ec_point); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; } EC_PrivateKeyImportProperties::EC_PrivateKeyImportProperties(const std::vector& ec_params, const BigInt& value) : PrivateKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_value(value) { add_binary(AttributeType::EcParams, m_ec_params); add_binary(AttributeType::Value, BigInt::encode(m_value)); } PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle) : Object(session, handle), m_domain_params(), m_public_key() { secure_vector ec_parameters = get_attribute_value(AttributeType::EcParams); m_domain_params = EC_Group(unlock(ec_parameters)); } PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) : Object(session, props) { m_domain_params = EC_Group(props.ec_params()); } PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const std::vector& ec_params, const EC_PrivateKeyGenerationProperties& props) : Object(session) { m_domain_params = EC_Group(ec_params); EC_PublicKeyGenerationProperties pub_key_props(ec_params); pub_key_props.set_verify(true); pub_key_props.set_private(false); pub_key_props.set_token(false); // don't create a persistent public key object ObjectHandle pub_key_handle = CK_INVALID_HANDLE; ObjectHandle priv_key_handle = CK_INVALID_HANDLE; Mechanism mechanism = { CKM_EC_KEY_PAIR_GEN, nullptr, 0 }; session.module()->C_GenerateKeyPair(session.handle(), &mechanism, pub_key_props.data(), static_cast(pub_key_props.count()), props.data(), static_cast(props.count()), &pub_key_handle, &priv_key_handle); this->reset_handle(priv_key_handle); Object public_key(session, pub_key_handle); m_public_key = decode_public_point(public_key.get_attribute_value(AttributeType::EcPoint), m_domain_params); } size_t PKCS11_EC_PrivateKey::key_length() const { return m_domain_params.get_order().bits(); } std::vector PKCS11_EC_PrivateKey::public_key_bits() const { return public_point().encode(PointGFp::COMPRESSED); } size_t PKCS11_EC_PrivateKey::estimated_strength() const { return ecp_work_factor(key_length()); } bool PKCS11_EC_PrivateKey::check_key(RandomNumberGenerator&, bool) const { return m_public_key.on_the_curve(); } AlgorithmIdentifier PKCS11_EC_PrivateKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), domain().DER_encode(EC_DOMPAR_ENC_EXPLICIT)); } } } #endif /* * PKCS#11 ECDH * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_ECDH) namespace Botan { namespace PKCS11 { ECDH_PublicKey PKCS11_ECDH_PublicKey::export_key() const { return ECDH_PublicKey(domain(), public_point()); } ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const { auto priv_key = get_attribute_value(AttributeType::Value); Null_RNG rng; return ECDH_PrivateKey(rng, domain(), BigInt::decode(priv_key)); } secure_vector PKCS11_ECDH_PrivateKey::private_key_bits() const { return export_key().private_key_bits(); } namespace { class PKCS11_ECDH_KA_Operation final : public PK_Ops::Key_Agreement { public: PKCS11_ECDH_KA_Operation(const PKCS11_EC_PrivateKey& key, const std::string& params) : PK_Ops::Key_Agreement(), m_key(key), m_mechanism(MechanismWrapper::create_ecdh_mechanism(params)) {} size_t agreed_value_size() const override { return m_key.domain().get_p_bytes(); } /// The encoding in V2.20 was not specified and resulted in different implementations choosing different encodings. /// Applications relying only on a V2.20 encoding (e.g. the DER variant) other than the one specified now (raw) may not work with all V2.30 compliant tokens. secure_vector agree(size_t key_len, const uint8_t other_key[], size_t other_key_len, const uint8_t salt[], size_t salt_len) override { std::vector der_encoded_other_key; if(m_key.point_encoding() == PublicPointEncoding::Der) { DER_Encoder(der_encoded_other_key).encode(other_key, other_key_len, OCTET_STRING); m_mechanism.set_ecdh_other_key(der_encoded_other_key.data(), der_encoded_other_key.size()); } else { m_mechanism.set_ecdh_other_key(other_key, other_key_len); } if(salt != nullptr && salt_len > 0) { m_mechanism.set_ecdh_salt(salt, salt_len); } ObjectHandle secret_handle = 0; AttributeContainer attributes; attributes.add_bool(AttributeType::Sensitive, false); attributes.add_bool(AttributeType::Extractable, true); attributes.add_numeric(AttributeType::Class, static_cast< CK_OBJECT_CLASS >(ObjectClass::SecretKey)); attributes.add_numeric(AttributeType::KeyType, static_cast< CK_KEY_TYPE >(KeyType::GenericSecret)); attributes.add_numeric(AttributeType::ValueLen, static_cast< CK_ULONG >(key_len)); m_key.module()->C_DeriveKey(m_key.session().handle(), m_mechanism.data(), m_key.handle(), attributes.data(), static_cast(attributes.count()), &secret_handle); Object secret_object(m_key.session(), secret_handle); secure_vector secret = secret_object.get_attribute_value(AttributeType::Value); if(secret.size() < key_len) { throw PKCS11_Error("ECDH key derivation secret length is too short"); } secret.resize(key_len); return secret; } private: const PKCS11_EC_PrivateKey& m_key; MechanismWrapper m_mechanism; }; } std::unique_ptr PKCS11_ECDH_PrivateKey::create_key_agreement_op(RandomNumberGenerator&, const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_ECDH_KA_Operation(*this, params)); } PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props) { ObjectHandle pub_key_handle = 0; ObjectHandle priv_key_handle = 0; Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::EcKeyPairGen), nullptr, 0 }; session.module()->C_GenerateKeyPair(session.handle(), &mechanism, pub_props.data(), static_cast(pub_props.count()), priv_props.data(), static_cast(priv_props.count()), &pub_key_handle, &priv_key_handle); return std::make_pair(PKCS11_ECDH_PublicKey(session, pub_key_handle), PKCS11_ECDH_PrivateKey(session, priv_key_handle)); } } } #endif /* * PKCS#11 ECDSA * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_ECDSA) namespace Botan { namespace PKCS11 { ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const { return ECDSA_PublicKey(domain(), public_point()); } bool PKCS11_ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!public_point().on_the_curve()) { return false; } if(!strong) { return true; } ECDSA_PublicKey pubkey(domain(), public_point()); return KeyPair::signature_consistency_check(rng, *this, pubkey, "EMSA1(SHA-256)"); } ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const { auto priv_key = get_attribute_value(AttributeType::Value); Null_RNG rng; return ECDSA_PrivateKey(rng, domain(), BigInt::decode(priv_key)); } secure_vector PKCS11_ECDSA_PrivateKey::private_key_bits() const { return export_key().private_key_bits(); } namespace { class PKCS11_ECDSA_Signature_Operation final : public PK_Ops::Signature { public: PKCS11_ECDSA_Signature_Operation(const PKCS11_EC_PrivateKey& key, const std::string& emsa) : PK_Ops::Signature(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa)) {} void update(const uint8_t msg[], size_t msg_len) override { if(!m_initialized) { // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); m_initialized = true; m_first_message = secure_vector(msg, msg + msg_len); return; } if(!m_first_message.empty()) { // second call to update: start multiple-part operation m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message); m_first_message.clear(); } m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast(msg), static_cast(msg_len)); } secure_vector sign(RandomNumberGenerator&) override { secure_vector signature; if(!m_first_message.empty()) { // single call to update: perform single-part operation m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature); m_first_message.clear(); } else { // multiple calls to update (or none): finish multiple-part operation m_key.module()->C_SignFinal(m_key.session().handle(), signature); } m_initialized = false; return signature; } size_t signature_length() const override { return 2*m_order.bytes(); } private: const PKCS11_EC_PrivateKey& m_key; const BigInt& m_order; MechanismWrapper m_mechanism; secure_vector m_first_message; bool m_initialized = false; }; class PKCS11_ECDSA_Verification_Operation final : public PK_Ops::Verification { public: PKCS11_ECDSA_Verification_Operation(const PKCS11_EC_PublicKey& key, const std::string& emsa) : PK_Ops::Verification(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa)) {} void update(const uint8_t msg[], size_t msg_len) override { if(!m_initialized) { // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); m_initialized = true; m_first_message = secure_vector(msg, msg + msg_len); return; } if(!m_first_message.empty()) { // second call to update: start multiple-part operation m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message); m_first_message.clear(); } m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast(msg), static_cast(msg_len)); } bool is_valid_signature(const uint8_t sig[], size_t sig_len) override { ReturnValue return_value = ReturnValue::SignatureInvalid; if(!m_first_message.empty()) { // single call to update: perform single-part operation m_key.module()->C_Verify(m_key.session().handle(), m_first_message.data(), static_cast(m_first_message.size()), const_cast(sig), static_cast(sig_len), &return_value); m_first_message.clear(); } else { // multiple calls to update (or none): finish multiple-part operation m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast(sig), static_cast(sig_len), &return_value); } m_initialized = false; if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid) { throw PKCS11_ReturnError(return_value); } return return_value == ReturnValue::OK; } private: const PKCS11_EC_PublicKey& m_key; const BigInt& m_order; MechanismWrapper m_mechanism; secure_vector m_first_message; bool m_initialized = false; }; } std::unique_ptr PKCS11_ECDSA_PublicKey::create_verification_op(const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_ECDSA_Verification_Operation(*this, params)); } std::unique_ptr PKCS11_ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_ECDSA_Signature_Operation(*this, params)); } PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props) { ObjectHandle pub_key_handle = 0; ObjectHandle priv_key_handle = 0; Mechanism mechanism = { static_cast(MechanismType::EcKeyPairGen), nullptr, 0 }; session.module()->C_GenerateKeyPair(session.handle(), &mechanism, pub_props.data(), static_cast(pub_props.count()), priv_props.data(), static_cast(priv_props.count()), &pub_key_handle, &priv_key_handle); return std::make_pair(PKCS11_ECDSA_PublicKey(session, pub_key_handle), PKCS11_ECDSA_PrivateKey(session, priv_key_handle)); } } } #endif /* * PKCS#11 Mechanism * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace PKCS11 { namespace { using PSS_Params = std::tuple; // maps a PSS mechanism type to the number of bytes used for the salt, the mechanism type of the underlying hash algorithm and the MGF static const std::map PssOptions = { { MechanismType::RsaPkcsPss, PSS_Params(0, MechanismType::Sha1, MGF::Mgf1Sha1) }, { MechanismType::Sha1RsaPkcsPss, PSS_Params(20, MechanismType::Sha1, MGF::Mgf1Sha1) }, { MechanismType::Sha224RsaPkcsPss, PSS_Params(28, MechanismType::Sha224, MGF::Mgf1Sha224) }, { MechanismType::Sha256RsaPkcsPss, PSS_Params(32, MechanismType::Sha256, MGF::Mgf1Sha256) }, { MechanismType::Sha384RsaPkcsPss, PSS_Params(48, MechanismType::Sha384, MGF::Mgf1Sha384) }, { MechanismType::Sha512RsaPkcsPss, PSS_Params(64, MechanismType::Sha512, MGF::Mgf1Sha512) } }; struct MechanismData { explicit MechanismData(MechanismType _type) : type(_type) {} MechanismData(MechanismData const&) = default; MechanismData& operator=(MechanismData const&) = default; virtual ~MechanismData() = default; // the mechanism to perform MechanismType type; }; struct RSA_SignMechanism final : public MechanismData { explicit RSA_SignMechanism(MechanismType _type) : MechanismData(_type), hash(static_cast(0)), mgf(static_cast(0)), salt_size(0) { auto pss_option = PssOptions.find(type); if(pss_option != PssOptions.end()) { hash = std::get<1>(pss_option->second); mgf = std::get<2>(pss_option->second); salt_size = std::get<0>(pss_option->second); } } // hash algorithm used in the PSS encoding; if the signature mechanism does not include message hashing, // then this value must be the mechanism used by the application to generate the message hash; // if the signature mechanism includes hashing, then this value must match the hash algorithm indicated by the signature mechanism MechanismType hash; // mask generation function to use on the encoded block MGF mgf; // length, in bytes, of the salt value used in the PSS encoding; typical values are the length of the message hash and zero size_t salt_size; }; // note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_sign_mechanism` static std::map SignMechanisms = { { "Raw", RSA_SignMechanism(MechanismType::RsaX509) }, { "EMSA2(Raw)", RSA_SignMechanism(MechanismType::RsaX931) }, { "EMSA2(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaX931) }, // RSASSA PKCS#1 v1.5 { "EMSA3(Raw)", RSA_SignMechanism(MechanismType::RsaPkcs) }, { "EMSA3(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) }, { "EMSA3(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) }, { "EMSA3(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) }, { "EMSA3(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) }, { "EMSA3(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) }, { "EMSA_PKCS1(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) }, { "EMSA_PKCS1(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) }, { "EMSA_PKCS1(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) }, { "EMSA_PKCS1(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) }, { "EMSA_PKCS1(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) }, // RSASSA PKCS#1 PSS { "EMSA4(Raw)", RSA_SignMechanism(MechanismType::RsaPkcsPss) }, { "EMSA4(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcsPss) }, { "EMSA4(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcsPss) }, { "EMSA4(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) }, { "EMSA4(SHA-256,MGF1,32)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) }, { "PSSR(SHA-256,MGF1,32)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) }, { "EMSA4(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) }, { "EMSA4(SHA-384,MGF1,48)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) }, { "PSSR(SHA-384,MGF1,48)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) }, { "EMSA4(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) }, { "EMSA4(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) }, { "PSSR(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) }, { "ISO9796", RSA_SignMechanism(MechanismType::Rsa9796) } }; struct RSA_CryptMechanism final : public MechanismData { RSA_CryptMechanism(MechanismType _type, size_t _padding_size, MechanismType _hash, MGF _mgf) : MechanismData(_type), hash(_hash), mgf(_mgf), padding_size(_padding_size) {} RSA_CryptMechanism(MechanismType _type, size_t _padding_size) : RSA_CryptMechanism(_type, _padding_size, static_cast(0), static_cast(0)) {} // mechanism ID of the message digest algorithm used to calculate the digest of the encoding parameter MechanismType hash; // mask generation function to use on the encoded block MGF mgf; // number of bytes required for the padding size_t padding_size; }; // note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_crypt_mechanism` static const std::map CryptMechanisms = { { "Raw", RSA_CryptMechanism(MechanismType::RsaX509, 0) }, { "EME-PKCS1-v1_5", RSA_CryptMechanism(MechanismType::RsaPkcs, 11) }, { "OAEP(SHA-1)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 20, MechanismType::Sha1, MGF::Mgf1Sha1) }, { "OAEP(SHA-224)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 28, MechanismType::Sha224, MGF::Mgf1Sha224) }, { "OAEP(SHA-256)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 32, MechanismType::Sha256, MGF::Mgf1Sha256) }, { "OAEP(SHA-384)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 48, MechanismType::Sha384, MGF::Mgf1Sha384) }, { "OAEP(SHA-512)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 64, MechanismType::Sha512, MGF::Mgf1Sha512) } }; // note: when updating this map, update the documentation for `MechanismWrapper::create_ecdsa_mechanism` static std::map EcdsaHash = { { "Raw", MechanismType::Ecdsa }, { "SHA-160", MechanismType::EcdsaSha1 }, { "SHA-224", MechanismType::EcdsaSha224 }, { "SHA-256", MechanismType::EcdsaSha256 }, { "SHA-384", MechanismType::EcdsaSha384 }, { "SHA-512", MechanismType::EcdsaSha512 } }; // note: when updating this map, update the documentation for `MechanismWrapper::create_ecdh_mechanism` static std::map EcdhHash = { { "Raw", KeyDerivation::Null }, { "SHA-160", KeyDerivation::Sha1Kdf }, { "SHA-224", KeyDerivation::Sha224Kdf }, { "SHA-256", KeyDerivation::Sha256Kdf }, { "SHA-384", KeyDerivation::Sha384Kdf }, { "SHA-512", KeyDerivation::Sha512Kdf } }; } MechanismWrapper::MechanismWrapper(MechanismType mechanism_type) : m_mechanism( { static_cast(mechanism_type), nullptr, 0 }), m_parameters(nullptr) {} MechanismWrapper MechanismWrapper::create_rsa_crypt_mechanism(const std::string& padding) { auto mechanism_info_it = CryptMechanisms.find(padding); if(mechanism_info_it == CryptMechanisms.end()) { // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding` throw Lookup_Error("PKCS#11 RSA encrypt/decrypt does not support EME " + padding); } RSA_CryptMechanism mechanism_info = mechanism_info_it->second; MechanismWrapper mech(mechanism_info.type); if(mechanism_info.type == MechanismType::RsaPkcsOaep) { mech.m_parameters = std::make_shared(); mech.m_parameters->oaep_params.hashAlg = static_cast(mechanism_info.hash); mech.m_parameters->oaep_params.mgf = static_cast(mechanism_info.mgf); mech.m_parameters->oaep_params.source = CKZ_DATA_SPECIFIED; mech.m_parameters->oaep_params.pSourceData = nullptr; mech.m_parameters->oaep_params.ulSourceDataLen = 0; mech.m_mechanism.pParameter = mech.m_parameters.get(); mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsOaepParams); } mech.m_padding_size = mechanism_info.padding_size; return mech; } MechanismWrapper MechanismWrapper::create_rsa_sign_mechanism(const std::string& padding) { auto mechanism_info_it = SignMechanisms.find(padding); if(mechanism_info_it == SignMechanisms.end()) { // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding` throw Lookup_Error("PKCS#11 RSA sign/verify does not support EMSA " + padding); } RSA_SignMechanism mechanism_info = mechanism_info_it->second; MechanismWrapper mech(mechanism_info.type); if(PssOptions.find(mechanism_info.type) != PssOptions.end()) { mech.m_parameters = std::make_shared(); mech.m_parameters->pss_params.hashAlg = static_cast(mechanism_info.hash); mech.m_parameters->pss_params.mgf = static_cast(mechanism_info.mgf); mech.m_parameters->pss_params.sLen = static_cast(mechanism_info.salt_size); mech.m_mechanism.pParameter = mech.m_parameters.get(); mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsPssParams); } return mech; } MechanismWrapper MechanismWrapper::create_ecdsa_mechanism(const std::string& hash) { std::string hash_name = hash; if(hash_name != "Raw") { hash_name = hash_for_emsa(hash); } auto mechanism_type = EcdsaHash.find(hash_name); if(mechanism_type == EcdsaHash.end()) { throw Lookup_Error("PKCS#11 ECDSA sign/verify does not support " + hash); } return MechanismWrapper(mechanism_type->second); } MechanismWrapper MechanismWrapper::create_ecdh_mechanism(const std::string& params) { std::vector param_parts = split_on(params, ','); if(param_parts.empty() || param_parts.size() > 2) throw Invalid_Argument("PKCS #11 ECDH key derivation bad params " + params); const bool use_cofactor = (param_parts[0] == "Cofactor") || (param_parts.size() == 2 && param_parts[1] == "Cofactor"); std::string kdf_name = (param_parts[0] == "Cofactor" ? param_parts[1] : param_parts[0]); std::string hash = kdf_name; if(kdf_name != "Raw") { SCAN_Name kdf_hash(kdf_name); if(kdf_hash.arg_count() > 0) { hash = kdf_hash.arg(0); } } auto kdf = EcdhHash.find(hash); if(kdf == EcdhHash.end()) { throw Lookup_Error("PKCS#11 ECDH key derivation does not support KDF " + kdf_name); } MechanismWrapper mech(use_cofactor ? MechanismType::Ecdh1CofactorDerive : MechanismType::Ecdh1Derive); mech.m_parameters = std::make_shared(); mech.m_parameters->ecdh_params.kdf = static_cast(kdf->second); mech.m_mechanism.pParameter = mech.m_parameters.get(); mech.m_mechanism.ulParameterLen = sizeof(Ecdh1DeriveParams); return mech; } } } /* * PKCS#11 Module * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace PKCS11 { Module::Module(Module&&) = default; Module::Module(const std::string& file_path, C_InitializeArgs init_args) : m_file_path(file_path) { if(file_path.empty()) throw Invalid_Argument("PKCS11 no module path specified"); reload(init_args); } Module::~Module() noexcept { try { m_low_level->C_Finalize(nullptr, nullptr); } catch(...) { // we are noexcept and must swallow any exception here } } void Module::reload(C_InitializeArgs init_args) { if(m_low_level) { m_low_level->C_Finalize(nullptr); } m_library.reset(new Dynamically_Loaded_Library(m_file_path)); LowLevel::C_GetFunctionList(*m_library, &m_func_list); m_low_level.reset(new LowLevel(m_func_list)); m_low_level->C_Initialize(&init_args); } } } /* * PKCS#11 Object * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace PKCS11 { AttributeContainer::AttributeContainer(ObjectClass object_class) { add_class(object_class); } void AttributeContainer::add_class(ObjectClass object_class) { m_numerics.emplace_back(static_cast< uint64_t >(object_class)); add_attribute(AttributeType::Class, reinterpret_cast< uint8_t* >(&m_numerics.back()), static_cast(sizeof(ObjectClass))); } void AttributeContainer::add_string(AttributeType attribute, const std::string& value) { m_strings.push_back(value); add_attribute(attribute, reinterpret_cast(m_strings.back().data()), static_cast(value.size())); } void AttributeContainer::add_binary(AttributeType attribute, const uint8_t* value, size_t length) { m_vectors.push_back(secure_vector(value, value + length)); add_attribute(attribute, reinterpret_cast< const uint8_t* >(m_vectors.back().data()), static_cast(length)); } void AttributeContainer::add_bool(AttributeType attribute, bool value) { m_numerics.push_back(value ? True : False); add_attribute(attribute, reinterpret_cast< uint8_t* >(&m_numerics.back()), sizeof(Bbool)); } void AttributeContainer::add_attribute(AttributeType attribute, const uint8_t* value, uint32_t size) { bool exists = false; // check if the attribute has been added already for(auto& existing_attribute : m_attributes) { if(existing_attribute.type == static_cast< CK_ATTRIBUTE_TYPE >(attribute)) { // remove old entries m_strings.erase(std::remove_if(m_strings.begin(), m_strings.end(), [ &existing_attribute ](const std::string& data) { return data.data() == existing_attribute.pValue; }), m_strings.end()); m_numerics.erase(std::remove_if(m_numerics.begin(), m_numerics.end(), [ &existing_attribute ](const uint64_t& data) { return &data == existing_attribute.pValue; }), m_numerics.end()); m_vectors.erase(std::remove_if(m_vectors.begin(), m_vectors.end(), [ &existing_attribute ](const secure_vector& data) { return data.data() == existing_attribute.pValue; }), m_vectors.end()); existing_attribute.pValue = const_cast< uint8_t* >(value); existing_attribute.ulValueLen = size; exists = true; break; } } if(!exists) { m_attributes.push_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(attribute), const_cast< uint8_t* >(value), size }); } } // ==================================================================================================== ObjectFinder::ObjectFinder(Session& session, const std::vector& search_template) : m_session(session), m_search_terminated(false) { module()->C_FindObjectsInit(m_session.get().handle(), const_cast< Attribute* >(search_template.data()), static_cast(search_template.size())); } ObjectFinder::~ObjectFinder() noexcept { try { if(m_search_terminated == false) { module()->C_FindObjectsFinal(m_session.get().handle(), nullptr); } } catch(...) { // ignore error during noexcept function } } std::vector ObjectFinder::find(uint32_t max_count) const { std::vector result(max_count); Ulong objectCount = 0; module()->C_FindObjects(m_session.get().handle(), result.data(), max_count, &objectCount); if(objectCount < max_count) { result.resize(objectCount); } return result; } void ObjectFinder::finish() { module()->C_FindObjectsFinal(m_session.get().handle()); m_search_terminated = true; } // ==================================================================================================== ObjectProperties::ObjectProperties(ObjectClass object_class) : AttributeContainer(object_class), m_object_class(object_class) {} // ==================================================================================================== StorageObjectProperties::StorageObjectProperties(ObjectClass object_class) : ObjectProperties(object_class) {} // ==================================================================================================== DataObjectProperties::DataObjectProperties() : StorageObjectProperties(ObjectClass::Data) {} // ==================================================================================================== CertificateProperties::CertificateProperties(CertificateType cert_type) : StorageObjectProperties(ObjectClass::Certificate), m_cert_type(cert_type) { add_numeric(AttributeType::CertificateType, static_cast< CK_CERTIFICATE_TYPE >(m_cert_type)); } // ==================================================================================================== KeyProperties::KeyProperties(ObjectClass object_class, KeyType key_type) : StorageObjectProperties(object_class), m_key_type(key_type) { add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type)); } // ==================================================================================================== PublicKeyProperties::PublicKeyProperties(KeyType key_type) : KeyProperties(ObjectClass::PublicKey, key_type) {} // ==================================================================================================== PrivateKeyProperties::PrivateKeyProperties(KeyType key_type) : KeyProperties(ObjectClass::PrivateKey, key_type) {} // ==================================================================================================== SecretKeyProperties::SecretKeyProperties(KeyType key_type) : KeyProperties(ObjectClass::SecretKey, key_type) {} // ==================================================================================================== DomainParameterProperties::DomainParameterProperties(KeyType key_type) : StorageObjectProperties(ObjectClass::DomainParameters), m_key_type(key_type) { add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type)); } // ==================================================================================================== Object::Object(Session& session, ObjectHandle handle) : m_session(session), m_handle(handle) {} Object::Object(Session& session, const ObjectProperties& obj_props) : m_session(session), m_handle(0) { m_session.get().module()->C_CreateObject(m_session.get().handle(), obj_props.data(), static_cast(obj_props.count()), &m_handle); } secure_vector Object::get_attribute_value(AttributeType attribute) const { std::map> attribute_map = { { attribute, secure_vector() } }; module()->C_GetAttributeValue(m_session.get().handle(), m_handle, attribute_map); return attribute_map.at(attribute); } void Object::set_attribute_value(AttributeType attribute, const secure_vector& value) const { std::map> attribute_map = { { attribute, value } }; module()->C_SetAttributeValue(m_session.get().handle(), m_handle, attribute_map); } void Object::destroy() const { module()->C_DestroyObject(m_session.get().handle(), m_handle); } ObjectHandle Object::copy(const AttributeContainer& modified_attributes) const { ObjectHandle copied_handle; module()->C_CopyObject(m_session.get().handle(), m_handle, modified_attributes.data(), static_cast(modified_attributes.count()), &copied_handle); return copied_handle; } } } /* * PKCS#11 Random Generator * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace PKCS11 { PKCS11_RNG::PKCS11_RNG(Session& session) : m_session(session) {} void PKCS11_RNG::randomize(uint8_t output[], std::size_t length) { module()->C_GenerateRandom(m_session.get().handle(), output, Ulong(length)); } void PKCS11_RNG::add_entropy(const uint8_t in[], std::size_t length) { module()->C_SeedRandom(m_session.get().handle(), const_cast(in), Ulong(length)); } } } /* * PKCS#11 RSA * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_RSA) namespace Botan { namespace PKCS11 { RSA_PublicKeyImportProperties::RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent) : PublicKeyProperties(KeyType::Rsa), m_modulus(modulus), m_pub_exponent(pub_exponent) { add_binary(AttributeType::Modulus, BigInt::encode(m_modulus)); add_binary(AttributeType::PublicExponent, BigInt::encode(m_pub_exponent)); } RSA_PublicKeyGenerationProperties::RSA_PublicKeyGenerationProperties(Ulong bits) : PublicKeyProperties(KeyType::Rsa) { add_numeric(AttributeType::ModulusBits, bits); } PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle) : Object(session, handle), RSA_PublicKey(BigInt::decode(get_attribute_value(AttributeType::Modulus)), BigInt::decode(get_attribute_value(AttributeType::PublicExponent))) { } PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props) : Object(session, pubkey_props), RSA_PublicKey(pubkey_props.modulus(), pubkey_props.pub_exponent()) {} RSA_PrivateKeyImportProperties::RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent) : PrivateKeyProperties(KeyType::Rsa), m_modulus(modulus), m_priv_exponent(priv_exponent) { add_binary(AttributeType::Modulus, BigInt::encode(m_modulus)); add_binary(AttributeType::PrivateExponent, BigInt::encode(m_priv_exponent)); } PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle) : Object(session, handle), RSA_PublicKey(BigInt::decode(get_attribute_value(AttributeType::Modulus)), BigInt::decode(get_attribute_value(AttributeType::PublicExponent))) { } PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props) : Object(session, priv_key_props), RSA_PublicKey(priv_key_props.modulus(), BigInt::decode(get_attribute_value(AttributeType::PublicExponent))) { } PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props) : Object(session), RSA_PublicKey() { RSA_PublicKeyGenerationProperties pub_key_props(bits); pub_key_props.set_encrypt(true); pub_key_props.set_verify(true); pub_key_props.set_token(false); // don't create a persistent public key object ObjectHandle pub_key_handle = CK_INVALID_HANDLE; ObjectHandle priv_key_handle = CK_INVALID_HANDLE; Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 }; session.module()->C_GenerateKeyPair(session.handle(), &mechanism, pub_key_props.data(), static_cast(pub_key_props.count()), priv_key_props.data(), static_cast(priv_key_props.count()), &pub_key_handle, &priv_key_handle); this->reset_handle(priv_key_handle); BigInt n = BigInt::decode(get_attribute_value(AttributeType::Modulus)); BigInt e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent)); RSA_PublicKey::init(std::move(n), std::move(e)); } RSA_PrivateKey PKCS11_RSA_PrivateKey::export_key() const { auto p = get_attribute_value(AttributeType::Prime1); auto q = get_attribute_value(AttributeType::Prime2); auto e = get_attribute_value(AttributeType::PublicExponent); auto d = get_attribute_value(AttributeType::PrivateExponent); auto n = get_attribute_value(AttributeType::Modulus); return RSA_PrivateKey( BigInt::decode(p) , BigInt::decode(q) , BigInt::decode(e) , BigInt::decode(d) , BigInt::decode(n)); } secure_vector PKCS11_RSA_PrivateKey::private_key_bits() const { return export_key().private_key_bits(); } namespace { // note: multiple-part decryption operations (with C_DecryptUpdate/C_DecryptFinal) // are not supported (PK_Ops::Decryption does not provide an `update` method) class PKCS11_RSA_Decryption_Operation final : public PK_Ops::Decryption { public: PKCS11_RSA_Decryption_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding, RandomNumberGenerator& rng) : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)), m_blinder(m_key.get_n(), rng, [ this ](const BigInt& k) { return power_mod(k, m_key.get_e(), m_key.get_n()); }, [ this ](const BigInt& k) { return inverse_mod(k, m_key.get_n()); }) { m_bits = m_key.get_n().bits() - 1; } size_t plaintext_length(size_t) const override { return m_key.get_n().bytes(); } secure_vector decrypt(uint8_t& valid_mask, const uint8_t ciphertext[], size_t ciphertext_len) override { valid_mask = 0; m_key.module()->C_DecryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); std::vector encrypted_data(ciphertext, ciphertext + ciphertext_len); // blind for RSA/RAW decryption if(! m_mechanism.padding_size()) { encrypted_data = BigInt::encode(m_blinder.blind(BigInt::decode(encrypted_data))); } secure_vector decrypted_data; m_key.module()->C_Decrypt(m_key.session().handle(), encrypted_data, decrypted_data); // Unblind for RSA/RAW decryption if(!m_mechanism.padding_size()) { decrypted_data = BigInt::encode_1363(m_blinder.unblind(BigInt::decode(decrypted_data)), m_key.get_n().bits() / 8 ); } valid_mask = 0xFF; return decrypted_data; } private: const PKCS11_RSA_PrivateKey& m_key; MechanismWrapper m_mechanism; size_t m_bits = 0; Blinder m_blinder; }; // note: multiple-part encryption operations (with C_EncryptUpdate/C_EncryptFinal) // are not supported (PK_Ops::Encryption does not provide an `update` method) class PKCS11_RSA_Encryption_Operation final : public PK_Ops::Encryption { public: PKCS11_RSA_Encryption_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding) : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)) { m_bits = 8 * (key.get_n().bytes() - m_mechanism.padding_size()) - 1; } size_t ciphertext_length(size_t) const override { return m_key.get_n().bytes(); } size_t max_input_bits() const override { return m_bits; } secure_vector encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator&) override { m_key.module()->C_EncryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); secure_vector encrytped_data; m_key.module()->C_Encrypt(m_key.session().handle(), secure_vector(msg, msg + msg_len), encrytped_data); return encrytped_data; } private: const PKCS11_RSA_PublicKey& m_key; MechanismWrapper m_mechanism; size_t m_bits = 0; }; class PKCS11_RSA_Signature_Operation final : public PK_Ops::Signature { public: PKCS11_RSA_Signature_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding) : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding)) {} size_t signature_length() const override { return m_key.get_n().bytes(); } void update(const uint8_t msg[], size_t msg_len) override { if(!m_initialized) { // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); m_initialized = true; m_first_message = secure_vector(msg, msg + msg_len); return; } if(!m_first_message.empty()) { // second call to update: start multiple-part operation m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message); m_first_message.clear(); } m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast< Byte* >(msg), static_cast(msg_len)); } secure_vector sign(RandomNumberGenerator&) override { secure_vector signature; if(!m_first_message.empty()) { // single call to update: perform single-part operation m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature); m_first_message.clear(); } else { // multiple calls to update (or none): finish multiple-part operation m_key.module()->C_SignFinal(m_key.session().handle(), signature); } m_initialized = false; return signature; } private: const PKCS11_RSA_PrivateKey& m_key; bool m_initialized = false; secure_vector m_first_message; MechanismWrapper m_mechanism; }; class PKCS11_RSA_Verification_Operation final : public PK_Ops::Verification { public: PKCS11_RSA_Verification_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding) : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding)) {} void update(const uint8_t msg[], size_t msg_len) override { if(!m_initialized) { // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); m_initialized = true; m_first_message = secure_vector(msg, msg + msg_len); return; } if(!m_first_message.empty()) { // second call to update: start multiple-part operation m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message); m_first_message.clear(); } m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast< Byte* >(msg), static_cast(msg_len)); } bool is_valid_signature(const uint8_t sig[], size_t sig_len) override { ReturnValue return_value = ReturnValue::SignatureInvalid; if(!m_first_message.empty()) { // single call to update: perform single-part operation m_key.module()->C_Verify(m_key.session().handle(), m_first_message.data(), static_cast(m_first_message.size()), const_cast< Byte* >(sig), static_cast(sig_len), &return_value); m_first_message.clear(); } else { // multiple calls to update (or none): finish multiple-part operation m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast< Byte* >(sig), static_cast(sig_len), &return_value); } m_initialized = false; if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid) { throw PKCS11_ReturnError(return_value); } return return_value == ReturnValue::OK; } private: const PKCS11_RSA_PublicKey& m_key; bool m_initialized = false; secure_vector m_first_message; MechanismWrapper m_mechanism; }; } std::unique_ptr PKCS11_RSA_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_RSA_Encryption_Operation(*this, params)); } std::unique_ptr PKCS11_RSA_PublicKey::create_verification_op(const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_RSA_Verification_Operation(*this, params)); } std::unique_ptr PKCS11_RSA_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_RSA_Decryption_Operation(*this, params, rng)); } std::unique_ptr PKCS11_RSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& /*provider*/) const { return std::unique_ptr(new PKCS11_RSA_Signature_Operation(*this, params)); } PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props, const RSA_PrivateKeyGenerationProperties& priv_props) { ObjectHandle pub_key_handle = 0; ObjectHandle priv_key_handle = 0; Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 }; session.module()->C_GenerateKeyPair(session.handle(), &mechanism, pub_props.data(), static_cast(pub_props.count()), priv_props.data(), static_cast(priv_props.count()), &pub_key_handle, &priv_key_handle); return std::make_pair(PKCS11_RSA_PublicKey(session, pub_key_handle), PKCS11_RSA_PrivateKey(session, priv_key_handle)); } } } #endif /* * PKCS#11 Session * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace PKCS11 { Session::Session(Slot& slot, bool read_only) : Session(slot, PKCS11::flags(Flag::SerialSession | (read_only ? Flag::None : Flag::RwSession)), nullptr, nullptr) {} Session::Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback) : m_slot(slot), m_handle(0), m_logged_in(false) { module()->C_OpenSession(m_slot.slot_id(), flags, callback_data, notify_callback, &m_handle); } Session::Session(Slot& slot, SessionHandle handle) : m_slot(slot), m_handle(handle) { SessionInfo info = get_info(); if(info.state == static_cast(SessionState::RoPublicSession) || info.state == static_cast(SessionState::RwPublicSession)) { m_logged_in = false; } else { m_logged_in = true; } } Session::~Session() noexcept { try { if(m_handle) { if(m_logged_in) { module()->C_Logout(m_handle, nullptr); } module()->C_CloseSession(m_handle, nullptr); m_handle = 0; } } catch(...) { // exception during noexcept destructor is ignored } } SessionHandle Session::release() { SessionHandle handle = 0; std::swap(handle, m_handle); return handle; } void Session::login(UserType user_type, const secure_string& pin) { module()->C_Login(m_handle, user_type, pin); m_logged_in = true; } void Session::logoff() { module()->C_Logout(m_handle); m_logged_in = false; } SessionInfo Session::get_info() const { SessionInfo info; module()->C_GetSessionInfo(m_handle, &info); return info; } void Session::set_pin(const secure_string& old_pin, const secure_string& new_pin) const { module()->C_SetPIN(m_handle, old_pin, new_pin); } void Session::init_pin(const secure_string& new_pin) { module()->C_InitPIN(m_handle, new_pin); } } } /* * PKCS#11 Slot * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace PKCS11 { Slot::Slot(Module& module, SlotId slot_id) : m_module(module), m_slot_id(slot_id) {} SlotInfo Slot::get_slot_info() const { SlotInfo slot_info = {}; m_module.get()->C_GetSlotInfo(m_slot_id, &slot_info); return slot_info; } std::vector Slot::get_mechanism_list() const { std::vector mechanism_list; m_module.get()->C_GetMechanismList(m_slot_id, mechanism_list); return mechanism_list; } MechanismInfo Slot::get_mechanism_info(MechanismType mechanism_type) const { MechanismInfo mechanism_info = {}; m_module.get()->C_GetMechanismInfo(m_slot_id, mechanism_type, &mechanism_info); return mechanism_info; } std::vector Slot::get_available_slots(Module& module, bool token_present) { std::vector slot_vec; module->C_GetSlotList(token_present, slot_vec); return slot_vec; } TokenInfo Slot::get_token_info() const { TokenInfo token_info; m_module.get()->C_GetTokenInfo(m_slot_id, &token_info); return token_info; } void Slot::initialize(const std::string& label, const secure_string& so_pin) const { m_module.get()->C_InitToken(m_slot_id, so_pin, label); } } } /* * PKCS#11 X.509 * (C) 2016 Daniel Neus, Sirrix AG * (C) 2016 Philipp Weber, Sirrix AG * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_X509_CERTIFICATES) namespace Botan { namespace PKCS11 { X509_CertificateProperties::X509_CertificateProperties(const std::vector& subject, const std::vector& value) : CertificateProperties(CertificateType::X509), m_subject(subject), m_value(value) { add_binary(AttributeType::Subject, m_subject); add_binary(AttributeType::Value, m_value); } PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, ObjectHandle handle) : Object(session, handle), X509_Certificate(unlock(get_attribute_value(AttributeType::Value))) { } PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props) : Object(session, props), X509_Certificate(props.value()) { } } } #endif /* * Derived from poly1305-donna-64.h by Andrew Moon * in https://github.com/floodyberry/poly1305-donna * * (C) 2014 Andrew Moon * (C) 2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void poly1305_init(secure_vector& X, const uint8_t key[32]) { /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ const uint64_t t0 = load_le(key, 0); const uint64_t t1 = load_le(key, 1); X[0] = ( t0 ) & 0xffc0fffffff; X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; X[2] = ((t1 >> 24) ) & 0x00ffffffc0f; /* h = 0 */ X[3] = 0; X[4] = 0; X[5] = 0; /* save pad for later */ X[6] = load_le(key, 2); X[7] = load_le(key, 3); } void poly1305_blocks(secure_vector& X, const uint8_t *m, size_t blocks, bool is_final = false) { #if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) typedef donna128 uint128_t; #endif const uint64_t hibit = is_final ? 0 : (static_cast(1) << 40); /* 1 << 128 */ const uint64_t r0 = X[0]; const uint64_t r1 = X[1]; const uint64_t r2 = X[2]; const uint64_t M44 = 0xFFFFFFFFFFF; const uint64_t M42 = 0x3FFFFFFFFFF; uint64_t h0 = X[3+0]; uint64_t h1 = X[3+1]; uint64_t h2 = X[3+2]; const uint64_t s1 = r1 * 20; const uint64_t s2 = r2 * 20; for(size_t i = 0; i != blocks; ++i) { const uint64_t t0 = load_le(m, 0); const uint64_t t1 = load_le(m, 1); h0 += (( t0 ) & M44); h1 += (((t0 >> 44) | (t1 << 20)) & M44); h2 += (((t1 >> 24) ) & M42) | hibit; const uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1; const uint64_t c0 = carry_shift(d0, 44); const uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2 + c0; const uint64_t c1 = carry_shift(d1, 44); const uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0 + c1; const uint64_t c2 = carry_shift(d2, 42); h0 = d0 & M44; h1 = d1 & M44; h2 = d2 & M42; h0 += c2 * 5; h1 += carry_shift(h0, 44); h0 = h0 & M44; m += 16; } X[3+0] = h0; X[3+1] = h1; X[3+2] = h2; } void poly1305_finish(secure_vector& X, uint8_t mac[16]) { const uint64_t M44 = 0xFFFFFFFFFFF; const uint64_t M42 = 0x3FFFFFFFFFF; /* fully carry h */ uint64_t h0 = X[3+0]; uint64_t h1 = X[3+1]; uint64_t h2 = X[3+2]; uint64_t c; c = (h1 >> 44); h1 &= M44; h2 += c; c = (h2 >> 42); h2 &= M42; h0 += c * 5; c = (h0 >> 44); h0 &= M44; h1 += c; c = (h1 >> 44); h1 &= M44; h2 += c; c = (h2 >> 42); h2 &= M42; h0 += c * 5; c = (h0 >> 44); h0 &= M44; h1 += c; /* compute h + -p */ uint64_t g0 = h0 + 5; c = (g0 >> 44); g0 &= M44; uint64_t g1 = h1 + c; c = (g1 >> 44); g1 &= M44; uint64_t g2 = h2 + c - (static_cast(1) << 42); /* select h if h < p, or h + -p if h >= p */ const auto c_mask = CT::Mask::expand(c); h0 = c_mask.select(g0, h0); h1 = c_mask.select(g1, h1); h2 = c_mask.select(g2, h2); /* h = (h + pad) */ const uint64_t t0 = X[6]; const uint64_t t1 = X[7]; h0 += (( t0 ) & M44) ; c = (h0 >> 44); h0 &= M44; h1 += (((t0 >> 44) | (t1 << 20)) & M44) + c; c = (h1 >> 44); h1 &= M44; h2 += (((t1 >> 24) ) & M42) + c; h2 &= M42; /* mac = h % (2^128) */ h0 = ((h0 ) | (h1 << 44)); h1 = ((h1 >> 20) | (h2 << 24)); store_le(mac, h0, h1); /* zero out the state */ clear_mem(X.data(), X.size()); } } void Poly1305::clear() { zap(m_poly); zap(m_buf); m_buf_pos = 0; } void Poly1305::key_schedule(const uint8_t key[], size_t) { m_buf_pos = 0; m_buf.resize(16); m_poly.resize(8); poly1305_init(m_poly, key); } void Poly1305::add_data(const uint8_t input[], size_t length) { verify_key_set(m_poly.size() == 8); if(m_buf_pos) { buffer_insert(m_buf, m_buf_pos, input, length); if(m_buf_pos + length >= m_buf.size()) { poly1305_blocks(m_poly, m_buf.data(), 1); input += (m_buf.size() - m_buf_pos); length -= (m_buf.size() - m_buf_pos); m_buf_pos = 0; } } const size_t full_blocks = length / m_buf.size(); const size_t remaining = length % m_buf.size(); if(full_blocks) poly1305_blocks(m_poly, input, full_blocks); buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining); m_buf_pos += remaining; } void Poly1305::final_result(uint8_t out[]) { verify_key_set(m_poly.size() == 8); if(m_buf_pos != 0) { m_buf[m_buf_pos] = 1; const size_t len = m_buf.size() - m_buf_pos - 1; if (len > 0) { clear_mem(&m_buf[m_buf_pos+1], len); } poly1305_blocks(m_poly, m_buf.data(), 1, true); } poly1305_finish(m_poly, out); m_poly.clear(); m_buf_pos = 0; } } /* * (C) 2017,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * The minimum weight irreducible binary polynomial of size n * * See http://www.hpl.hp.com/techreports/98/HPL-98-135.pdf */ enum class MinWeightPolynomial : uint64_t { P64 = 0x1B, P128 = 0x87, P192 = 0x87, P256 = 0x425, P512 = 0x125, P1024 = 0x80043, }; template void poly_double(uint8_t out[], const uint8_t in[]) { uint64_t W[LIMBS]; load_be(W, in, LIMBS); const uint64_t POLY = static_cast(P); const uint64_t carry = POLY * (W[0] >> 63); BOTAN_IF_CONSTEXPR(LIMBS > 0) { for(size_t i = 0; i != LIMBS - 1; ++i) W[i] = (W[i] << 1) ^ (W[i+1] >> 63); } W[LIMBS-1] = (W[LIMBS-1] << 1) ^ carry; copy_out_be(out, LIMBS*8, W); } template void poly_double_le(uint8_t out[], const uint8_t in[]) { uint64_t W[LIMBS]; load_le(W, in, LIMBS); const uint64_t POLY = static_cast(P); const uint64_t carry = POLY * (W[LIMBS-1] >> 63); BOTAN_IF_CONSTEXPR(LIMBS > 0) { for(size_t i = 0; i != LIMBS - 1; ++i) W[LIMBS-1-i] = (W[LIMBS-1-i] << 1) ^ (W[LIMBS-2-i] >> 63); } W[0] = (W[0] << 1) ^ carry; copy_out_le(out, LIMBS*8, W); } } void poly_double_n(uint8_t out[], const uint8_t in[], size_t n) { switch(n) { case 8: return poly_double<1, MinWeightPolynomial::P64>(out, in); case 16: return poly_double<2, MinWeightPolynomial::P128>(out, in); case 24: return poly_double<3, MinWeightPolynomial::P192>(out, in); case 32: return poly_double<4, MinWeightPolynomial::P256>(out, in); case 64: return poly_double<8, MinWeightPolynomial::P512>(out, in); case 128: return poly_double<16, MinWeightPolynomial::P1024>(out, in); default: throw Invalid_Argument("Unsupported size for poly_double_n"); } } void poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n) { switch(n) { case 8: return poly_double_le<1, MinWeightPolynomial::P64>(out, in); case 16: return poly_double_le<2, MinWeightPolynomial::P128>(out, in); case 24: return poly_double_le<3, MinWeightPolynomial::P192>(out, in); case 32: return poly_double_le<4, MinWeightPolynomial::P256>(out, in); case 64: return poly_double_le<8, MinWeightPolynomial::P512>(out, in); case 128: return poly_double_le<16, MinWeightPolynomial::P1024>(out, in); default: throw Invalid_Argument("Unsupported size for poly_double_n_le"); } } } /* * TLS v1.0 and v1.2 PRFs * (C) 2004-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { TLS_PRF::TLS_PRF() : TLS_PRF(MessageAuthenticationCode::create_or_throw("HMAC(MD5)"), MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)")) { } namespace { /* * TLS PRF P_hash function */ void P_hash(uint8_t out[], size_t out_len, MessageAuthenticationCode& mac, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len) { try { mac.set_key(secret, secret_len); } catch(Invalid_Key_Length&) { throw Internal_Error("The premaster secret of " + std::to_string(secret_len) + " bytes is too long for the PRF"); } secure_vector A(salt, salt + salt_len); secure_vector h; size_t offset = 0; while(offset != out_len) { A = mac.process(A); mac.update(A); mac.update(salt, salt_len); mac.final(h); const size_t writing = std::min(h.size(), out_len - offset); xor_buf(&out[offset], h.data(), writing); offset += writing; } } } size_t TLS_PRF::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { const size_t S1_len = (secret_len + 1) / 2, S2_len = (secret_len + 1) / 2; const uint8_t* S1 = secret; const uint8_t* S2 = secret + (secret_len - S2_len); secure_vector msg; msg.reserve(label_len + salt_len); msg += std::make_pair(label, label_len); msg += std::make_pair(salt, salt_len); P_hash(key, key_len, *m_hmac_md5, S1, S1_len, msg.data(), msg.size()); P_hash(key, key_len, *m_hmac_sha1, S2, S2_len, msg.data(), msg.size()); return key_len; } size_t TLS_12_PRF::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { secure_vector msg; msg.reserve(label_len + salt_len); msg += std::make_pair(label, label_len); msg += std::make_pair(salt, salt_len); P_hash(key, key_len, *m_mac, secret, secret_len, msg.data(), msg.size()); return key_len; } } /* * X9.42 PRF * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Encode an integer as an OCTET STRING */ std::vector encode_x942_int(uint32_t n) { uint8_t n_buf[4] = { 0 }; store_be(n, n_buf); std::vector output; DER_Encoder(output).encode(n_buf, 4, OCTET_STRING); return output; } } size_t X942_PRF::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { std::unique_ptr hash(HashFunction::create("SHA-160")); secure_vector h; secure_vector in; size_t offset = 0; uint32_t counter = 1; in.reserve(salt_len + label_len); in += std::make_pair(label,label_len); in += std::make_pair(salt,salt_len); while(offset != key_len && counter) { hash->update(secret, secret_len); hash->update( DER_Encoder().start_cons(SEQUENCE) .start_cons(SEQUENCE) .encode(m_key_wrap_oid) .raw_bytes(encode_x942_int(counter)) .end_cons() .encode_if(salt_len != 0, DER_Encoder() .start_explicit(0) .encode(in, OCTET_STRING) .end_explicit() ) .start_explicit(2) .raw_bytes(encode_x942_int(static_cast(8 * key_len))) .end_explicit() .end_cons().get_contents() ); hash->final(h); const size_t copied = std::min(h.size(), key_len - offset); copy_mem(&key[offset], h.data(), copied); offset += copied; ++counter; } // FIXME: returns truncated output return offset; } std::string X942_PRF::name() const { return "X9.42-PRF(" + m_key_wrap_oid.to_formatted_string() + ")"; } } /* * (C) 2016,2019,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) && !defined(BOTAN_USE_GCC_INLINE_ASM) #endif namespace Botan { namespace { #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) /* * According to Intel, RDRAND is guaranteed to generate a random * number within 10 retries on a working CPU */ const size_t HWRNG_RETRIES = 10; #else /* * Lacking specific guidance we give the CPU quite a bit of leeway */ const size_t HWRNG_RETRIES = 512; #endif #if defined(BOTAN_TARGET_ARCH_IS_X86_32) typedef uint32_t hwrng_output; #else typedef uint64_t hwrng_output; #endif hwrng_output read_hwrng(bool& success) { hwrng_output output = 0; success = false; #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) int cf = 0; #if defined(BOTAN_USE_GCC_INLINE_ASM) // same asm seq works for 32 and 64 bit asm volatile("rdrand %0; adcl $0,%1" : "=r" (output), "=r" (cf) : "0" (output), "1" (cf) : "cc"); #elif defined(BOTAN_TARGET_ARCH_IS_X86_32) cf = _rdrand32_step(&output); #else cf = _rdrand64_step(&output); #endif success = (1 == cf); #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) /* DARN indicates error by returning 0xFF..FF, ie is biased. Which is crazy. Avoid the bias by invoking it twice and, assuming both succeed, returning the XOR of the two results, which should unbias the output. */ uint64_t output2 = 0; // DARN codes are 0: 32-bit conditioned, 1: 64-bit conditioned, 2: 64-bit raw (ala RDSEED) asm volatile("darn %0, 1" : "=r" (output)); asm volatile("darn %0, 1" : "=r" (output2)); if((~output) != 0 && (~output2) != 0) { output ^= output2; success = true; } #endif if(success) return output; return 0; } hwrng_output read_hwrng() { for(size_t i = 0; i < HWRNG_RETRIES; ++i) { bool success = false; hwrng_output output = read_hwrng(success); if(success) return output; } throw PRNG_Unseeded("Processor RNG instruction failed to produce output within expected iterations"); } } //static bool Processor_RNG::available() { #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) return CPUID::has_rdrand(); #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) return CPUID::has_darn_rng(); #else return false; #endif } std::string Processor_RNG::name() const { #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) return "rdrand"; #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) return "darn"; #else return "hwrng"; #endif } void Processor_RNG::randomize(uint8_t out[], size_t out_len) { while(out_len >= sizeof(hwrng_output)) { const hwrng_output r = read_hwrng(); store_le(r, out); out += sizeof(hwrng_output); out_len -= sizeof(hwrng_output); } if(out_len > 0) // at most sizeof(hwrng_output)-1 { const hwrng_output r = read_hwrng(); for(size_t i = 0; i != out_len; ++i) out[i] = get_byte(i, r); } } Processor_RNG::Processor_RNG() { if(!Processor_RNG::available()) throw Invalid_State("Current CPU does not support RNG instruction"); } void Processor_RNG::add_entropy(const uint8_t[], size_t) { /* no way to add entropy */ } size_t Processor_RNG::reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) { /* no way to add entropy */ return 0; } } /* * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Encrypted_PSK_Database::Encrypted_PSK_Database(const secure_vector& master_key) { m_cipher = BlockCipher::create_or_throw("AES-256"); m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); m_hmac->set_key(master_key); m_cipher->set_key(m_hmac->process("wrap")); m_hmac->set_key(m_hmac->process("hmac")); } Encrypted_PSK_Database::~Encrypted_PSK_Database() { // for ~unique_ptr } std::set Encrypted_PSK_Database::list_names() const { const std::set encrypted_names = kv_get_all(); std::set names; for(std::string enc_name : encrypted_names) { try { const secure_vector raw_name = base64_decode(enc_name); const secure_vector name_bits = nist_key_unwrap_padded(raw_name.data(), raw_name.size(), *m_cipher); std::string pt_name(cast_uint8_ptr_to_char(name_bits.data()), name_bits.size()); names.insert(pt_name); } catch(Invalid_Authentication_Tag&) { } } return names; } void Encrypted_PSK_Database::remove(const std::string& name) { const std::vector wrapped_name = nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher); this->kv_del(base64_encode(wrapped_name)); } secure_vector Encrypted_PSK_Database::get(const std::string& name) const { const std::vector wrapped_name = nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher); const std::string val_base64 = kv_get(base64_encode(wrapped_name)); if(val_base64.empty()) throw Invalid_Argument("Named PSK not located"); const secure_vector val = base64_decode(val_base64); std::unique_ptr wrap_cipher(m_cipher->clone()); wrap_cipher->set_key(m_hmac->process(wrapped_name)); return nist_key_unwrap_padded(val.data(), val.size(), *wrap_cipher); } void Encrypted_PSK_Database::set(const std::string& name, const uint8_t val[], size_t len) { /* * Both as a basic precaution wrt key seperation, and specifically to prevent * cut-and-paste attacks against the database, each PSK is encrypted with a * distinct key which is derived by hashing the wrapped key name with HMAC. */ const std::vector wrapped_name = nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher); std::unique_ptr wrap_cipher(m_cipher->clone()); wrap_cipher->set_key(m_hmac->process(wrapped_name)); const std::vector wrapped_key = nist_key_wrap_padded(val, len, *wrap_cipher); this->kv_set(base64_encode(wrapped_name), base64_encode(wrapped_key)); } } /* * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Encrypted_PSK_Database_SQL::Encrypted_PSK_Database_SQL(const secure_vector& master_key, std::shared_ptr db, const std::string& table_name) : Encrypted_PSK_Database(master_key), m_db(db), m_table_name(table_name) { m_db->create_table( "create table if not exists " + m_table_name + "(psk_name TEXT PRIMARY KEY, psk_value TEXT)"); } Encrypted_PSK_Database_SQL::~Encrypted_PSK_Database_SQL() { /* for ~unique_ptr */ } void Encrypted_PSK_Database_SQL::kv_del(const std::string& name) { auto stmt = m_db->new_statement("delete from " + m_table_name + " where psk_name=?1"); stmt->bind(1, name); stmt->spin(); } void Encrypted_PSK_Database_SQL::kv_set(const std::string& name, const std::string& value) { auto stmt = m_db->new_statement("insert or replace into " + m_table_name + " values(?1, ?2)"); stmt->bind(1, name); stmt->bind(2, value); stmt->spin(); } std::string Encrypted_PSK_Database_SQL::kv_get(const std::string& name) const { auto stmt = m_db->new_statement("select psk_value from " + m_table_name + " where psk_name = ?1"); stmt->bind(1, name); while(stmt->step()) { return stmt->get_str(0); } return ""; } std::set Encrypted_PSK_Database_SQL::kv_get_all() const { std::set names; auto stmt = m_db->new_statement("select psk_name from " + m_table_name); while(stmt->step()) { names.insert(stmt->get_str(0)); } return names; } } /* * Blinding for public key operations * (C) 1999-2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Blinder::Blinder(const BigInt& modulus, RandomNumberGenerator& rng, std::function fwd, std::function inv) : m_reducer(modulus), m_rng(rng), m_fwd_fn(fwd), m_inv_fn(inv), m_modulus_bits(modulus.bits()), m_e{}, m_d{}, m_counter{} { const BigInt k = blinding_nonce(); m_e = m_fwd_fn(k); m_d = m_inv_fn(k); } BigInt Blinder::blinding_nonce() const { return BigInt(m_rng, m_modulus_bits - 1); } BigInt Blinder::blind(const BigInt& i) const { if(!m_reducer.initialized()) throw Invalid_State("Blinder not initialized, cannot blind"); ++m_counter; if((BOTAN_BLINDING_REINIT_INTERVAL > 0) && (m_counter > BOTAN_BLINDING_REINIT_INTERVAL)) { const BigInt k = blinding_nonce(); m_e = m_fwd_fn(k); m_d = m_inv_fn(k); m_counter = 0; } else { m_e = m_reducer.square(m_e); m_d = m_reducer.square(m_d); } return m_reducer.multiply(i, m_e); } BigInt Blinder::unblind(const BigInt& i) const { if(!m_reducer.initialized()) throw Invalid_State("Blinder not initialized, cannot unblind"); return m_reducer.multiply(i, m_d); } } /* * PK Key * (C) 1999-2010,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_RSA) #endif #if defined(BOTAN_HAS_DSA) #endif #if defined(BOTAN_HAS_DL_GROUP) #endif #if defined(BOTAN_HAS_DIFFIE_HELLMAN) #endif #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) #endif #if defined(BOTAN_HAS_ECDSA) #endif #if defined(BOTAN_HAS_ECGDSA) #endif #if defined(BOTAN_HAS_ECKCDSA) #endif #if defined(BOTAN_HAS_ED25519) #endif #if defined(BOTAN_HAS_GOST_34_10_2001) #endif #if defined(BOTAN_HAS_ELGAMAL) #endif #if defined(BOTAN_HAS_ECDH) #endif #if defined(BOTAN_HAS_CURVE_25519) #endif #if defined(BOTAN_HAS_MCELIECE) #endif #if defined(BOTAN_HAS_XMSS_RFC8391) #endif #if defined(BOTAN_HAS_SM2) #endif #if defined(BOTAN_HAS_OPENSSL) #endif namespace Botan { std::unique_ptr load_public_key(const AlgorithmIdentifier& alg_id, const std::vector& key_bits) { const std::string oid_str = alg_id.get_oid().to_formatted_string(); const std::vector alg_info = split_on(oid_str, '/'); const std::string alg_name = alg_info[0]; #if defined(BOTAN_HAS_RSA) if(alg_name == "RSA") return std::unique_ptr(new RSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_CURVE_25519) if(alg_name == "Curve25519") return std::unique_ptr(new Curve25519_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_MCELIECE) if(alg_name == "McEliece") return std::unique_ptr(new McEliece_PublicKey(key_bits)); #endif #if defined(BOTAN_HAS_ECDSA) if(alg_name == "ECDSA") return std::unique_ptr(new ECDSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECDH) if(alg_name == "ECDH") return std::unique_ptr(new ECDH_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_DIFFIE_HELLMAN) if(alg_name == "DH") return std::unique_ptr(new DH_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_DSA) if(alg_name == "DSA") return std::unique_ptr(new DSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ELGAMAL) if(alg_name == "ElGamal") return std::unique_ptr(new ElGamal_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECGDSA) if(alg_name == "ECGDSA") return std::unique_ptr(new ECGDSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECKCDSA) if(alg_name == "ECKCDSA") return std::unique_ptr(new ECKCDSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ED25519) if(alg_name == "Ed25519") return std::unique_ptr(new Ed25519_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") return std::unique_ptr(new GOST_3410_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_SM2) if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") return std::unique_ptr(new SM2_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_XMSS_RFC8391) if(alg_name == "XMSS") return std::unique_ptr(new XMSS_PublicKey(key_bits)); #endif throw Decoding_Error("Unknown or unavailable public key algorithm " + alg_name); } std::unique_ptr load_private_key(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits) { const std::string alg_name = alg_id.get_oid().to_formatted_string(); #if defined(BOTAN_HAS_RSA) if(alg_name == "RSA") return std::unique_ptr(new RSA_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_CURVE_25519) if(alg_name == "Curve25519") return std::unique_ptr(new Curve25519_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECDSA) if(alg_name == "ECDSA") return std::unique_ptr(new ECDSA_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECDH) if(alg_name == "ECDH") return std::unique_ptr(new ECDH_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_DIFFIE_HELLMAN) if(alg_name == "DH") return std::unique_ptr(new DH_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_DSA) if(alg_name == "DSA") return std::unique_ptr(new DSA_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_MCELIECE) if(alg_name == "McEliece") return std::unique_ptr(new McEliece_PrivateKey(key_bits)); #endif #if defined(BOTAN_HAS_ECGDSA) if(alg_name == "ECGDSA") return std::unique_ptr(new ECGDSA_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECKCDSA) if(alg_name == "ECKCDSA") return std::unique_ptr(new ECKCDSA_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ED25519) if(alg_name == "Ed25519") return std::unique_ptr(new Ed25519_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") return std::unique_ptr(new GOST_3410_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_SM2) if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") return std::unique_ptr(new SM2_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ELGAMAL) if(alg_name == "ElGamal") return std::unique_ptr(new ElGamal_PrivateKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_XMSS_RFC8391) if(alg_name == "XMSS") return std::unique_ptr(new XMSS_PrivateKey(key_bits)); #endif throw Decoding_Error("Unknown or unavailable public key algorithm " + alg_name); } #if defined(BOTAN_HAS_ECC_GROUP) namespace { std::string default_ec_group_for(const std::string& alg_name) { if(alg_name == "SM2" || alg_name == "SM2_Enc" || alg_name == "SM2_Sig") return "sm2p256v1"; if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256") return "gost_256A"; if(alg_name == "GOST-34.10-2012-512") return "gost_512A"; if(alg_name == "ECGDSA") return "brainpool256r1"; return "secp256r1"; } } #endif std::unique_ptr create_private_key(const std::string& alg_name, RandomNumberGenerator& rng, const std::string& params, const std::string& provider) { /* * Default paramaters are chosen for work factor > 2**128 where possible */ #if defined(BOTAN_HAS_CURVE_25519) if(alg_name == "Curve25519") return std::unique_ptr(new Curve25519_PrivateKey(rng)); #endif #if defined(BOTAN_HAS_RSA) if(alg_name == "RSA") { const size_t rsa_bits = (params.empty() ? 3072 : to_u32bit(params)); #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { std::unique_ptr pk; if((pk = make_openssl_rsa_private_key(rng, rsa_bits))) return pk; if(!provider.empty()) return nullptr; } #endif return std::unique_ptr(new RSA_PrivateKey(rng, rsa_bits)); } #endif #if defined(BOTAN_HAS_MCELIECE) if(alg_name == "McEliece") { std::vector mce_param = Botan::split_on(params.empty() ? "2960,57" : params, ','); if(mce_param.size() != 2) throw Invalid_Argument("create_private_key bad McEliece parameters " + params); size_t mce_n = Botan::to_u32bit(mce_param[0]); size_t mce_t = Botan::to_u32bit(mce_param[1]); return std::unique_ptr(new Botan::McEliece_PrivateKey(rng, mce_n, mce_t)); } #endif #if defined(BOTAN_HAS_XMSS_RFC8391) if(alg_name == "XMSS") { return std::unique_ptr( new XMSS_PrivateKey(XMSS_Parameters(params.empty() ? "XMSS-SHA2_10_512" : params).oid(), rng)); } #endif #if defined(BOTAN_HAS_ED25519) if(alg_name == "Ed25519") { return std::unique_ptr(new Ed25519_PrivateKey(rng)); } #endif // ECC crypto #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) if(alg_name == "ECDSA" || alg_name == "ECDH" || alg_name == "ECKCDSA" || alg_name == "ECGDSA" || alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc" || alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") { const EC_Group ec_group(params.empty() ? default_ec_group_for(alg_name) : params); #if defined(BOTAN_HAS_ECDSA) if(alg_name == "ECDSA") return std::unique_ptr(new ECDSA_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_ECDH) if(alg_name == "ECDH") return std::unique_ptr(new ECDH_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_ECKCDSA) if(alg_name == "ECKCDSA") return std::unique_ptr(new ECKCDSA_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") return std::unique_ptr(new GOST_3410_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_SM2) if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") return std::unique_ptr(new SM2_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_ECGDSA) if(alg_name == "ECGDSA") return std::unique_ptr(new ECGDSA_PrivateKey(rng, ec_group)); #endif } #endif // DL crypto #if defined(BOTAN_HAS_DL_GROUP) if(alg_name == "DH" || alg_name == "DSA" || alg_name == "ElGamal") { std::string default_group = (alg_name == "DSA") ? "dsa/botan/2048" : "modp/ietf/2048"; DL_Group modp_group(params.empty() ? default_group : params); #if defined(BOTAN_HAS_DIFFIE_HELLMAN) if(alg_name == "DH") return std::unique_ptr(new DH_PrivateKey(rng, modp_group)); #endif #if defined(BOTAN_HAS_DSA) if(alg_name == "DSA") return std::unique_ptr(new DSA_PrivateKey(rng, modp_group)); #endif #if defined(BOTAN_HAS_ELGAMAL) if(alg_name == "ElGamal") return std::unique_ptr(new ElGamal_PrivateKey(rng, modp_group)); #endif } #endif BOTAN_UNUSED(alg_name, rng, params, provider); return std::unique_ptr(); } std::vector probe_provider_private_key(const std::string& alg_name, const std::vector possible) { std::vector providers; for(auto&& prov : possible) { if(prov == "base" || #if defined(BOTAN_HAS_OPENSSL) (prov == "openssl" && alg_name == "RSA") || #endif 0) { providers.push_back(prov); // available } } BOTAN_UNUSED(alg_name); return providers; } } /* * PK Key Types * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string create_hex_fingerprint(const uint8_t bits[], size_t bits_len, const std::string& hash_name) { std::unique_ptr hash_fn(HashFunction::create_or_throw(hash_name)); const std::string hex_hash = hex_encode(hash_fn->process(bits, bits_len)); std::string fprint; for(size_t i = 0; i != hex_hash.size(); i += 2) { if(i != 0) fprint.push_back(':'); fprint.push_back(hex_hash[i]); fprint.push_back(hex_hash[i+1]); } return fprint; } std::vector Public_Key::subject_public_key() const { std::vector output; DER_Encoder(output).start_cons(SEQUENCE) .encode(algorithm_identifier()) .encode(public_key_bits(), BIT_STRING) .end_cons(); return output; } /* * Default OID access */ OID Public_Key::get_oid() const { const OID o = OIDS::str2oid_or_empty(algo_name()); if(o.empty()) throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs"); return o; } secure_vector Private_Key::private_key_info() const { const size_t PKCS8_VERSION = 0; return DER_Encoder() .start_cons(SEQUENCE) .encode(PKCS8_VERSION) .encode(pkcs8_algorithm_identifier()) .encode(private_key_bits(), OCTET_STRING) .end_cons() .get_contents(); } /* * Hash of the X.509 subjectPublicKey encoding */ std::string Public_Key::fingerprint_public(const std::string& hash_algo) const { return create_hex_fingerprint(subject_public_key(), hash_algo); } /* * Hash of the PKCS #8 encoding for this key object */ std::string Private_Key::fingerprint_private(const std::string& hash_algo) const { return create_hex_fingerprint(private_key_bits(), hash_algo); } std::unique_ptr Public_Key::create_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support encryption"); } std::unique_ptr Public_Key::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support KEM encryption"); } std::unique_ptr Public_Key::create_verification_op(const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support verification"); } std::unique_ptr Private_Key::create_decryption_op(RandomNumberGenerator& /*rng*/, const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support decryption"); } std::unique_ptr Private_Key::create_kem_decryption_op(RandomNumberGenerator& /*rng*/, const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support KEM decryption"); } std::unique_ptr Private_Key::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support signatures"); } std::unique_ptr Private_Key::create_key_agreement_op(RandomNumberGenerator& /*rng*/, const std::string& /*params*/, const std::string& /*provider*/) const { throw Lookup_Error(algo_name() + " does not support key agreement"); } } /* * PK Operation Types * (C) 2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { PK_Ops::Encryption_with_EME::Encryption_with_EME(const std::string& eme) { m_eme.reset(get_eme(eme)); if(!m_eme.get()) throw Algorithm_Not_Found(eme); } size_t PK_Ops::Encryption_with_EME::max_input_bits() const { return 8 * m_eme->maximum_input_size(max_raw_input_bits()); } secure_vector PK_Ops::Encryption_with_EME::encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) { const size_t max_raw = max_raw_input_bits(); const std::vector encoded = unlock(m_eme->encode(msg, msg_len, max_raw, rng)); return raw_encrypt(encoded.data(), encoded.size(), rng); } PK_Ops::Decryption_with_EME::Decryption_with_EME(const std::string& eme) { m_eme.reset(get_eme(eme)); if(!m_eme.get()) throw Algorithm_Not_Found(eme); } secure_vector PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, const uint8_t ciphertext[], size_t ciphertext_len) { const secure_vector raw = raw_decrypt(ciphertext, ciphertext_len); return m_eme->unpad(valid_mask, raw.data(), raw.size()); } PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(const std::string& kdf) { if(kdf != "Raw") m_kdf.reset(get_kdf(kdf)); } secure_vector PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len, const uint8_t w[], size_t w_len, const uint8_t salt[], size_t salt_len) { secure_vector z = raw_agree(w, w_len); if(m_kdf) return m_kdf->derive_key(key_len, z, salt, salt_len); return z; } PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa) : Signature(), m_emsa(get_emsa(emsa)), m_hash(hash_for_emsa(emsa)), m_prefix_used(false) { if(!m_emsa) throw Algorithm_Not_Found(emsa); } void PK_Ops::Signature_with_EMSA::update(const uint8_t msg[], size_t msg_len) { if(has_prefix() && !m_prefix_used) { m_prefix_used = true; secure_vector prefix = message_prefix(); m_emsa->update(prefix.data(), prefix.size()); } m_emsa->update(msg, msg_len); } secure_vector PK_Ops::Signature_with_EMSA::sign(RandomNumberGenerator& rng) { m_prefix_used = false; const secure_vector msg = m_emsa->raw_data(); const auto padded = m_emsa->encoding_of(msg, this->max_input_bits(), rng); return raw_sign(padded.data(), padded.size(), rng); } PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa) : Verification(), m_emsa(get_emsa(emsa)), m_hash(hash_for_emsa(emsa)), m_prefix_used(false) { if(!m_emsa) throw Algorithm_Not_Found(emsa); } void PK_Ops::Verification_with_EMSA::update(const uint8_t msg[], size_t msg_len) { if(has_prefix() && !m_prefix_used) { m_prefix_used = true; secure_vector prefix = message_prefix(); m_emsa->update(prefix.data(), prefix.size()); } m_emsa->update(msg, msg_len); } bool PK_Ops::Verification_with_EMSA::is_valid_signature(const uint8_t sig[], size_t sig_len) { m_prefix_used = false; const secure_vector msg = m_emsa->raw_data(); if(with_recovery()) { secure_vector output_of_key = verify_mr(sig, sig_len); return m_emsa->verify(output_of_key, msg, max_input_bits()); } else { Null_RNG rng; secure_vector encoded = m_emsa->encoding_of(msg, max_input_bits(), rng); return verify(encoded.data(), encoded.size(), sig, sig_len); } } void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(secure_vector& out_encapsulated_key, secure_vector& out_shared_key, size_t desired_shared_key_len, Botan::RandomNumberGenerator& rng, const uint8_t salt[], size_t salt_len) { secure_vector raw_shared; this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng); out_shared_key = m_kdf->derive_key(desired_shared_key_len, raw_shared.data(), raw_shared.size(), salt, salt_len); } PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(const std::string& kdf) { m_kdf.reset(get_kdf(kdf)); } secure_vector PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(const uint8_t encap_key[], size_t len, size_t desired_shared_key_len, const uint8_t salt[], size_t salt_len) { secure_vector raw_shared = this->raw_kem_decrypt(encap_key, len); return m_kdf->derive_key(desired_shared_key_len, raw_shared.data(), raw_shared.size(), salt, salt_len); } PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(const std::string& kdf) { m_kdf.reset(get_kdf(kdf)); } } /* * PKCS #8 * (C) 1999-2010,2014,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_PKCS5_PBES2) #endif namespace Botan { namespace PKCS8 { namespace { /* * Get info from an EncryptedPrivateKeyInfo */ secure_vector PKCS8_extract(DataSource& source, AlgorithmIdentifier& pbe_alg_id) { secure_vector key_data; BER_Decoder(source) .start_cons(SEQUENCE) .decode(pbe_alg_id) .decode(key_data, OCTET_STRING) .verify_end(); return key_data; } /* * PEM decode and/or decrypt a private key */ secure_vector PKCS8_decode( DataSource& source, std::function get_passphrase, AlgorithmIdentifier& pk_alg_id, bool is_encrypted) { AlgorithmIdentifier pbe_alg_id; secure_vector key_data, key; try { if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) { if(is_encrypted) { key_data = PKCS8_extract(source, pbe_alg_id); } else { // todo read more efficiently while(!source.end_of_data()) { uint8_t b; size_t read = source.read_byte(b); if(read) { key_data.push_back(b); } } } } else { std::string label; key_data = PEM_Code::decode(source, label); // todo remove autodetect for pem as well? if(label == "PRIVATE KEY") is_encrypted = false; else if(label == "ENCRYPTED PRIVATE KEY") { DataSource_Memory key_source(key_data); key_data = PKCS8_extract(key_source, pbe_alg_id); } else throw PKCS8_Exception("Unknown PEM label " + label); } if(key_data.empty()) throw PKCS8_Exception("No key data found"); } catch(Decoding_Error& e) { throw Decoding_Error("PKCS #8 private key decoding", e); } try { if(is_encrypted) { if(OIDS::oid2str_or_throw(pbe_alg_id.get_oid()) != "PBE-PKCS5v20") throw PKCS8_Exception("Unknown PBE type " + pbe_alg_id.get_oid().to_string()); #if defined(BOTAN_HAS_PKCS5_PBES2) key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.get_parameters()); #else BOTAN_UNUSED(get_passphrase); throw Decoding_Error("Private key is encrypted but PBES2 was disabled in build"); #endif } else key = key_data; BER_Decoder(key) .start_cons(SEQUENCE) .decode_and_check(0, "Unknown PKCS #8 version number") .decode(pk_alg_id) .decode(key, OCTET_STRING) .discard_remaining() .end_cons(); } catch(std::exception& e) { throw Decoding_Error("PKCS #8 private key decoding", e); } return key; } } /* * BER encode a PKCS #8 private key, unencrypted */ secure_vector BER_encode(const Private_Key& key) { // keeping around for compat return key.private_key_info(); } /* * PEM encode a PKCS #8 private key, unencrypted */ std::string PEM_encode(const Private_Key& key) { return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY"); } #if defined(BOTAN_HAS_PKCS5_PBES2) namespace { std::pair choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo) { if(pbe_algo.empty()) { /* * For algorithms where we are using a non-RFC format anyway, default to * SIV or GCM. For others (RSA, ECDSA, ...) default to something widely * compatible. */ const bool nonstandard_pk = (key_algo == "McEliece" || key_algo == "XMSS"); if(nonstandard_pk) { #if defined(BOTAN_HAS_AEAD_SIV) && defined(BOTAN_HAS_SHA2_64) return std::make_pair("AES-256/SIV", "SHA-512"); #elif defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_SHA2_64) return std::make_pair("AES-256/GCM", "SHA-512"); #endif } // Default is something compatible with everyone else return std::make_pair("AES-256/CBC", "SHA-256"); } SCAN_Name request(pbe_algo); if(request.arg_count() != 2 || (request.algo_name() != "PBE-PKCS5v20" && request.algo_name() != "PBES2")) { throw Invalid_Argument("Unsupported PBE " + pbe_algo); } return std::make_pair(request.arg(0), request.arg(1)); } } #endif /* * BER encode a PKCS #8 private key, encrypted */ std::vector BER_encode(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, std::chrono::milliseconds msec, const std::string& pbe_algo) { #if defined(BOTAN_HAS_PKCS5_PBES2) const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name()); const std::pair> pbe_info = pbes2_encrypt_msec(PKCS8::BER_encode(key), pass, msec, nullptr, pbe_params.first, pbe_params.second, rng); std::vector output; DER_Encoder der(output); der.start_cons(SEQUENCE) .encode(pbe_info.first) .encode(pbe_info.second, OCTET_STRING) .end_cons(); return output; #else BOTAN_UNUSED(key, rng, pass, msec, pbe_algo); throw Encoding_Error("PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build"); #endif } /* * PEM encode a PKCS #8 private key, encrypted */ std::string PEM_encode(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, std::chrono::milliseconds msec, const std::string& pbe_algo) { if(pass.empty()) return PEM_encode(key); return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo), "ENCRYPTED PRIVATE KEY"); } /* * BER encode a PKCS #8 private key, encrypted */ std::vector BER_encode_encrypted_pbkdf_iter(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, size_t pbkdf_iterations, const std::string& cipher, const std::string& pbkdf_hash) { #if defined(BOTAN_HAS_PKCS5_PBES2) const std::pair> pbe_info = pbes2_encrypt_iter(key.private_key_info(), pass, pbkdf_iterations, cipher.empty() ? "AES-256/CBC" : cipher, pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash, rng); std::vector output; DER_Encoder der(output); der.start_cons(SEQUENCE) .encode(pbe_info.first) .encode(pbe_info.second, OCTET_STRING) .end_cons(); return output; #else BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash); throw Encoding_Error("PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build"); #endif } /* * PEM encode a PKCS #8 private key, encrypted */ std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, size_t pbkdf_iterations, const std::string& cipher, const std::string& pbkdf_hash) { return PEM_Code::encode( PKCS8::BER_encode_encrypted_pbkdf_iter(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash), "ENCRYPTED PRIVATE KEY"); } /* * BER encode a PKCS #8 private key, encrypted */ std::vector BER_encode_encrypted_pbkdf_msec(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, std::chrono::milliseconds pbkdf_msec, size_t* pbkdf_iterations, const std::string& cipher, const std::string& pbkdf_hash) { #if defined(BOTAN_HAS_PKCS5_PBES2) const std::pair> pbe_info = pbes2_encrypt_msec(key.private_key_info(), pass, pbkdf_msec, pbkdf_iterations, cipher.empty() ? "AES-256/CBC" : cipher, pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash, rng); std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .encode(pbe_info.first) .encode(pbe_info.second, OCTET_STRING) .end_cons(); return output; #else BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash); throw Encoding_Error("BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build"); #endif } /* * PEM encode a PKCS #8 private key, encrypted */ std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, std::chrono::milliseconds pbkdf_msec, size_t* pbkdf_iterations, const std::string& cipher, const std::string& pbkdf_hash) { return PEM_Code::encode( PKCS8::BER_encode_encrypted_pbkdf_msec(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash), "ENCRYPTED PRIVATE KEY"); } namespace { /* * Extract a private key (encrypted/unencrypted) and return it */ std::unique_ptr load_key(DataSource& source, std::function get_pass, bool is_encrypted) { AlgorithmIdentifier alg_id; secure_vector pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted); const std::string alg_name = OIDS::oid2str_or_empty(alg_id.get_oid()); if(alg_name.empty()) throw PKCS8_Exception("Unknown algorithm OID: " + alg_id.get_oid().to_string()); return load_private_key(alg_id, pkcs8_key); } } /* * Extract an encrypted private key and return it */ std::unique_ptr load_key(DataSource& source, std::function get_pass) { return load_key(source, get_pass, true); } /* * Extract an encrypted private key and return it */ std::unique_ptr load_key(DataSource& source, const std::string& pass) { // We need to use bind rather than a lambda capturing `pass` here in order to avoid a Clang 8 bug. // See https://github.com/randombit/botan/issues/2255. return load_key(source, std::bind([](const std::string p) { return p; }, pass), true); } /* * Extract an unencrypted private key and return it */ std::unique_ptr load_key(DataSource& source) { auto fail_fn = []() -> std::string { throw PKCS8_Exception("Internal error: Attempt to read password for unencrypted key"); }; return load_key(source, fail_fn, false); } /* * Make a copy of this private key */ std::unique_ptr copy_key(const Private_Key& key) { DataSource_Memory source(PEM_encode(key)); return PKCS8::load_key(source); } /* * Extract an encrypted private key and return it */ Private_Key* load_key(DataSource& source, RandomNumberGenerator& rng, std::function get_pass) { BOTAN_UNUSED(rng); return PKCS8::load_key(source, get_pass).release(); } /* * Extract an encrypted private key and return it */ Private_Key* load_key(DataSource& source, RandomNumberGenerator& rng, const std::string& pass) { BOTAN_UNUSED(rng); return PKCS8::load_key(source, pass).release(); } /* * Extract an unencrypted private key and return it */ Private_Key* load_key(DataSource& source, RandomNumberGenerator& rng) { BOTAN_UNUSED(rng); return PKCS8::load_key(source).release(); } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) /* * Extract an encrypted private key and return it */ Private_Key* load_key(const std::string& fsname, RandomNumberGenerator& rng, std::function get_pass) { BOTAN_UNUSED(rng); DataSource_Stream in(fsname); return PKCS8::load_key(in, get_pass).release(); } /* * Extract an encrypted private key and return it */ Private_Key* load_key(const std::string& fsname, RandomNumberGenerator& rng, const std::string& pass) { BOTAN_UNUSED(rng); DataSource_Stream in(fsname); // We need to use bind rather than a lambda capturing `pass` here in order to avoid a Clang 8 bug. // See https://github.com/randombit/botan/issues/2255. return PKCS8::load_key(in, std::bind([](const std::string p) { return p; }, pass)).release(); } /* * Extract an unencrypted private key and return it */ Private_Key* load_key(const std::string& fsname, RandomNumberGenerator& rng) { BOTAN_UNUSED(rng); DataSource_Stream in(fsname); return PKCS8::load_key(in).release(); } #endif /* * Make a copy of this private key */ Private_Key* copy_key(const Private_Key& key, RandomNumberGenerator& rng) { BOTAN_UNUSED(rng); return PKCS8::copy_key(key).release(); } } } /* * (C) 1999-2010,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { secure_vector PK_Decryptor::decrypt(const uint8_t in[], size_t length) const { uint8_t valid_mask = 0; secure_vector decoded = do_decrypt(valid_mask, in, length); if(valid_mask == 0) throw Decoding_Error("Invalid public key ciphertext, cannot decrypt"); return decoded; } secure_vector PK_Decryptor::decrypt_or_random(const uint8_t in[], size_t length, size_t expected_pt_len, RandomNumberGenerator& rng, const uint8_t required_content_bytes[], const uint8_t required_content_offsets[], size_t required_contents_length) const { const secure_vector fake_pms = rng.random_vec(expected_pt_len); uint8_t decrypt_valid = 0; secure_vector decoded = do_decrypt(decrypt_valid, in, length); auto valid_mask = CT::Mask::is_equal(decrypt_valid, 0xFF); valid_mask &= CT::Mask(CT::Mask::is_zero(decoded.size() ^ expected_pt_len)); decoded.resize(expected_pt_len); for(size_t i = 0; i != required_contents_length; ++i) { /* These values are chosen by the application and for TLS are constants, so this early failure via assert is fine since we know 0,1 < 48 If there is a protocol that has content checks on the key where the expected offsets are controllable by the attacker this could still leak. Alternately could always reduce the offset modulo the length? */ const uint8_t exp = required_content_bytes[i]; const uint8_t off = required_content_offsets[i]; BOTAN_ASSERT(off < expected_pt_len, "Offset in range of plaintext"); auto eq = CT::Mask::is_equal(decoded[off], exp); valid_mask &= eq; } // If valid_mask is false, assign fake pre master instead valid_mask.select_n(decoded.data(), decoded.data(), fake_pms.data(), expected_pt_len); return decoded; } secure_vector PK_Decryptor::decrypt_or_random(const uint8_t in[], size_t length, size_t expected_pt_len, RandomNumberGenerator& rng) const { return decrypt_or_random(in, length, expected_pt_len, rng, nullptr, nullptr, 0); } PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key, RandomNumberGenerator& rng, const std::string& padding, const std::string& provider) { m_op = key.create_encryption_op(rng, padding, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support encryption"); } PK_Encryptor_EME::~PK_Encryptor_EME() { /* for unique_ptr */ } size_t PK_Encryptor_EME::ciphertext_length(size_t ptext_len) const { return m_op->ciphertext_length(ptext_len); } std::vector PK_Encryptor_EME::enc(const uint8_t in[], size_t length, RandomNumberGenerator& rng) const { return unlock(m_op->encrypt(in, length, rng)); } size_t PK_Encryptor_EME::maximum_input_size() const { return m_op->max_input_bits() / 8; } PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key, RandomNumberGenerator& rng, const std::string& padding, const std::string& provider) { m_op = key.create_decryption_op(rng, padding, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support decryption"); } PK_Decryptor_EME::~PK_Decryptor_EME() { /* for unique_ptr */ } size_t PK_Decryptor_EME::plaintext_length(size_t ctext_len) const { return m_op->plaintext_length(ctext_len); } secure_vector PK_Decryptor_EME::do_decrypt(uint8_t& valid_mask, const uint8_t in[], size_t in_len) const { return m_op->decrypt(valid_mask, in, in_len); } PK_KEM_Encryptor::PK_KEM_Encryptor(const Public_Key& key, RandomNumberGenerator& rng, const std::string& param, const std::string& provider) { m_op = key.create_kem_encryption_op(rng, param, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support KEM encryption"); } PK_KEM_Encryptor::~PK_KEM_Encryptor() { /* for unique_ptr */ } void PK_KEM_Encryptor::encrypt(secure_vector& out_encapsulated_key, secure_vector& out_shared_key, size_t desired_shared_key_len, Botan::RandomNumberGenerator& rng, const uint8_t salt[], size_t salt_len) { m_op->kem_encrypt(out_encapsulated_key, out_shared_key, desired_shared_key_len, rng, salt, salt_len); } PK_KEM_Decryptor::PK_KEM_Decryptor(const Private_Key& key, RandomNumberGenerator& rng, const std::string& param, const std::string& provider) { m_op = key.create_kem_decryption_op(rng, param, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support KEM decryption"); } PK_KEM_Decryptor::~PK_KEM_Decryptor() { /* for unique_ptr */ } secure_vector PK_KEM_Decryptor::decrypt(const uint8_t encap_key[], size_t encap_key_len, size_t desired_shared_key_len, const uint8_t salt[], size_t salt_len) { return m_op->kem_decrypt(encap_key, encap_key_len, desired_shared_key_len, salt, salt_len); } PK_Key_Agreement::PK_Key_Agreement(const Private_Key& key, RandomNumberGenerator& rng, const std::string& kdf, const std::string& provider) { m_op = key.create_key_agreement_op(rng, kdf, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support key agreement"); } PK_Key_Agreement::~PK_Key_Agreement() { /* for unique_ptr */ } PK_Key_Agreement& PK_Key_Agreement::operator=(PK_Key_Agreement&& other) { if(this != &other) { m_op = std::move(other.m_op); } return (*this); } PK_Key_Agreement::PK_Key_Agreement(PK_Key_Agreement&& other) : m_op(std::move(other.m_op)) {} size_t PK_Key_Agreement::agreed_value_size() const { return m_op->agreed_value_size(); } SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, const uint8_t in[], size_t in_len, const uint8_t salt[], size_t salt_len) const { return m_op->agree(key_len, in, in_len, salt, salt_len); } static void check_der_format_supported(Signature_Format format, size_t parts) { if(format != IEEE_1363 && parts == 1) throw Invalid_Argument("PK: This algorithm does not support DER encoding"); } PK_Signer::PK_Signer(const Private_Key& key, RandomNumberGenerator& rng, const std::string& emsa, Signature_Format format, const std::string& provider) { m_op = key.create_signature_op(rng, emsa, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support signature generation"); m_sig_format = format; m_parts = key.message_parts(); m_part_size = key.message_part_size(); check_der_format_supported(format, m_parts); } PK_Signer::~PK_Signer() { /* for unique_ptr */ } void PK_Signer::update(const uint8_t in[], size_t length) { m_op->update(in, length); } namespace { std::vector der_encode_signature(const std::vector& sig, size_t parts, size_t part_size) { if(sig.size() % parts != 0 || sig.size() != parts * part_size) throw Encoding_Error("Unexpected size for DER signature"); std::vector sig_parts(parts); for(size_t i = 0; i != sig_parts.size(); ++i) sig_parts[i].binary_decode(&sig[part_size*i], part_size); std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .encode_list(sig_parts) .end_cons(); return output; } } size_t PK_Signer::signature_length() const { if(m_sig_format == IEEE_1363) { return m_op->signature_length(); } else if(m_sig_format == DER_SEQUENCE) { // This is a large over-estimate but its easier than computing // the exact value return m_op->signature_length() + (8 + 4*m_parts); } else throw Internal_Error("PK_Signer: Invalid signature format enum"); } std::vector PK_Signer::signature(RandomNumberGenerator& rng) { const std::vector sig = unlock(m_op->sign(rng)); if(m_sig_format == IEEE_1363) { return sig; } else if(m_sig_format == DER_SEQUENCE) { return der_encode_signature(sig, m_parts, m_part_size); } else throw Internal_Error("PK_Signer: Invalid signature format enum"); } PK_Verifier::PK_Verifier(const Public_Key& key, const std::string& emsa, Signature_Format format, const std::string& provider) { m_op = key.create_verification_op(emsa, provider); if(!m_op) throw Invalid_Argument("Key type " + key.algo_name() + " does not support signature verification"); m_sig_format = format; m_parts = key.message_parts(); m_part_size = key.message_part_size(); check_der_format_supported(format, m_parts); } PK_Verifier::~PK_Verifier() { /* for unique_ptr */ } void PK_Verifier::set_input_format(Signature_Format format) { check_der_format_supported(format, m_parts); m_sig_format = format; } bool PK_Verifier::verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length) { update(msg, msg_length); return check_signature(sig, sig_length); } void PK_Verifier::update(const uint8_t in[], size_t length) { m_op->update(in, length); } bool PK_Verifier::check_signature(const uint8_t sig[], size_t length) { try { if(m_sig_format == IEEE_1363) { return m_op->is_valid_signature(sig, length); } else if(m_sig_format == DER_SEQUENCE) { std::vector real_sig; BER_Decoder decoder(sig, length); BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); BOTAN_ASSERT_NOMSG(m_parts != 0 && m_part_size != 0); size_t count = 0; while(ber_sig.more_items()) { BigInt sig_part; ber_sig.decode(sig_part); real_sig += BigInt::encode_1363(sig_part, m_part_size); ++count; } if(count != m_parts) throw Decoding_Error("PK_Verifier: signature size invalid"); const std::vector reencoded = der_encode_signature(real_sig, m_parts, m_part_size); if(reencoded.size() != length || same_mem(reencoded.data(), sig, reencoded.size()) == false) { throw Decoding_Error("PK_Verifier: signature is not the canonical DER encoding"); } return m_op->is_valid_signature(real_sig.data(), real_sig.size()); } else throw Internal_Error("PK_Verifier: Invalid signature format enum"); } catch(Invalid_Argument&) { return false; } } } /* * Public Key Work Factor Functions * (C) 1999-2007,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t ecp_work_factor(size_t bits) { return bits / 2; } namespace { size_t nfs_workfactor(size_t bits, double log2_k) { // approximates natural logarithm of an integer of given bitsize const double log2_e = 1.44269504088896340736; const double log_p = bits / log2_e; const double log_log_p = std::log(log_p); // RFC 3766: k * e^((1.92 + o(1)) * cubrt(ln(n) * (ln(ln(n)))^2)) const double est = 1.92 * std::pow(log_p * log_log_p * log_log_p, 1.0/3.0); // return log2 of the workfactor return static_cast(log2_k + log2_e * est); } } size_t if_work_factor(size_t bits) { // RFC 3766 estimates k at .02 and o(1) to be effectively zero for sizes of interest const double log2_k = -5.6438; // log2(.02) return nfs_workfactor(bits, log2_k); } size_t dl_work_factor(size_t bits) { // Lacking better estimates... return if_work_factor(bits); } size_t dl_exponent_size(size_t bits) { /* This uses a slightly tweaked version of the standard work factor function above. It assumes k is 1 (thus overestimating the strength of the prime group by 5-6 bits), and always returns at least 128 bits (this only matters for very small primes). */ const size_t min_workfactor = 64; const double log2_k = 0; return 2 * std::max(min_workfactor, nfs_workfactor(bits, log2_k)); } } /* * X.509 Public Key * (C) 1999-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace X509 { std::vector BER_encode(const Public_Key& key) { // keeping it around for compat return key.subject_public_key(); } /* * PEM encode a X.509 public key */ std::string PEM_encode(const Public_Key& key) { return PEM_Code::encode(key.subject_public_key(), "PUBLIC KEY"); } /* * Extract a public key and return it */ Public_Key* load_key(DataSource& source) { try { AlgorithmIdentifier alg_id; std::vector key_bits; if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) { BER_Decoder(source) .start_cons(SEQUENCE) .decode(alg_id) .decode(key_bits, BIT_STRING) .end_cons(); } else { DataSource_Memory ber( PEM_Code::decode_check_label(source, "PUBLIC KEY") ); BER_Decoder(ber) .start_cons(SEQUENCE) .decode(alg_id) .decode(key_bits, BIT_STRING) .end_cons(); } if(key_bits.empty()) throw Decoding_Error("X.509 public key decoding"); return load_public_key(alg_id, key_bits).release(); } catch(Decoding_Error& e) { throw Decoding_Error("X.509 public key decoding", e); } } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) /* * Extract a public key and return it */ Public_Key* load_key(const std::string& fsname) { DataSource_Stream source(fsname, true); return X509::load_key(source); } #endif /* * Extract a public key and return it */ Public_Key* load_key(const std::vector& mem) { DataSource_Memory source(mem); return X509::load_key(source); } /* * Make a copy of this public key */ Public_Key* copy_key(const Public_Key& key) { DataSource_Memory source(PEM_encode(key)); return X509::load_key(source); } } } /* * RC4 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Combine cipher stream with message */ void RC4::cipher(const uint8_t in[], uint8_t out[], size_t length) { verify_key_set(m_state.empty() == false); while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); length -= (m_buffer.size() - m_position); in += (m_buffer.size() - m_position); out += (m_buffer.size() - m_position); generate(); } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; } StreamCipher* RC4::clone() const { return new RC4(m_SKIP); } Key_Length_Specification RC4::key_spec() const { return Key_Length_Specification(1, 256); } void RC4::set_iv(const uint8_t*, size_t length) { if(length > 0) throw Invalid_IV_Length("RC4", length); } /* * Generate cipher stream */ void RC4::generate() { uint8_t SX, SY; for(size_t i = 0; i != m_buffer.size(); i += 4) { SX = m_state[m_X+1]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; m_state[m_X+1] = SY; m_state[m_Y] = SX; m_buffer[i] = m_state[(SX + SY) % 256]; SX = m_state[m_X+2]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; m_state[m_X+2] = SY; m_state[m_Y] = SX; m_buffer[i+1] = m_state[(SX + SY) % 256]; SX = m_state[m_X+3]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; m_state[m_X+3] = SY; m_state[m_Y] = SX; m_buffer[i+2] = m_state[(SX + SY) % 256]; m_X = (m_X + 4) % 256; SX = m_state[m_X]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; m_state[m_X] = SY; m_state[m_Y] = SX; m_buffer[i+3] = m_state[(SX + SY) % 256]; } m_position = 0; } /* * RC4 Key Schedule */ void RC4::key_schedule(const uint8_t key[], size_t length) { m_state.resize(256); m_buffer.resize(256); m_position = m_X = m_Y = 0; for(size_t i = 0; i != 256; ++i) m_state[i] = static_cast(i); for(size_t i = 0, state_index = 0; i != 256; ++i) { state_index = (state_index + key[i % length] + m_state[i]) % 256; std::swap(m_state[i], m_state[state_index]); } for(size_t i = 0; i <= m_SKIP; i += m_buffer.size()) generate(); m_position += (m_SKIP % m_buffer.size()); } /* * Return the name of this type */ std::string RC4::name() const { if(m_SKIP == 0) return "RC4"; else if(m_SKIP == 256) return "MARK-4"; else return "RC4(" + std::to_string(m_SKIP) + ")"; } /* * Clear memory of sensitive data */ void RC4::clear() { zap(m_state); zap(m_buffer); m_position = m_X = m_Y = 0; } /* * RC4 Constructor */ RC4::RC4(size_t s) : m_SKIP(s) {} void RC4::seek(uint64_t) { throw Not_Implemented("RC4 does not support seeking"); } } /* * RDRAND RNG * (C) 2016,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void RDRAND_RNG::randomize(uint8_t out[], size_t out_len) { Processor_RNG rng; rng.randomize(out, out_len); } RDRAND_RNG::RDRAND_RNG() { // Will throw if instruction is not available Processor_RNG rng; } //static bool RDRAND_RNG::available() { return Processor_RNG::available(); } //static uint32_t RDRAND_RNG::rdrand() { Processor_RNG rng; for(;;) { try { uint8_t out[4]; rng.randomize(out, 4); return load_le(out, 0); } catch(PRNG_Unseeded&) {} } } //static uint32_t RDRAND_RNG::rdrand_status(bool& ok) { ok = false; Processor_RNG rng; try { uint8_t out[4]; rng.randomize(out, 4); ok = true; return load_le(out, 0); } catch(PRNG_Unseeded&) {} return 0; } } /* * Entropy Source Using Intel's rdseed instruction * (C) 2015 Daniel Neus * (C) 2015,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { BOTAN_FUNC_ISA("rdseed") bool read_rdseed(secure_vector& seed) { /* * RDSEED is not guaranteed to generate an output within any specific number * of attempts. However in testing on a Skylake system, with all hyperthreads * occupied in tight RDSEED loops, RDSEED will still usually succeed in under * 150 attempts. The maximum ever seen was 230 attempts until success. When * idle, RDSEED usually succeeds in 1 or 2 attempts. * * We set an upper bound of 512 attempts, because it is possible that due * to firmware issue RDSEED is simply broken and never succeeds. We do not * want to loop forever in that case. If we exceed that limit, then we assume * the hardware is actually just broken, and stop the poll. */ const size_t RDSEED_RETRIES = 512; for(size_t i = 0; i != RDSEED_RETRIES; ++i) { uint32_t r = 0; int cf = 0; #if defined(BOTAN_USE_GCC_INLINE_ASM) asm("rdseed %0; adcl $0,%1" : "=r" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); #else cf = _rdseed32_step(&r); #endif if(1 == cf) { seed.push_back(r); return true; } // Intel suggests pausing if RDSEED fails. _mm_pause(); } return false; // failed to produce an output after many attempts } } size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) { const size_t RDSEED_BYTES = 1024; static_assert(RDSEED_BYTES % 4 == 0, "Bad RDSEED configuration"); if(CPUID::has_rdseed()) { secure_vector seed; seed.reserve(RDSEED_BYTES / 4); for(size_t p = 0; p != RDSEED_BYTES / 4; ++p) { /* If at any point we exceed our retry count, we stop the entire seed gathering process. This situation will only occur in situations of extremely high RDSEED utilization. If RDSEED is currently so highly contended, then the rest of the poll is likely to also face contention and it is better to quit now rather than (presumably) face very high retry times for the rest of the poll. */ if(!read_rdseed(seed)) break; } if(seed.size() > 0) { rng.add_entropy(reinterpret_cast(seed.data()), seed.size() * sizeof(uint32_t)); } } // RDSEED is used but not trusted return 0; } } /* * AES Key Wrap (RFC 3394) * (C) 2011 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { secure_vector rfc3394_keywrap(const secure_vector& key, const SymmetricKey& kek) { BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32, "Invalid KEK length for NIST key wrap"); const std::string cipher_name = "AES-" + std::to_string(8*kek.size()); std::unique_ptr aes(BlockCipher::create_or_throw(cipher_name)); aes->set_key(kek); std::vector wrapped = nist_key_wrap(key.data(), key.size(), *aes); return secure_vector(wrapped.begin(), wrapped.end()); } secure_vector rfc3394_keyunwrap(const secure_vector& key, const SymmetricKey& kek) { BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32, "Invalid KEK length for NIST key wrap"); BOTAN_ARG_CHECK(key.size() >= 16 && key.size() % 8 == 0, "Bad input key size for NIST key unwrap"); const std::string cipher_name = "AES-" + std::to_string(8*kek.size()); std::unique_ptr aes(BlockCipher::create_or_throw(cipher_name)); aes->set_key(kek); return nist_key_unwrap(key.data(), key.size(), *aes); } } /* * RFC 6979 Deterministic Nonce Generator * (C) 2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { RFC6979_Nonce_Generator::RFC6979_Nonce_Generator(const std::string& hash, const BigInt& order, const BigInt& x) : m_order(order), m_qlen(m_order.bits()), m_rlen(m_qlen / 8 + (m_qlen % 8 ? 1 : 0)), m_rng_in(m_rlen * 2), m_rng_out(m_rlen) { m_hmac_drbg.reset(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")"))); BigInt::encode_1363(m_rng_in.data(), m_rlen, x); } RFC6979_Nonce_Generator::~RFC6979_Nonce_Generator() { // for ~unique_ptr } const BigInt& RFC6979_Nonce_Generator::nonce_for(const BigInt& m) { BigInt::encode_1363(&m_rng_in[m_rlen], m_rlen, m); m_hmac_drbg->clear(); m_hmac_drbg->initialize_with(m_rng_in.data(), m_rng_in.size()); do { m_hmac_drbg->randomize(m_rng_out.data(), m_rng_out.size()); m_k.binary_decode(m_rng_out.data(), m_rng_out.size()); m_k >>= (8*m_rlen - m_qlen); } while(m_k == 0 || m_k >= m_order); return m_k; } BigInt generate_rfc6979_nonce(const BigInt& x, const BigInt& q, const BigInt& h, const std::string& hash) { RFC6979_Nonce_Generator gen(hash, q, x); BigInt k = gen.nonce_for(h); return k; } } /* * RIPEMD-160 * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr RIPEMD_160::copy_state() const { return std::unique_ptr(new RIPEMD_160(*this)); } namespace { /* * RIPEMD-160 F1 Function */ template inline void F1(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, uint32_t M) { A += (B ^ C ^ D) + M; A = rotl(A) + E; C = rotl<10>(C); } /* * RIPEMD-160 F2 Function */ template inline void F2(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, uint32_t M) { A += (D ^ (B & (C ^ D))) + M; A = rotl(A) + E; C = rotl<10>(C); } /* * RIPEMD-160 F3 Function */ template inline void F3(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, uint32_t M) { A += (D ^ (B | ~C)) + M; A = rotl(A) + E; C = rotl<10>(C); } /* * RIPEMD-160 F4 Function */ template inline void F4(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, uint32_t M) { A += (C ^ (D & (B ^ C))) + M; A = rotl(A) + E; C = rotl<10>(C); } /* * RIPEMD-160 F5 Function */ template inline void F5(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, uint32_t M) { A += (B ^ (C | ~D)) + M; A = rotl(A) + E; C = rotl<10>(C); } } /* * RIPEMD-160 Compression Function */ void RIPEMD_160::compress_n(const uint8_t input[], size_t blocks) { const uint32_t MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1, MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0xA953FD4E, MAGIC6 = 0x50A28BE6, MAGIC7 = 0x5C4DD124, MAGIC8 = 0x6D703EF3, MAGIC9 = 0x7A6D76E9; for(size_t i = 0; i != blocks; ++i) { load_le(m_M.data(), input, m_M.size()); uint32_t A1 = m_digest[0], A2 = A1, B1 = m_digest[1], B2 = B1, C1 = m_digest[2], C2 = C1, D1 = m_digest[3], D2 = D1, E1 = m_digest[4], E2 = E1; F1<11>(A1,B1,C1,D1,E1,m_M[ 0] ); F5< 8>(A2,B2,C2,D2,E2,m_M[ 5]+MAGIC6); F1<14>(E1,A1,B1,C1,D1,m_M[ 1] ); F5< 9>(E2,A2,B2,C2,D2,m_M[14]+MAGIC6); F1<15>(D1,E1,A1,B1,C1,m_M[ 2] ); F5< 9>(D2,E2,A2,B2,C2,m_M[ 7]+MAGIC6); F1<12>(C1,D1,E1,A1,B1,m_M[ 3] ); F5<11>(C2,D2,E2,A2,B2,m_M[ 0]+MAGIC6); F1< 5>(B1,C1,D1,E1,A1,m_M[ 4] ); F5<13>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC6); F1< 8>(A1,B1,C1,D1,E1,m_M[ 5] ); F5<15>(A2,B2,C2,D2,E2,m_M[ 2]+MAGIC6); F1< 7>(E1,A1,B1,C1,D1,m_M[ 6] ); F5<15>(E2,A2,B2,C2,D2,m_M[11]+MAGIC6); F1< 9>(D1,E1,A1,B1,C1,m_M[ 7] ); F5< 5>(D2,E2,A2,B2,C2,m_M[ 4]+MAGIC6); F1<11>(C1,D1,E1,A1,B1,m_M[ 8] ); F5< 7>(C2,D2,E2,A2,B2,m_M[13]+MAGIC6); F1<13>(B1,C1,D1,E1,A1,m_M[ 9] ); F5< 7>(B2,C2,D2,E2,A2,m_M[ 6]+MAGIC6); F1<14>(A1,B1,C1,D1,E1,m_M[10] ); F5< 8>(A2,B2,C2,D2,E2,m_M[15]+MAGIC6); F1<15>(E1,A1,B1,C1,D1,m_M[11] ); F5<11>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC6); F1< 6>(D1,E1,A1,B1,C1,m_M[12] ); F5<14>(D2,E2,A2,B2,C2,m_M[ 1]+MAGIC6); F1< 7>(C1,D1,E1,A1,B1,m_M[13] ); F5<14>(C2,D2,E2,A2,B2,m_M[10]+MAGIC6); F1< 9>(B1,C1,D1,E1,A1,m_M[14] ); F5<12>(B2,C2,D2,E2,A2,m_M[ 3]+MAGIC6); F1< 8>(A1,B1,C1,D1,E1,m_M[15] ); F5< 6>(A2,B2,C2,D2,E2,m_M[12]+MAGIC6); F2< 7>(E1,A1,B1,C1,D1,m_M[ 7]+MAGIC2); F4< 9>(E2,A2,B2,C2,D2,m_M[ 6]+MAGIC7); F2< 6>(D1,E1,A1,B1,C1,m_M[ 4]+MAGIC2); F4<13>(D2,E2,A2,B2,C2,m_M[11]+MAGIC7); F2< 8>(C1,D1,E1,A1,B1,m_M[13]+MAGIC2); F4<15>(C2,D2,E2,A2,B2,m_M[ 3]+MAGIC7); F2<13>(B1,C1,D1,E1,A1,m_M[ 1]+MAGIC2); F4< 7>(B2,C2,D2,E2,A2,m_M[ 7]+MAGIC7); F2<11>(A1,B1,C1,D1,E1,m_M[10]+MAGIC2); F4<12>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC7); F2< 9>(E1,A1,B1,C1,D1,m_M[ 6]+MAGIC2); F4< 8>(E2,A2,B2,C2,D2,m_M[13]+MAGIC7); F2< 7>(D1,E1,A1,B1,C1,m_M[15]+MAGIC2); F4< 9>(D2,E2,A2,B2,C2,m_M[ 5]+MAGIC7); F2<15>(C1,D1,E1,A1,B1,m_M[ 3]+MAGIC2); F4<11>(C2,D2,E2,A2,B2,m_M[10]+MAGIC7); F2< 7>(B1,C1,D1,E1,A1,m_M[12]+MAGIC2); F4< 7>(B2,C2,D2,E2,A2,m_M[14]+MAGIC7); F2<12>(A1,B1,C1,D1,E1,m_M[ 0]+MAGIC2); F4< 7>(A2,B2,C2,D2,E2,m_M[15]+MAGIC7); F2<15>(E1,A1,B1,C1,D1,m_M[ 9]+MAGIC2); F4<12>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC7); F2< 9>(D1,E1,A1,B1,C1,m_M[ 5]+MAGIC2); F4< 7>(D2,E2,A2,B2,C2,m_M[12]+MAGIC7); F2<11>(C1,D1,E1,A1,B1,m_M[ 2]+MAGIC2); F4< 6>(C2,D2,E2,A2,B2,m_M[ 4]+MAGIC7); F2< 7>(B1,C1,D1,E1,A1,m_M[14]+MAGIC2); F4<15>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC7); F2<13>(A1,B1,C1,D1,E1,m_M[11]+MAGIC2); F4<13>(A2,B2,C2,D2,E2,m_M[ 1]+MAGIC7); F2<12>(E1,A1,B1,C1,D1,m_M[ 8]+MAGIC2); F4<11>(E2,A2,B2,C2,D2,m_M[ 2]+MAGIC7); F3<11>(D1,E1,A1,B1,C1,m_M[ 3]+MAGIC3); F3< 9>(D2,E2,A2,B2,C2,m_M[15]+MAGIC8); F3<13>(C1,D1,E1,A1,B1,m_M[10]+MAGIC3); F3< 7>(C2,D2,E2,A2,B2,m_M[ 5]+MAGIC8); F3< 6>(B1,C1,D1,E1,A1,m_M[14]+MAGIC3); F3<15>(B2,C2,D2,E2,A2,m_M[ 1]+MAGIC8); F3< 7>(A1,B1,C1,D1,E1,m_M[ 4]+MAGIC3); F3<11>(A2,B2,C2,D2,E2,m_M[ 3]+MAGIC8); F3<14>(E1,A1,B1,C1,D1,m_M[ 9]+MAGIC3); F3< 8>(E2,A2,B2,C2,D2,m_M[ 7]+MAGIC8); F3< 9>(D1,E1,A1,B1,C1,m_M[15]+MAGIC3); F3< 6>(D2,E2,A2,B2,C2,m_M[14]+MAGIC8); F3<13>(C1,D1,E1,A1,B1,m_M[ 8]+MAGIC3); F3< 6>(C2,D2,E2,A2,B2,m_M[ 6]+MAGIC8); F3<15>(B1,C1,D1,E1,A1,m_M[ 1]+MAGIC3); F3<14>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC8); F3<14>(A1,B1,C1,D1,E1,m_M[ 2]+MAGIC3); F3<12>(A2,B2,C2,D2,E2,m_M[11]+MAGIC8); F3< 8>(E1,A1,B1,C1,D1,m_M[ 7]+MAGIC3); F3<13>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC8); F3<13>(D1,E1,A1,B1,C1,m_M[ 0]+MAGIC3); F3< 5>(D2,E2,A2,B2,C2,m_M[12]+MAGIC8); F3< 6>(C1,D1,E1,A1,B1,m_M[ 6]+MAGIC3); F3<14>(C2,D2,E2,A2,B2,m_M[ 2]+MAGIC8); F3< 5>(B1,C1,D1,E1,A1,m_M[13]+MAGIC3); F3<13>(B2,C2,D2,E2,A2,m_M[10]+MAGIC8); F3<12>(A1,B1,C1,D1,E1,m_M[11]+MAGIC3); F3<13>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC8); F3< 7>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC3); F3< 7>(E2,A2,B2,C2,D2,m_M[ 4]+MAGIC8); F3< 5>(D1,E1,A1,B1,C1,m_M[12]+MAGIC3); F3< 5>(D2,E2,A2,B2,C2,m_M[13]+MAGIC8); F4<11>(C1,D1,E1,A1,B1,m_M[ 1]+MAGIC4); F2<15>(C2,D2,E2,A2,B2,m_M[ 8]+MAGIC9); F4<12>(B1,C1,D1,E1,A1,m_M[ 9]+MAGIC4); F2< 5>(B2,C2,D2,E2,A2,m_M[ 6]+MAGIC9); F4<14>(A1,B1,C1,D1,E1,m_M[11]+MAGIC4); F2< 8>(A2,B2,C2,D2,E2,m_M[ 4]+MAGIC9); F4<15>(E1,A1,B1,C1,D1,m_M[10]+MAGIC4); F2<11>(E2,A2,B2,C2,D2,m_M[ 1]+MAGIC9); F4<14>(D1,E1,A1,B1,C1,m_M[ 0]+MAGIC4); F2<14>(D2,E2,A2,B2,C2,m_M[ 3]+MAGIC9); F4<15>(C1,D1,E1,A1,B1,m_M[ 8]+MAGIC4); F2<14>(C2,D2,E2,A2,B2,m_M[11]+MAGIC9); F4< 9>(B1,C1,D1,E1,A1,m_M[12]+MAGIC4); F2< 6>(B2,C2,D2,E2,A2,m_M[15]+MAGIC9); F4< 8>(A1,B1,C1,D1,E1,m_M[ 4]+MAGIC4); F2<14>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC9); F4< 9>(E1,A1,B1,C1,D1,m_M[13]+MAGIC4); F2< 6>(E2,A2,B2,C2,D2,m_M[ 5]+MAGIC9); F4<14>(D1,E1,A1,B1,C1,m_M[ 3]+MAGIC4); F2< 9>(D2,E2,A2,B2,C2,m_M[12]+MAGIC9); F4< 5>(C1,D1,E1,A1,B1,m_M[ 7]+MAGIC4); F2<12>(C2,D2,E2,A2,B2,m_M[ 2]+MAGIC9); F4< 6>(B1,C1,D1,E1,A1,m_M[15]+MAGIC4); F2< 9>(B2,C2,D2,E2,A2,m_M[13]+MAGIC9); F4< 8>(A1,B1,C1,D1,E1,m_M[14]+MAGIC4); F2<12>(A2,B2,C2,D2,E2,m_M[ 9]+MAGIC9); F4< 6>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC4); F2< 5>(E2,A2,B2,C2,D2,m_M[ 7]+MAGIC9); F4< 5>(D1,E1,A1,B1,C1,m_M[ 6]+MAGIC4); F2<15>(D2,E2,A2,B2,C2,m_M[10]+MAGIC9); F4<12>(C1,D1,E1,A1,B1,m_M[ 2]+MAGIC4); F2< 8>(C2,D2,E2,A2,B2,m_M[14]+MAGIC9); F5< 9>(B1,C1,D1,E1,A1,m_M[ 4]+MAGIC5); F1< 8>(B2,C2,D2,E2,A2,m_M[12] ); F5<15>(A1,B1,C1,D1,E1,m_M[ 0]+MAGIC5); F1< 5>(A2,B2,C2,D2,E2,m_M[15] ); F5< 5>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC5); F1<12>(E2,A2,B2,C2,D2,m_M[10] ); F5<11>(D1,E1,A1,B1,C1,m_M[ 9]+MAGIC5); F1< 9>(D2,E2,A2,B2,C2,m_M[ 4] ); F5< 6>(C1,D1,E1,A1,B1,m_M[ 7]+MAGIC5); F1<12>(C2,D2,E2,A2,B2,m_M[ 1] ); F5< 8>(B1,C1,D1,E1,A1,m_M[12]+MAGIC5); F1< 5>(B2,C2,D2,E2,A2,m_M[ 5] ); F5<13>(A1,B1,C1,D1,E1,m_M[ 2]+MAGIC5); F1<14>(A2,B2,C2,D2,E2,m_M[ 8] ); F5<12>(E1,A1,B1,C1,D1,m_M[10]+MAGIC5); F1< 6>(E2,A2,B2,C2,D2,m_M[ 7] ); F5< 5>(D1,E1,A1,B1,C1,m_M[14]+MAGIC5); F1< 8>(D2,E2,A2,B2,C2,m_M[ 6] ); F5<12>(C1,D1,E1,A1,B1,m_M[ 1]+MAGIC5); F1<13>(C2,D2,E2,A2,B2,m_M[ 2] ); F5<13>(B1,C1,D1,E1,A1,m_M[ 3]+MAGIC5); F1< 6>(B2,C2,D2,E2,A2,m_M[13] ); F5<14>(A1,B1,C1,D1,E1,m_M[ 8]+MAGIC5); F1< 5>(A2,B2,C2,D2,E2,m_M[14] ); F5<11>(E1,A1,B1,C1,D1,m_M[11]+MAGIC5); F1<15>(E2,A2,B2,C2,D2,m_M[ 0] ); F5< 8>(D1,E1,A1,B1,C1,m_M[ 6]+MAGIC5); F1<13>(D2,E2,A2,B2,C2,m_M[ 3] ); F5< 5>(C1,D1,E1,A1,B1,m_M[15]+MAGIC5); F1<11>(C2,D2,E2,A2,B2,m_M[ 9] ); F5< 6>(B1,C1,D1,E1,A1,m_M[13]+MAGIC5); F1<11>(B2,C2,D2,E2,A2,m_M[11] ); C1 = m_digest[1] + C1 + D2; m_digest[1] = m_digest[2] + D1 + E2; m_digest[2] = m_digest[3] + E1 + A2; m_digest[3] = m_digest[4] + A1 + B2; m_digest[4] = m_digest[0] + B1 + C2; m_digest[0] = C1; input += hash_block_size(); } } /* * Copy out the digest */ void RIPEMD_160::copy_out(uint8_t output[]) { copy_out_vec_le(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void RIPEMD_160::clear() { MDx_HashFunction::clear(); zeroise(m_M); m_digest[0] = 0x67452301; m_digest[1] = 0xEFCDAB89; m_digest[2] = 0x98BADCFE; m_digest[3] = 0x10325476; m_digest[4] = 0xC3D2E1F0; } } /* * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_AUTO_SEEDING_RNG) #endif namespace Botan { void RandomNumberGenerator::randomize_with_ts_input(uint8_t output[], size_t output_len) { if(this->accepts_input()) { /* Form additional input which is provided to the PRNG implementation to paramaterize the KDF output. */ uint8_t additional_input[16] = { 0 }; store_le(OS::get_system_timestamp_ns(), additional_input); store_le(OS::get_high_resolution_clock(), additional_input + 8); this->randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); } else { this->randomize(output, output_len); } } void RandomNumberGenerator::randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) { this->add_entropy(input, input_len); this->randomize(output, output_len); } size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs, size_t poll_bits, std::chrono::milliseconds poll_timeout) { if(this->accepts_input()) { return srcs.poll(*this, poll_bits, poll_timeout); } else { return 0; } } void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) { if(this->accepts_input()) { secure_vector buf(poll_bits / 8); rng.randomize(buf.data(), buf.size()); this->add_entropy(buf.data(), buf.size()); } } RandomNumberGenerator* RandomNumberGenerator::make_rng() { #if defined(BOTAN_HAS_AUTO_SEEDING_RNG) return new AutoSeeded_RNG; #else throw Not_Implemented("make_rng failed, no AutoSeeded_RNG in this build"); #endif } #if defined(BOTAN_TARGET_OS_HAS_THREADS) #if defined(BOTAN_HAS_AUTO_SEEDING_RNG) Serialized_RNG::Serialized_RNG() : m_rng(new AutoSeeded_RNG) {} #else Serialized_RNG::Serialized_RNG() { throw Not_Implemented("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build"); } #endif #endif } /* * Roughtime * (C) 2019 Nuno Goncalves * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { // This exists to work around a LGTM false positive static_assert(Roughtime::request_min_size == 1024, "Expected minimum size"); template< bool B, class T = void > using enable_if_t = typename std::enable_if::type; template struct is_array : std::false_type {}; template struct is_array>:std::true_type{}; template T impl_from_little_endian(const uint8_t* t, const size_t i) { static_assert(sizeof(T) <= sizeof(int64_t), ""); return T(static_cast(t[i]) << i * 8) + (i == 0 ? T(0) : impl_from_little_endian(t, i - 1)); } template T from_little_endian(const uint8_t* t) { return impl_from_little_endian(t, sizeof(T) - 1); } template::value>* = nullptr> T copy(const uint8_t* t) { return typecast_copy(t); //arrays are endianess indepedent, so we do a memcpy } template::value>* = nullptr> T copy(const uint8_t* t) { return from_little_endian(t); //other types are arithmetic, so we account that roughtime serializes as little endian } template std::map> unpack_roughtime_packet(T bytes) { if(bytes.size() < 8) { throw Roughtime::Roughtime_Error("Map length is under minimum of 8 bytes"); } const auto buf = bytes.data(); const uint32_t num_tags = buf[0]; const uint32_t start_content = num_tags * 8; if(start_content > bytes.size()) { throw Roughtime::Roughtime_Error("Map length too small to contain all tags"); } uint32_t start = start_content; std::map> tags; for(uint32_t i=0; i(buf + 4 + i*4); if(end > bytes.size()) { throw Roughtime::Roughtime_Error("Tag end index out of bounds"); } if(end < start) { throw Roughtime::Roughtime_Error("Tag offset must be more than previous tag offset"); } const char* label_ptr = cast_uint8_ptr_to_char(buf) + (num_tags+i)*4; const char label[] = {label_ptr[0], label_ptr[1], label_ptr[2], label_ptr[3], 0}; auto ret = tags.emplace(label, std::vector(buf+start, buf+end)); if(!ret.second) { throw Roughtime::Roughtime_Error(std::string("Map has duplicated tag: ") + label); } start = static_cast(end); } return tags; } template T get(const std::map>& map, const std::string& label) { const auto& tag = map.find(label); if(tag == map.end()) { throw Roughtime::Roughtime_Error("Tag " + label + " not found"); } if(tag->second.size() != sizeof(T)) { throw Roughtime::Roughtime_Error("Tag " + label + " has unexpected size"); } return copy(tag->second.data()); } const std::vector& get_v(const std::map>& map, const std::string& label) { const auto& tag = map.find(label); if(tag == map.end()) { throw Roughtime::Roughtime_Error("Tag " + label + " not found"); } return tag->second; } bool verify_signature(const std::array& pk, const std::vector& payload, const std::array& signature) { const char context[] = "RoughTime v1 response signature"; Ed25519_PublicKey key(std::vector(pk.data(), pk.data()+pk.size())); PK_Verifier verifier(key, "Pure"); verifier.update(cast_char_ptr_to_uint8(context), sizeof(context)); //add context including \0 verifier.update(payload); return verifier.check_signature(signature.data(), signature.size()); } std::array hashLeaf(const std::array& leaf) { std::array ret; std::unique_ptr hash(HashFunction::create_or_throw("SHA-512")); hash->update(0); hash->update(leaf.data(), leaf.size()); hash->final(ret.data()); return ret; } void hashNode(std::array& hash, const std::array& node, bool reverse) { std::unique_ptr h(HashFunction::create_or_throw("SHA-512")); h->update(1); if(reverse) { h->update(node.data(), node.size()); h->update(hash.data(), hash.size()); } else { h->update(hash.data(), hash.size()); h->update(node.data(), node.size()); } h->final(hash.data()); } template std::array vector_to_array(std::vector vec) { if(vec.size() != N) { throw std::logic_error("Invalid vector size"); } return typecast_copy>(vec.data()); } } namespace Roughtime { Nonce::Nonce(const std::vector& nonce) { if(nonce.size() != 64) { throw Invalid_Argument("Nonce lenght must be 64"); } m_nonce = typecast_copy>(nonce.data()); } Nonce::Nonce(RandomNumberGenerator& rng) { rng.randomize(m_nonce.data(), m_nonce.size()); } std::array encode_request(const Nonce& nonce) { std::array buf = {{2, 0, 0, 0, 64, 0, 0, 0, 'N', 'O', 'N', 'C', 'P', 'A', 'D', 0xff}}; std::memcpy(buf.data() + 16, nonce.get_nonce().data(), nonce.get_nonce().size()); std::memset(buf.data() + 16 + nonce.get_nonce().size(), 0, buf.size() - 16 - nonce.get_nonce().size()); return buf; } Response Response::from_bits(const std::vector& response, const Nonce& nonce) { const auto response_v = unpack_roughtime_packet(response); const auto cert = unpack_roughtime_packet(get_v(response_v, "CERT")); const auto cert_dele = get>(cert, "DELE"); const auto cert_sig = get>(cert, "SIG"); const auto cert_dele_v = unpack_roughtime_packet(cert_dele); const auto srep = get_v(response_v, "SREP"); const auto srep_v = unpack_roughtime_packet(srep); const auto cert_dele_pubk = get>(cert_dele_v, "PUBK"); const auto sig = get>(response_v, "SIG"); if(!verify_signature(cert_dele_pubk, srep, sig)) { throw Roughtime_Error("Response signature invalid"); } const auto indx = get(response_v, "INDX"); const auto path = get_v(response_v, "PATH"); const auto srep_root = get>(srep_v, "ROOT"); const auto size = path.size(); const auto levels = size/64; if(size % 64) { throw Roughtime_Error("Merkle tree path size must be multiple of 64 bytes"); } if(indx >= (1u << levels)) { throw Roughtime_Error("Merkle tree path is too short"); } auto hash = hashLeaf(nonce.get_nonce()); auto index = indx; auto level = 0u; while(level < levels) { hashNode(hash, typecast_copy>(path.data() + level*64), index&1); ++level; index>>=1; } if(srep_root != hash) { throw Roughtime_Error("Nonce verification failed"); } const auto cert_dele_maxt = sys_microseconds64(get(cert_dele_v, "MAXT")); const auto cert_dele_mint = sys_microseconds64(get(cert_dele_v, "MINT")); const auto srep_midp = sys_microseconds64(get(srep_v, "MIDP")); const auto srep_radi = get(srep_v, "RADI"); if(srep_midp < cert_dele_mint) { throw Roughtime_Error("Midpoint earlier than delegation start"); } if(srep_midp > cert_dele_maxt) { throw Roughtime_Error("Midpoint later than delegation end"); } return {cert_dele, cert_sig, srep_midp, srep_radi}; } bool Response::validate(const Ed25519_PublicKey& pk) const { const char context[] = "RoughTime v1 delegation signature--"; PK_Verifier verifier(pk, "Pure"); verifier.update(cast_char_ptr_to_uint8(context), sizeof(context)); //add context including \0 verifier.update(m_cert_dele.data(), m_cert_dele.size()); return verifier.check_signature(m_cert_sig.data(), m_cert_sig.size()); } Nonce nonce_from_blind(const std::vector& previous_response, const Nonce& blind) { std::array ret; const auto blind_arr = blind.get_nonce(); std::unique_ptr hash(Botan::HashFunction::create_or_throw("SHA-512")); hash->update(previous_response); hash->update(hash->final()); hash->update(blind_arr.data(), blind_arr.size()); hash->final(ret.data()); return ret; } Chain::Chain(const std::string& str) { std::stringstream ss(str); const std::string ERROR_MESSAGE = "Line does not have 4 space separated fields"; for(std::string s; std::getline(ss, s);) { size_t start = 0, end = 0; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto publicKeyType = s.substr(start, end-start); if(publicKeyType != "ed25519") { throw Not_Implemented("Only ed25519 publicKeyType is implemented"); } start = end + 1; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto serverPublicKey = Botan::Ed25519_PublicKey(Botan::base64_decode(s.substr(start, end-start))); start = end + 1; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } if((end - start) != 88) { throw Decoding_Error("Nonce has invalid length"); } const auto vec = Botan::base64_decode(s.substr(start, end-start)); const auto nonceOrBlind = Nonce(vector_to_array<64>(Botan::base64_decode(s.substr(start, end-start)))); start = end + 1; end = s.find(' ', start); if(end != std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto response = Botan::unlock(Botan::base64_decode(s.substr(start))); m_links.push_back({response, serverPublicKey, nonceOrBlind}); } } std::vector Chain::responses() const { std::vector responses; for(unsigned i = 0; i < m_links.size(); ++i) { const auto& l = m_links[i]; const auto nonce = i ? nonce_from_blind(m_links[i-1].response(), l.nonce_or_blind()) : l.nonce_or_blind(); const auto response = Response::from_bits(l.response(), nonce); if(!response.validate(l.public_key())) { throw Roughtime_Error("Invalid signature or public key"); } responses.push_back(response); } return responses; } Nonce Chain::next_nonce(const Nonce& blind) const { return m_links.empty() ? blind : nonce_from_blind(m_links.back().response(), blind); } void Chain::append(const Link& new_link, size_t max_chain_size) { if(max_chain_size <= 0) { throw Invalid_Argument("Max chain size must be positive"); } while(m_links.size() >= max_chain_size) { if(m_links.size() == 1) { auto new_link_updated = new_link; new_link_updated.nonce_or_blind() = nonce_from_blind(m_links[0].response(), new_link.nonce_or_blind()); //we need to convert blind to nonce m_links.clear(); m_links.push_back(new_link_updated); return; } if(m_links.size() >= 2) { m_links[1].nonce_or_blind() = nonce_from_blind(m_links[0].response(), m_links[1].nonce_or_blind()); //we need to convert blind to nonce } m_links.erase(m_links.begin()); } m_links.push_back(new_link); } std::string Chain::to_string() const { std::string s; s.reserve((7+1 + 88+1 + 44+1 + 480)*m_links.size()); for(const auto& link : m_links) { s += "ed25519"; s += ' '; s += Botan::base64_encode(link.public_key().get_public_key()); s += ' '; s += Botan::base64_encode(link.nonce_or_blind().get_nonce().data(), link.nonce_or_blind().get_nonce().size()); s += ' '; s += Botan::base64_encode(link.response()); s += '\n'; } return s; } std::vector online_request(const std::string& uri, const Nonce& nonce, std::chrono::milliseconds timeout) { const std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now(); auto socket = OS::open_socket_udp(uri, timeout); if(!socket) { throw Not_Implemented("No socket support enabled in build"); } const auto encoded = encode_request(nonce); socket->write(encoded.data(), encoded.size()); if(std::chrono::system_clock::now() - start_time > timeout) { throw System_Error("Timeout during socket write"); } std::vector buffer; buffer.resize(360+64*10+1); //response basic size is 360 bytes + 64 bytes for each level of merkle tree //add one additional byte to be able to differentiate if datagram got truncated const auto n = socket->read(buffer.data(), buffer.size()); if(!n || std::chrono::system_clock::now() - start_time > timeout) { throw System_Error("Timeout waiting for response"); } if(n == buffer.size()) { throw System_Error("Buffer too small"); } buffer.resize(n); return buffer; } std::vector servers_from_str(const std::string& str) { std::vector servers; std::stringstream ss(str); const std::string ERROR_MESSAGE = "Line does not have at least 5 space separated fields"; for(std::string s; std::getline(ss, s);) { size_t start = 0, end = 0; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto name = s.substr(start, end-start); start = end + 1; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto publicKeyType = s.substr(start, end-start); if(publicKeyType != "ed25519") { throw Not_Implemented("Only ed25519 publicKeyType is implemented"); } start = end + 1; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto publicKeyBase64 = s.substr(start, end-start); const auto publicKey = Botan::Ed25519_PublicKey(Botan::base64_decode(publicKeyBase64)); start = end + 1; end = s.find(' ', start); if(end == std::string::npos) { throw Decoding_Error(ERROR_MESSAGE); } const auto protocol = s.substr(start, end-start); if(protocol != "udp") { throw Not_Implemented("Only UDP protocol is implemented"); } const auto addresses = [&]() { std::vector addr; for(;;) { start = end + 1; end = s.find(' ', start); const auto address = s.substr(start, (end == std::string::npos) ? std::string::npos : end-start); if(address.empty()) { return addr; } addr.push_back(address); if(end == std::string::npos) { return addr; } } } (); if(addresses.size() == 0) { throw Decoding_Error(ERROR_MESSAGE); } servers.push_back({name, publicKey, std::move(addresses)}); } return servers; } } } /* * RSA * (C) 1999-2010,2015,2016,2018,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_OPENSSL) #endif #if defined(BOTAN_HAS_THREAD_UTILS) #endif namespace Botan { class RSA_Public_Data final { public: RSA_Public_Data(BigInt&& n, BigInt&& e) : m_n(n), m_e(e), m_monty_n(std::make_shared(m_n)), m_public_modulus_bits(m_n.bits()), m_public_modulus_bytes(m_n.bytes()) {} BigInt public_op(const BigInt& m) const { const size_t powm_window = 1; auto powm_m_n = monty_precompute(m_monty_n, m, powm_window, false); return monty_execute_vartime(*powm_m_n, m_e); } const BigInt& get_n() const { return m_n; } const BigInt& get_e() const { return m_e; } size_t public_modulus_bits() const { return m_public_modulus_bits; } size_t public_modulus_bytes() const { return m_public_modulus_bytes; } private: BigInt m_n; BigInt m_e; std::shared_ptr m_monty_n; size_t m_public_modulus_bits; size_t m_public_modulus_bytes; }; class RSA_Private_Data final { public: RSA_Private_Data(BigInt&& d, BigInt&& p, BigInt&& q, BigInt&& d1, BigInt&& d2, BigInt&& c) : m_d(d), m_p(p), m_q(q), m_d1(d1), m_d2(d2), m_c(c), m_mod_p(m_p), m_mod_q(m_q), m_monty_p(std::make_shared(m_p, m_mod_p)), m_monty_q(std::make_shared(m_q, m_mod_q)), m_p_bits(m_p.bits()), m_q_bits(m_q.bits()) {} const BigInt& get_d() const { return m_d; } const BigInt& get_p() const { return m_p; } const BigInt& get_q() const { return m_q; } const BigInt& get_d1() const { return m_d1; } const BigInt& get_d2() const { return m_d2; } const BigInt& get_c() const { return m_c; } //private: BigInt m_d; BigInt m_p; BigInt m_q; BigInt m_d1; BigInt m_d2; BigInt m_c; Modular_Reducer m_mod_p; Modular_Reducer m_mod_q; std::shared_ptr m_monty_p; std::shared_ptr m_monty_q; size_t m_p_bits; size_t m_q_bits; }; std::shared_ptr RSA_PublicKey::public_data() const { return m_public; } const BigInt& RSA_PublicKey::get_n() const { return m_public->get_n(); } const BigInt& RSA_PublicKey::get_e() const { return m_public->get_e(); } void RSA_PublicKey::init(BigInt&& n, BigInt&& e) { if(n.is_negative() || n.is_even() || e.is_negative() || e.is_even()) throw Decoding_Error("Invalid RSA public key parameters"); m_public = std::make_shared(std::move(n), std::move(e)); } RSA_PublicKey::RSA_PublicKey(const AlgorithmIdentifier&, const std::vector& key_bits) { BigInt n, e; BER_Decoder(key_bits) .start_cons(SEQUENCE) .decode(n) .decode(e) .end_cons(); init(std::move(n), std::move(e)); } RSA_PublicKey::RSA_PublicKey(const BigInt& modulus, const BigInt& exponent) { BigInt n = modulus; BigInt e = exponent; init(std::move(n), std::move(e)); } size_t RSA_PublicKey::key_length() const { return m_public->public_modulus_bits(); } size_t RSA_PublicKey::estimated_strength() const { return if_work_factor(key_length()); } AlgorithmIdentifier RSA_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_NULL_PARAM); } std::vector RSA_PublicKey::public_key_bits() const { std::vector output; DER_Encoder der(output); der.start_cons(SEQUENCE) .encode(get_n()) .encode(get_e()) .end_cons(); return output; } /* * Check RSA Public Parameters */ bool RSA_PublicKey::check_key(RandomNumberGenerator&, bool) const { if(get_n() < 35 || get_n().is_even() || get_e() < 3 || get_e().is_even()) return false; return true; } std::shared_ptr RSA_PrivateKey::private_data() const { return m_private; } secure_vector RSA_PrivateKey::private_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) .encode(static_cast(0)) .encode(get_n()) .encode(get_e()) .encode(get_d()) .encode(get_p()) .encode(get_q()) .encode(get_d1()) .encode(get_d2()) .encode(get_c()) .end_cons() .get_contents(); } const BigInt& RSA_PrivateKey::get_p() const { return m_private->get_p(); } const BigInt& RSA_PrivateKey::get_q() const { return m_private->get_q(); } const BigInt& RSA_PrivateKey::get_d() const { return m_private->get_d(); } const BigInt& RSA_PrivateKey::get_c() const { return m_private->get_c(); } const BigInt& RSA_PrivateKey::get_d1() const { return m_private->get_d1(); } const BigInt& RSA_PrivateKey::get_d2() const { return m_private->get_d2(); } void RSA_PrivateKey::init(BigInt&& d, BigInt&& p, BigInt&& q, BigInt&& d1, BigInt&& d2, BigInt&& c) { m_private = std::make_shared( std::move(d), std::move(p), std::move(q), std::move(d1), std::move(d2), std::move(c)); } RSA_PrivateKey::RSA_PrivateKey(const AlgorithmIdentifier&, const secure_vector& key_bits) { BigInt n, e, d, p, q, d1, d2, c; BER_Decoder(key_bits) .start_cons(SEQUENCE) .decode_and_check(0, "Unknown PKCS #1 key format version") .decode(n) .decode(e) .decode(d) .decode(p) .decode(q) .decode(d1) .decode(d2) .decode(c) .end_cons(); RSA_PublicKey::init(std::move(n), std::move(e)); RSA_PrivateKey::init(std::move(d), std::move(p), std::move(q), std::move(d1), std::move(d2), std::move(c)); } RSA_PrivateKey::RSA_PrivateKey(const BigInt& prime1, const BigInt& prime2, const BigInt& exp, const BigInt& d_exp, const BigInt& mod) { BigInt p = prime1; BigInt q = prime2; BigInt n = mod; if(n.is_zero()) n = p * q; BigInt e = exp; BigInt d = d_exp; const BigInt p_minus_1 = p - 1; const BigInt q_minus_1 = q - 1; if(d.is_zero()) { const BigInt phi_n = lcm(p_minus_1, q_minus_1); d = inverse_mod(e, phi_n); } BigInt d1 = ct_modulo(d, p_minus_1); BigInt d2 = ct_modulo(d, q_minus_1); BigInt c = inverse_mod(q, p); RSA_PublicKey::init(std::move(n), std::move(e)); RSA_PrivateKey::init(std::move(d), std::move(p), std::move(q), std::move(d1), std::move(d2), std::move(c)); } /* * Create a RSA private key */ RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, size_t bits, size_t exp) { if(bits < 1024) throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + std::to_string(bits) + " bits long"); if(exp < 3 || exp % 2 == 0) throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); BigInt n, e, d, p, q, d1, d2, c; e = exp; const size_t p_bits = (bits + 1) / 2; const size_t q_bits = bits - p_bits; do { // TODO could generate primes in thread pool p = generate_rsa_prime(rng, rng, p_bits, e); q = generate_rsa_prime(rng, rng, q_bits, e); if(p == q) throw Internal_Error("RNG failure during RSA key generation"); n = p * q; } while(n.bits() != bits); const BigInt p_minus_1 = p - 1; const BigInt q_minus_1 = q - 1; const BigInt phi_n = lcm(p_minus_1, q_minus_1); d = inverse_mod(e, phi_n); d1 = ct_modulo(d, p_minus_1); d2 = ct_modulo(d, q_minus_1); c = inverse_mod(q, p); RSA_PublicKey::init(std::move(n), std::move(e)); RSA_PrivateKey::init(std::move(d), std::move(p), std::move(q), std::move(d1), std::move(d2), std::move(c)); } /* * Check Private RSA Parameters */ bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(get_n() < 35 || get_n().is_even() || get_e() < 3 || get_e().is_even()) return false; if(get_d() < 2 || get_p() < 3 || get_q() < 3) return false; if(get_p() * get_q() != get_n()) return false; if(get_p() == get_q()) return false; if(get_d1() != ct_modulo(get_d(), get_p() - 1)) return false; if(get_d2() != ct_modulo(get_d(), get_q() - 1)) return false; if(get_c() != inverse_mod(get_q(), get_p())) return false; const size_t prob = (strong) ? 128 : 12; if(!is_prime(get_p(), rng, prob)) return false; if(!is_prime(get_q(), rng, prob)) return false; if(strong) { if(ct_modulo(get_e() * get_d(), lcm(get_p() - 1, get_q() - 1)) != 1) return false; return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-256)"); } return true; } namespace { /** * RSA private (decrypt/sign) operation */ class RSA_Private_Operation { protected: size_t public_modulus_bits() const { return m_public->public_modulus_bits(); } size_t public_modulus_bytes() const { return m_public->public_modulus_bytes(); } explicit RSA_Private_Operation(const RSA_PrivateKey& rsa, RandomNumberGenerator& rng) : m_public(rsa.public_data()), m_private(rsa.private_data()), m_blinder(m_public->get_n(), rng, [this](const BigInt& k) { return m_public->public_op(k); }, [this](const BigInt& k) { return inverse_mod(k, m_public->get_n()); }), m_blinding_bits(64), m_max_d1_bits(m_private->m_p_bits + m_blinding_bits), m_max_d2_bits(m_private->m_q_bits + m_blinding_bits) { } secure_vector raw_op(const uint8_t input[], size_t input_len) { const BigInt input_bn(input, input_len); if(input_bn >= m_public->get_n()) throw Invalid_Argument("RSA private op - input is too large"); // TODO: This should be a function on blinder // BigInt Blinder::run_blinded_function(std::function fn, const BigInt& input); const BigInt recovered = m_blinder.unblind(rsa_private_op(m_blinder.blind(input_bn))); BOTAN_ASSERT(input_bn == m_public->public_op(recovered), "RSA consistency check"); return BigInt::encode_1363(recovered, m_public->public_modulus_bytes()); } private: BigInt rsa_private_op(const BigInt& m) const { /* TODO Consider using Montgomery reduction instead of Barrett, using the "Smooth RSA-CRT" method. https://eprint.iacr.org/2007/039.pdf */ static constexpr size_t powm_window = 4; // Compute this in main thread to avoid racing on the rng const BigInt d1_mask(m_blinder.rng(), m_blinding_bits); #if defined(BOTAN_HAS_THREAD_UTILS) && !defined(BOTAN_HAS_VALGRIND) #define BOTAN_RSA_USE_ASYNC #endif #if defined(BOTAN_RSA_USE_ASYNC) /* * Precompute m.sig_words in the main thread before calling async. Otherwise * the two threads race (during Modular_Reducer::reduce) and while the output * is correct in both threads, helgrind warns. */ m.sig_words(); auto future_j1 = Thread_Pool::global_instance().run([this, &m, &d1_mask]() { #endif const BigInt masked_d1 = m_private->get_d1() + (d1_mask * (m_private->get_p() - 1)); auto powm_d1_p = monty_precompute(m_private->m_monty_p, m_private->m_mod_p.reduce(m), powm_window); BigInt j1 = monty_execute(*powm_d1_p, masked_d1, m_max_d1_bits); #if defined(BOTAN_RSA_USE_ASYNC) return j1; }); #endif const BigInt d2_mask(m_blinder.rng(), m_blinding_bits); const BigInt masked_d2 = m_private->get_d2() + (d2_mask * (m_private->get_q() - 1)); auto powm_d2_q = monty_precompute(m_private->m_monty_q, m_private->m_mod_q.reduce(m), powm_window); const BigInt j2 = monty_execute(*powm_d2_q, masked_d2, m_max_d2_bits); #if defined(BOTAN_RSA_USE_ASYNC) BigInt j1 = future_j1.get(); #endif /* * To recover the final value from the CRT representation (j1,j2) * we use Garner's algorithm: * c = q^-1 mod p (this is precomputed) * h = c*(j1-j2) mod p * m = j2 + h*q * * We must avoid leaking if j1 >= j2 or not, as doing so allows deriving * information about the secret prime. Do this by first adding p to j1, * which should ensure the subtraction of j2 does not underflow. But * this may still underflow if p and q are imbalanced in size. */ j1 = m_private->m_mod_p.multiply(m_private->m_mod_p.reduce((m_private->get_p() + j1) - j2), m_private->get_c()); return mul_add(j1, m_private->get_q(), j2); } std::shared_ptr m_public; std::shared_ptr m_private; // XXX could the blinder starting pair be shared? Blinder m_blinder; const size_t m_blinding_bits; const size_t m_max_d1_bits; const size_t m_max_d2_bits; }; class RSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA, private RSA_Private_Operation { public: size_t max_input_bits() const override { return public_modulus_bits() - 1; } size_t signature_length() const override { return public_modulus_bytes(); } RSA_Signature_Operation(const RSA_PrivateKey& rsa, const std::string& emsa, RandomNumberGenerator& rng) : PK_Ops::Signature_with_EMSA(emsa), RSA_Private_Operation(rsa, rng) { } secure_vector raw_sign(const uint8_t input[], size_t input_len, RandomNumberGenerator&) override { return raw_op(input, input_len); } }; class RSA_Decryption_Operation final : public PK_Ops::Decryption_with_EME, private RSA_Private_Operation { public: RSA_Decryption_Operation(const RSA_PrivateKey& rsa, const std::string& eme, RandomNumberGenerator& rng) : PK_Ops::Decryption_with_EME(eme), RSA_Private_Operation(rsa, rng) { } size_t plaintext_length(size_t) const override { return public_modulus_bytes(); } secure_vector raw_decrypt(const uint8_t input[], size_t input_len) override { return raw_op(input, input_len); } }; class RSA_KEM_Decryption_Operation final : public PK_Ops::KEM_Decryption_with_KDF, private RSA_Private_Operation { public: RSA_KEM_Decryption_Operation(const RSA_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : PK_Ops::KEM_Decryption_with_KDF(kdf), RSA_Private_Operation(key, rng) {} secure_vector raw_kem_decrypt(const uint8_t encap_key[], size_t len) override { return raw_op(encap_key, len); } }; /** * RSA public (encrypt/verify) operation */ class RSA_Public_Operation { public: explicit RSA_Public_Operation(const RSA_PublicKey& rsa) : m_public(rsa.public_data()) {} size_t get_max_input_bits() const { const size_t n_bits = m_public->public_modulus_bits(); /* Make Coverity happy that n_bits - 1 won't underflow 5 bit minimum: smallest possible RSA key is 3*5 */ BOTAN_ASSERT_NOMSG(n_bits >= 5); return n_bits - 1; } protected: BigInt public_op(const BigInt& m) const { if(m >= m_public->get_n()) throw Invalid_Argument("RSA public op - input is too large"); return m_public->public_op(m); } size_t public_modulus_bytes() const { return m_public->public_modulus_bytes(); } const BigInt& get_n() const { return m_public->get_n(); } std::shared_ptr m_public; }; class RSA_Encryption_Operation final : public PK_Ops::Encryption_with_EME, private RSA_Public_Operation { public: RSA_Encryption_Operation(const RSA_PublicKey& rsa, const std::string& eme) : PK_Ops::Encryption_with_EME(eme), RSA_Public_Operation(rsa) { } size_t ciphertext_length(size_t) const override { return public_modulus_bytes(); } size_t max_raw_input_bits() const override { return get_max_input_bits(); } secure_vector raw_encrypt(const uint8_t input[], size_t input_len, RandomNumberGenerator&) override { BigInt input_bn(input, input_len); return BigInt::encode_1363(public_op(input_bn), public_modulus_bytes()); } }; class RSA_Verify_Operation final : public PK_Ops::Verification_with_EMSA, private RSA_Public_Operation { public: size_t max_input_bits() const override { return get_max_input_bits(); } RSA_Verify_Operation(const RSA_PublicKey& rsa, const std::string& emsa) : PK_Ops::Verification_with_EMSA(emsa), RSA_Public_Operation(rsa) { } bool with_recovery() const override { return true; } secure_vector verify_mr(const uint8_t input[], size_t input_len) override { BigInt input_bn(input, input_len); return BigInt::encode_locked(public_op(input_bn)); } }; class RSA_KEM_Encryption_Operation final : public PK_Ops::KEM_Encryption_with_KDF, private RSA_Public_Operation { public: RSA_KEM_Encryption_Operation(const RSA_PublicKey& key, const std::string& kdf) : PK_Ops::KEM_Encryption_with_KDF(kdf), RSA_Public_Operation(key) {} private: void raw_kem_encrypt(secure_vector& out_encapsulated_key, secure_vector& raw_shared_key, Botan::RandomNumberGenerator& rng) override { const BigInt r = BigInt::random_integer(rng, 1, get_n()); const BigInt c = public_op(r); out_encapsulated_key = BigInt::encode_locked(c); raw_shared_key = BigInt::encode_locked(r); } }; } std::unique_ptr RSA_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { try { return make_openssl_rsa_enc_op(*this, params); } catch(Exception& e) { /* * If OpenSSL for some reason could not handle this (eg due to OAEP params), * throw if openssl was specifically requested but otherwise just fall back * to the normal version. */ if(provider == "openssl") throw Lookup_Error("OpenSSL RSA provider rejected key:" + std::string(e.what())); } } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new RSA_Encryption_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr RSA_PublicKey::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new RSA_KEM_Encryption_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr RSA_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { std::unique_ptr res = make_openssl_rsa_ver_op(*this, params); if(res) return res; } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new RSA_Verify_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr RSA_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { try { return make_openssl_rsa_dec_op(*this, params); } catch(Exception& e) { if(provider == "openssl") throw Lookup_Error("OpenSSL RSA provider rejected key:" + std::string(e.what())); } } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new RSA_Decryption_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr RSA_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr(new RSA_KEM_Decryption_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr RSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { #if defined(BOTAN_HAS_OPENSSL) if(provider == "openssl" || provider.empty()) { std::unique_ptr res = make_openssl_rsa_sig_op(*this, params); if(res) return res; } #endif if(provider == "base" || provider.empty()) return std::unique_ptr(new RSA_Signature_Operation(*this, params, rng)); throw Provider_Not_Found(algo_name(), provider); } } /* * Salsa20 / XSalsa20 * (C) 1999-2010,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { #define SALSA20_QUARTER_ROUND(x1, x2, x3, x4) \ do { \ x2 ^= rotl<7>(x1 + x4); \ x3 ^= rotl<9>(x2 + x1); \ x4 ^= rotl<13>(x3 + x2); \ x1 ^= rotl<18>(x4 + x3); \ } while(0) /* * Generate HSalsa20 cipher stream (for XSalsa20 IV setup) */ //static void Salsa20::hsalsa20(uint32_t output[8], const uint32_t input[16]) { uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; for(size_t i = 0; i != 10; ++i) { SALSA20_QUARTER_ROUND(x00, x04, x08, x12); SALSA20_QUARTER_ROUND(x05, x09, x13, x01); SALSA20_QUARTER_ROUND(x10, x14, x02, x06); SALSA20_QUARTER_ROUND(x15, x03, x07, x11); SALSA20_QUARTER_ROUND(x00, x01, x02, x03); SALSA20_QUARTER_ROUND(x05, x06, x07, x04); SALSA20_QUARTER_ROUND(x10, x11, x08, x09); SALSA20_QUARTER_ROUND(x15, x12, x13, x14); } output[0] = x00; output[1] = x05; output[2] = x10; output[3] = x15; output[4] = x06; output[5] = x07; output[6] = x08; output[7] = x09; } /* * Generate Salsa20 cipher stream */ //static void Salsa20::salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds) { BOTAN_ASSERT_NOMSG(rounds % 2 == 0); uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; for(size_t i = 0; i != rounds / 2; ++i) { SALSA20_QUARTER_ROUND(x00, x04, x08, x12); SALSA20_QUARTER_ROUND(x05, x09, x13, x01); SALSA20_QUARTER_ROUND(x10, x14, x02, x06); SALSA20_QUARTER_ROUND(x15, x03, x07, x11); SALSA20_QUARTER_ROUND(x00, x01, x02, x03); SALSA20_QUARTER_ROUND(x05, x06, x07, x04); SALSA20_QUARTER_ROUND(x10, x11, x08, x09); SALSA20_QUARTER_ROUND(x15, x12, x13, x14); } store_le(x00 + input[ 0], output + 4 * 0); store_le(x01 + input[ 1], output + 4 * 1); store_le(x02 + input[ 2], output + 4 * 2); store_le(x03 + input[ 3], output + 4 * 3); store_le(x04 + input[ 4], output + 4 * 4); store_le(x05 + input[ 5], output + 4 * 5); store_le(x06 + input[ 6], output + 4 * 6); store_le(x07 + input[ 7], output + 4 * 7); store_le(x08 + input[ 8], output + 4 * 8); store_le(x09 + input[ 9], output + 4 * 9); store_le(x10 + input[10], output + 4 * 10); store_le(x11 + input[11], output + 4 * 11); store_le(x12 + input[12], output + 4 * 12); store_le(x13 + input[13], output + 4 * 13); store_le(x14 + input[14], output + 4 * 14); store_le(x15 + input[15], output + 4 * 15); } #undef SALSA20_QUARTER_ROUND /* * Combine cipher stream with message */ void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length) { verify_key_set(m_state.empty() == false); while(length >= m_buffer.size() - m_position) { const size_t available = m_buffer.size() - m_position; xor_buf(out, in, &m_buffer[m_position], available); salsa_core(m_buffer.data(), m_state.data(), 20); ++m_state[8]; m_state[9] += (m_state[8] == 0); length -= available; in += available; out += available; m_position = 0; } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; } void Salsa20::initialize_state() { static const uint32_t TAU[] = { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; static const uint32_t SIGMA[] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; m_state[1] = m_key[0]; m_state[2] = m_key[1]; m_state[3] = m_key[2]; m_state[4] = m_key[3]; if(m_key.size() == 4) { m_state[0] = TAU[0]; m_state[5] = TAU[1]; m_state[10] = TAU[2]; m_state[15] = TAU[3]; m_state[11] = m_key[0]; m_state[12] = m_key[1]; m_state[13] = m_key[2]; m_state[14] = m_key[3]; } else { m_state[0] = SIGMA[0]; m_state[5] = SIGMA[1]; m_state[10] = SIGMA[2]; m_state[15] = SIGMA[3]; m_state[11] = m_key[4]; m_state[12] = m_key[5]; m_state[13] = m_key[6]; m_state[14] = m_key[7]; } m_state[6] = 0; m_state[7] = 0; m_state[8] = 0; m_state[9] = 0; m_position = 0; } /* * Salsa20 Key Schedule */ void Salsa20::key_schedule(const uint8_t key[], size_t length) { m_key.resize(length / 4); load_le(m_key.data(), key, m_key.size()); m_state.resize(16); m_buffer.resize(64); set_iv(nullptr, 0); } /* * Set the Salsa IV */ void Salsa20::set_iv(const uint8_t iv[], size_t length) { verify_key_set(m_state.empty() == false); if(!valid_iv_length(length)) throw Invalid_IV_Length(name(), length); initialize_state(); if(length == 0) { // Salsa20 null IV m_state[6] = 0; m_state[7] = 0; } else if(length == 8) { // Salsa20 m_state[6] = load_le(iv, 0); m_state[7] = load_le(iv, 1); } else { // XSalsa20 m_state[6] = load_le(iv, 0); m_state[7] = load_le(iv, 1); m_state[8] = load_le(iv, 2); m_state[9] = load_le(iv, 3); secure_vector hsalsa(8); hsalsa20(hsalsa.data(), m_state.data()); m_state[ 1] = hsalsa[0]; m_state[ 2] = hsalsa[1]; m_state[ 3] = hsalsa[2]; m_state[ 4] = hsalsa[3]; m_state[ 6] = load_le(iv, 4); m_state[ 7] = load_le(iv, 5); m_state[11] = hsalsa[4]; m_state[12] = hsalsa[5]; m_state[13] = hsalsa[6]; m_state[14] = hsalsa[7]; } m_state[8] = 0; m_state[9] = 0; salsa_core(m_buffer.data(), m_state.data(), 20); ++m_state[8]; m_state[9] += (m_state[8] == 0); m_position = 0; } bool Salsa20::valid_iv_length(size_t iv_len) const { return (iv_len == 0 || iv_len == 8 || iv_len == 24); } size_t Salsa20::default_iv_length() const { return 24; } Key_Length_Specification Salsa20::key_spec() const { return Key_Length_Specification(16, 32, 16); } StreamCipher* Salsa20::clone() const { return new Salsa20; } std::string Salsa20::name() const { return "Salsa20"; } /* * Clear memory of sensitive data */ void Salsa20::clear() { zap(m_key); zap(m_state); zap(m_buffer); m_position = 0; } void Salsa20::seek(uint64_t offset) { verify_key_set(m_state.empty() == false); // Find the block offset const uint64_t counter = offset / 64; uint8_t counter8[8]; store_le(counter, counter8); m_state[8] = load_le(counter8, 0); m_state[9] += load_le(counter8, 1); salsa_core(m_buffer.data(), m_state.data(), 20); ++m_state[8]; m_state[9] += (m_state[8] == 0); m_position = offset % 64; } } /** * (C) 2018 Jack Lloyd * (C) 2018 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string Scrypt_Family::name() const { return "Scrypt"; } std::unique_ptr Scrypt_Family::default_params() const { return std::unique_ptr(new Scrypt(32768, 8, 1)); } std::unique_ptr Scrypt_Family::tune(size_t output_length, std::chrono::milliseconds msec, size_t max_memory_usage_mb) const { BOTAN_UNUSED(output_length); /* * Some rough relations between scrypt parameters and runtime. * Denote here by stime(N,r,p) the msec it takes to run scrypt. * * Emperically for smaller sizes: * stime(N,8*r,p) / stime(N,r,p) is ~ 6-7 * stime(N,r,8*p) / stime(N,r,8*p) is ~ 7 * stime(2*N,r,p) / stime(N,r,p) is ~ 2 * * Compute stime(8192,1,1) as baseline and extrapolate */ const size_t max_memory_usage = max_memory_usage_mb * 1024 * 1024; // Starting parameters size_t N = 8192; size_t r = 1; size_t p = 1; Timer timer("Scrypt"); const auto tune_time = BOTAN_PBKDF_TUNING_TIME; timer.run_until_elapsed(tune_time, [&]() { uint8_t output[32] = { 0 }; scrypt(output, sizeof(output), "test", 4, nullptr, 0, N, r, p); }); // No timer events seems strange, perhaps something is wrong - give // up on this and just return default params if(timer.events() == 0) return default_params(); // nsec per eval of scrypt with initial params const uint64_t measured_time = timer.value() / timer.events(); const uint64_t target_nsec = msec.count() * static_cast(1000000); uint64_t est_nsec = measured_time; // First move increase r by 8x if possible if(max_memory_usage == 0 || scrypt_memory_usage(N, r, p)*8 < max_memory_usage) { if(target_nsec / est_nsec >= 5) { r *= 8; est_nsec *= 5; } } // Now double N as many times as we can while(max_memory_usage == 0 || scrypt_memory_usage(N, r, p)*2 < max_memory_usage) { if(target_nsec / est_nsec >= 2) { N *= 2; est_nsec *= 2; } else break; } // If we have extra runtime budget, increment p if(target_nsec / est_nsec > 2) p *= std::min(1024, static_cast(target_nsec / est_nsec)); return std::unique_ptr(new Scrypt(N, r, p)); } std::unique_ptr Scrypt_Family::from_params(size_t N, size_t r, size_t p) const { return std::unique_ptr(new Scrypt(N, r, p)); } std::unique_ptr Scrypt_Family::from_iterations(size_t iter) const { const size_t r = 8; const size_t p = 1; size_t N = 8192; if(iter > 50000) N = 16384; if(iter > 100000) N = 32768; if(iter > 150000) N = 65536; return std::unique_ptr(new Scrypt(N, r, p)); } Scrypt::Scrypt(size_t N, size_t r, size_t p) : m_N(N), m_r(r), m_p(p) { if(!is_power_of_2(N)) throw Invalid_Argument("Scrypt N parameter must be a power of 2"); if(p == 0 || p > 1024) throw Invalid_Argument("Invalid or unsupported scrypt p"); if(r == 0 || r > 256) throw Invalid_Argument("Invalid or unsupported scrypt r"); if(N < 1 || N > 4194304) throw Invalid_Argument("Invalid or unsupported scrypt N"); } std::string Scrypt::to_string() const { std::ostringstream oss; oss << "Scrypt(" << m_N << "," << m_r << "," << m_p << ")"; return oss.str(); } size_t Scrypt::total_memory_usage() const { return scrypt_memory_usage(m_N, m_r, m_p); } void Scrypt::derive_key(uint8_t output[], size_t output_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) const { scrypt(output, output_len, password, password_len, salt, salt_len, N(), r(), p()); } namespace { void scryptBlockMix(size_t r, uint8_t* B, uint8_t* Y) { uint32_t B32[16]; secure_vector X(64); copy_mem(X.data(), &B[(2*r-1)*64], 64); for(size_t i = 0; i != 2*r; i++) { xor_buf(X.data(), &B[64*i], 64); load_le(B32, X.data(), 16); Salsa20::salsa_core(X.data(), B32, 8); copy_mem(&Y[64*i], X.data(), 64); } for(size_t i = 0; i < r; ++i) { copy_mem(&B[i*64], &Y[(i * 2) * 64], 64); } for(size_t i = 0; i < r; ++i) { copy_mem(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64); } } void scryptROMmix(size_t r, size_t N, uint8_t* B, secure_vector& V) { const size_t S = 128 * r; for(size_t i = 0; i != N; ++i) { copy_mem(&V[S*i], B, S); scryptBlockMix(r, B, &V[N*S]); } for(size_t i = 0; i != N; ++i) { // compiler doesn't know here that N is power of 2 const size_t j = load_le(&B[(2*r-1)*64], 0) & (N - 1); xor_buf(B, &V[j*S], S); scryptBlockMix(r, B, &V[N*S]); } } } void scrypt(uint8_t output[], size_t output_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len, size_t N, size_t r, size_t p) { const size_t S = 128 * r; secure_vector B(p * S); // temp space secure_vector V((N+1) * S); auto hmac_sha256 = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); try { hmac_sha256->set_key(cast_char_ptr_to_uint8(password), password_len); } catch(Invalid_Key_Length&) { throw Invalid_Argument("Scrypt cannot accept passphrases of the provided length"); } pbkdf2(*hmac_sha256.get(), B.data(), B.size(), salt, salt_len, 1); // these can be parallel for(size_t i = 0; i != p; ++i) { scryptROMmix(r, N, &B[128*r*i], V); } pbkdf2(*hmac_sha256.get(), output, output_len, B.data(), B.size(), 1); } } /* * SEED * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { alignas(64) const uint32_t SEED_S0[256] = { 0x2989A1A8, 0x05858184, 0x16C6D2D4, 0x13C3D3D0, 0x14445054, 0x1D0D111C, 0x2C8CA0AC, 0x25052124, 0x1D4D515C, 0x03434340, 0x18081018, 0x1E0E121C, 0x11415150, 0x3CCCF0FC, 0x0ACAC2C8, 0x23436360, 0x28082028, 0x04444044, 0x20002020, 0x1D8D919C, 0x20C0E0E0, 0x22C2E2E0, 0x08C8C0C8, 0x17071314, 0x2585A1A4, 0x0F8F838C, 0x03030300, 0x3B4B7378, 0x3B8BB3B8, 0x13031310, 0x12C2D2D0, 0x2ECEE2EC, 0x30407070, 0x0C8C808C, 0x3F0F333C, 0x2888A0A8, 0x32023230, 0x1DCDD1DC, 0x36C6F2F4, 0x34447074, 0x2CCCE0EC, 0x15859194, 0x0B0B0308, 0x17475354, 0x1C4C505C, 0x1B4B5358, 0x3D8DB1BC, 0x01010100, 0x24042024, 0x1C0C101C, 0x33437370, 0x18889098, 0x10001010, 0x0CCCC0CC, 0x32C2F2F0, 0x19C9D1D8, 0x2C0C202C, 0x27C7E3E4, 0x32427270, 0x03838380, 0x1B8B9398, 0x11C1D1D0, 0x06868284, 0x09C9C1C8, 0x20406060, 0x10405050, 0x2383A3A0, 0x2BCBE3E8, 0x0D0D010C, 0x3686B2B4, 0x1E8E929C, 0x0F4F434C, 0x3787B3B4, 0x1A4A5258, 0x06C6C2C4, 0x38487078, 0x2686A2A4, 0x12021210, 0x2F8FA3AC, 0x15C5D1D4, 0x21416160, 0x03C3C3C0, 0x3484B0B4, 0x01414140, 0x12425250, 0x3D4D717C, 0x0D8D818C, 0x08080008, 0x1F0F131C, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37C7F3F4, 0x21C1E1E0, 0x3DCDF1FC, 0x36467274, 0x2F0F232C, 0x27072324, 0x3080B0B0, 0x0B8B8388, 0x0E0E020C, 0x2B8BA3A8, 0x2282A2A0, 0x2E4E626C, 0x13839390, 0x0D4D414C, 0x29496168, 0x3C4C707C, 0x09090108, 0x0A0A0208, 0x3F8FB3BC, 0x2FCFE3EC, 0x33C3F3F0, 0x05C5C1C4, 0x07878384, 0x14041014, 0x3ECEF2FC, 0x24446064, 0x1ECED2DC, 0x2E0E222C, 0x0B4B4348, 0x1A0A1218, 0x06060204, 0x21012120, 0x2B4B6368, 0x26466264, 0x02020200, 0x35C5F1F4, 0x12829290, 0x0A8A8288, 0x0C0C000C, 0x3383B3B0, 0x3E4E727C, 0x10C0D0D0, 0x3A4A7278, 0x07474344, 0x16869294, 0x25C5E1E4, 0x26062224, 0x00808080, 0x2D8DA1AC, 0x1FCFD3DC, 0x2181A1A0, 0x30003030, 0x37073334, 0x2E8EA2AC, 0x36063234, 0x15051114, 0x22022220, 0x38083038, 0x34C4F0F4, 0x2787A3A4, 0x05454144, 0x0C4C404C, 0x01818180, 0x29C9E1E8, 0x04848084, 0x17879394, 0x35053134, 0x0BCBC3C8, 0x0ECEC2CC, 0x3C0C303C, 0x31417170, 0x11011110, 0x07C7C3C4, 0x09898188, 0x35457174, 0x3BCBF3F8, 0x1ACAD2D8, 0x38C8F0F8, 0x14849094, 0x19495158, 0x02828280, 0x04C4C0C4, 0x3FCFF3FC, 0x09494148, 0x39093138, 0x27476364, 0x00C0C0C0, 0x0FCFC3CC, 0x17C7D3D4, 0x3888B0B8, 0x0F0F030C, 0x0E8E828C, 0x02424240, 0x23032320, 0x11819190, 0x2C4C606C, 0x1BCBD3D8, 0x2484A0A4, 0x34043034, 0x31C1F1F0, 0x08484048, 0x02C2C2C0, 0x2F4F636C, 0x3D0D313C, 0x2D0D212C, 0x00404040, 0x3E8EB2BC, 0x3E0E323C, 0x3C8CB0BC, 0x01C1C1C0, 0x2A8AA2A8, 0x3A8AB2B8, 0x0E4E424C, 0x15455154, 0x3B0B3338, 0x1CCCD0DC, 0x28486068, 0x3F4F737C, 0x1C8C909C, 0x18C8D0D8, 0x0A4A4248, 0x16465254, 0x37477374, 0x2080A0A0, 0x2DCDE1EC, 0x06464244, 0x3585B1B4, 0x2B0B2328, 0x25456164, 0x3ACAF2F8, 0x23C3E3E0, 0x3989B1B8, 0x3181B1B0, 0x1F8F939C, 0x1E4E525C, 0x39C9F1F8, 0x26C6E2E4, 0x3282B2B0, 0x31013130, 0x2ACAE2E8, 0x2D4D616C, 0x1F4F535C, 0x24C4E0E4, 0x30C0F0F0, 0x0DCDC1CC, 0x08888088, 0x16061214, 0x3A0A3238, 0x18485058, 0x14C4D0D4, 0x22426260, 0x29092128, 0x07070304, 0x33033330, 0x28C8E0E8, 0x1B0B1318, 0x05050104, 0x39497178, 0x10809090, 0x2A4A6268, 0x2A0A2228, 0x1A8A9298 }; alignas(64) const uint32_t SEED_S1[256] = { 0x38380830, 0xE828C8E0, 0x2C2D0D21, 0xA42686A2, 0xCC0FCFC3, 0xDC1ECED2, 0xB03383B3, 0xB83888B0, 0xAC2F8FA3, 0x60204060, 0x54154551, 0xC407C7C3, 0x44044440, 0x6C2F4F63, 0x682B4B63, 0x581B4B53, 0xC003C3C3, 0x60224262, 0x30330333, 0xB43585B1, 0x28290921, 0xA02080A0, 0xE022C2E2, 0xA42787A3, 0xD013C3D3, 0x90118191, 0x10110111, 0x04060602, 0x1C1C0C10, 0xBC3C8CB0, 0x34360632, 0x480B4B43, 0xEC2FCFE3, 0x88088880, 0x6C2C4C60, 0xA82888A0, 0x14170713, 0xC404C4C0, 0x14160612, 0xF434C4F0, 0xC002C2C2, 0x44054541, 0xE021C1E1, 0xD416C6D2, 0x3C3F0F33, 0x3C3D0D31, 0x8C0E8E82, 0x98188890, 0x28280820, 0x4C0E4E42, 0xF436C6F2, 0x3C3E0E32, 0xA42585A1, 0xF839C9F1, 0x0C0D0D01, 0xDC1FCFD3, 0xD818C8D0, 0x282B0B23, 0x64264662, 0x783A4A72, 0x24270723, 0x2C2F0F23, 0xF031C1F1, 0x70324272, 0x40024242, 0xD414C4D0, 0x40014141, 0xC000C0C0, 0x70334373, 0x64274763, 0xAC2C8CA0, 0x880B8B83, 0xF437C7F3, 0xAC2D8DA1, 0x80008080, 0x1C1F0F13, 0xC80ACAC2, 0x2C2C0C20, 0xA82A8AA2, 0x34340430, 0xD012C2D2, 0x080B0B03, 0xEC2ECEE2, 0xE829C9E1, 0x5C1D4D51, 0x94148490, 0x18180810, 0xF838C8F0, 0x54174753, 0xAC2E8EA2, 0x08080800, 0xC405C5C1, 0x10130313, 0xCC0DCDC1, 0x84068682, 0xB83989B1, 0xFC3FCFF3, 0x7C3D4D71, 0xC001C1C1, 0x30310131, 0xF435C5F1, 0x880A8A82, 0x682A4A62, 0xB03181B1, 0xD011C1D1, 0x20200020, 0xD417C7D3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171, 0x04070703, 0xD81BCBD3, 0x9C1D8D91, 0x98198991, 0x60214161, 0xBC3E8EB2, 0xE426C6E2, 0x58194951, 0xDC1DCDD1, 0x50114151, 0x90108090, 0xDC1CCCD0, 0x981A8A92, 0xA02383A3, 0xA82B8BA3, 0xD010C0D0, 0x80018181, 0x0C0F0F03, 0x44074743, 0x181A0A12, 0xE023C3E3, 0xEC2CCCE0, 0x8C0D8D81, 0xBC3F8FB3, 0x94168692, 0x783B4B73, 0x5C1C4C50, 0xA02282A2, 0xA02181A1, 0x60234363, 0x20230323, 0x4C0D4D41, 0xC808C8C0, 0x9C1E8E92, 0x9C1C8C90, 0x383A0A32, 0x0C0C0C00, 0x2C2E0E22, 0xB83A8AB2, 0x6C2E4E62, 0x9C1F8F93, 0x581A4A52, 0xF032C2F2, 0x90128292, 0xF033C3F3, 0x48094941, 0x78384870, 0xCC0CCCC0, 0x14150511, 0xF83BCBF3, 0x70304070, 0x74354571, 0x7C3F4F73, 0x34350531, 0x10100010, 0x00030303, 0x64244460, 0x6C2D4D61, 0xC406C6C2, 0x74344470, 0xD415C5D1, 0xB43484B0, 0xE82ACAE2, 0x08090901, 0x74364672, 0x18190911, 0xFC3ECEF2, 0x40004040, 0x10120212, 0xE020C0E0, 0xBC3D8DB1, 0x04050501, 0xF83ACAF2, 0x00010101, 0xF030C0F0, 0x282A0A22, 0x5C1E4E52, 0xA82989A1, 0x54164652, 0x40034343, 0x84058581, 0x14140410, 0x88098981, 0x981B8B93, 0xB03080B0, 0xE425C5E1, 0x48084840, 0x78394971, 0x94178793, 0xFC3CCCF0, 0x1C1E0E12, 0x80028282, 0x20210121, 0x8C0C8C80, 0x181B0B13, 0x5C1F4F53, 0x74374773, 0x54144450, 0xB03282B2, 0x1C1D0D11, 0x24250521, 0x4C0F4F43, 0x00000000, 0x44064642, 0xEC2DCDE1, 0x58184850, 0x50124252, 0xE82BCBE3, 0x7C3E4E72, 0xD81ACAD2, 0xC809C9C1, 0xFC3DCDF1, 0x30300030, 0x94158591, 0x64254561, 0x3C3C0C30, 0xB43686B2, 0xE424C4E0, 0xB83B8BB3, 0x7C3C4C70, 0x0C0E0E02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393, 0x34370733, 0xE427C7E3, 0x24240420, 0xA42484A0, 0xC80BCBC3, 0x50134353, 0x080A0A02, 0x84078783, 0xD819C9D1, 0x4C0C4C40, 0x80038383, 0x8C0F8F83, 0xCC0ECEC2, 0x383B0B33, 0x480A4A42, 0xB43787B3 }; alignas(64) const uint32_t SEED_S2[256] = { 0xA1A82989, 0x81840585, 0xD2D416C6, 0xD3D013C3, 0x50541444, 0x111C1D0D, 0xA0AC2C8C, 0x21242505, 0x515C1D4D, 0x43400343, 0x10181808, 0x121C1E0E, 0x51501141, 0xF0FC3CCC, 0xC2C80ACA, 0x63602343, 0x20282808, 0x40440444, 0x20202000, 0x919C1D8D, 0xE0E020C0, 0xE2E022C2, 0xC0C808C8, 0x13141707, 0xA1A42585, 0x838C0F8F, 0x03000303, 0x73783B4B, 0xB3B83B8B, 0x13101303, 0xD2D012C2, 0xE2EC2ECE, 0x70703040, 0x808C0C8C, 0x333C3F0F, 0xA0A82888, 0x32303202, 0xD1DC1DCD, 0xF2F436C6, 0x70743444, 0xE0EC2CCC, 0x91941585, 0x03080B0B, 0x53541747, 0x505C1C4C, 0x53581B4B, 0xB1BC3D8D, 0x01000101, 0x20242404, 0x101C1C0C, 0x73703343, 0x90981888, 0x10101000, 0xC0CC0CCC, 0xF2F032C2, 0xD1D819C9, 0x202C2C0C, 0xE3E427C7, 0x72703242, 0x83800383, 0x93981B8B, 0xD1D011C1, 0x82840686, 0xC1C809C9, 0x60602040, 0x50501040, 0xA3A02383, 0xE3E82BCB, 0x010C0D0D, 0xB2B43686, 0x929C1E8E, 0x434C0F4F, 0xB3B43787, 0x52581A4A, 0xC2C406C6, 0x70783848, 0xA2A42686, 0x12101202, 0xA3AC2F8F, 0xD1D415C5, 0x61602141, 0xC3C003C3, 0xB0B43484, 0x41400141, 0x52501242, 0x717C3D4D, 0x818C0D8D, 0x00080808, 0x131C1F0F, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xF3F437C7, 0xE1E021C1, 0xF1FC3DCD, 0x72743646, 0x232C2F0F, 0x23242707, 0xB0B03080, 0x83880B8B, 0x020C0E0E, 0xA3A82B8B, 0xA2A02282, 0x626C2E4E, 0x93901383, 0x414C0D4D, 0x61682949, 0x707C3C4C, 0x01080909, 0x02080A0A, 0xB3BC3F8F, 0xE3EC2FCF, 0xF3F033C3, 0xC1C405C5, 0x83840787, 0x10141404, 0xF2FC3ECE, 0x60642444, 0xD2DC1ECE, 0x222C2E0E, 0x43480B4B, 0x12181A0A, 0x02040606, 0x21202101, 0x63682B4B, 0x62642646, 0x02000202, 0xF1F435C5, 0x92901282, 0x82880A8A, 0x000C0C0C, 0xB3B03383, 0x727C3E4E, 0xD0D010C0, 0x72783A4A, 0x43440747, 0x92941686, 0xE1E425C5, 0x22242606, 0x80800080, 0xA1AC2D8D, 0xD3DC1FCF, 0xA1A02181, 0x30303000, 0x33343707, 0xA2AC2E8E, 0x32343606, 0x11141505, 0x22202202, 0x30383808, 0xF0F434C4, 0xA3A42787, 0x41440545, 0x404C0C4C, 0x81800181, 0xE1E829C9, 0x80840484, 0x93941787, 0x31343505, 0xC3C80BCB, 0xC2CC0ECE, 0x303C3C0C, 0x71703141, 0x11101101, 0xC3C407C7, 0x81880989, 0x71743545, 0xF3F83BCB, 0xD2D81ACA, 0xF0F838C8, 0x90941484, 0x51581949, 0x82800282, 0xC0C404C4, 0xF3FC3FCF, 0x41480949, 0x31383909, 0x63642747, 0xC0C000C0, 0xC3CC0FCF, 0xD3D417C7, 0xB0B83888, 0x030C0F0F, 0x828C0E8E, 0x42400242, 0x23202303, 0x91901181, 0x606C2C4C, 0xD3D81BCB, 0xA0A42484, 0x30343404, 0xF1F031C1, 0x40480848, 0xC2C002C2, 0x636C2F4F, 0x313C3D0D, 0x212C2D0D, 0x40400040, 0xB2BC3E8E, 0x323C3E0E, 0xB0BC3C8C, 0xC1C001C1, 0xA2A82A8A, 0xB2B83A8A, 0x424C0E4E, 0x51541545, 0x33383B0B, 0xD0DC1CCC, 0x60682848, 0x737C3F4F, 0x909C1C8C, 0xD0D818C8, 0x42480A4A, 0x52541646, 0x73743747, 0xA0A02080, 0xE1EC2DCD, 0x42440646, 0xB1B43585, 0x23282B0B, 0x61642545, 0xF2F83ACA, 0xE3E023C3, 0xB1B83989, 0xB1B03181, 0x939C1F8F, 0x525C1E4E, 0xF1F839C9, 0xE2E426C6, 0xB2B03282, 0x31303101, 0xE2E82ACA, 0x616C2D4D, 0x535C1F4F, 0xE0E424C4, 0xF0F030C0, 0xC1CC0DCD, 0x80880888, 0x12141606, 0x32383A0A, 0x50581848, 0xD0D414C4, 0x62602242, 0x21282909, 0x03040707, 0x33303303, 0xE0E828C8, 0x13181B0B, 0x01040505, 0x71783949, 0x90901080, 0x62682A4A, 0x22282A0A, 0x92981A8A }; alignas(64) const uint32_t SEED_S3[256] = { 0x08303838, 0xC8E0E828, 0x0D212C2D, 0x86A2A426, 0xCFC3CC0F, 0xCED2DC1E, 0x83B3B033, 0x88B0B838, 0x8FA3AC2F, 0x40606020, 0x45515415, 0xC7C3C407, 0x44404404, 0x4F636C2F, 0x4B63682B, 0x4B53581B, 0xC3C3C003, 0x42626022, 0x03333033, 0x85B1B435, 0x09212829, 0x80A0A020, 0xC2E2E022, 0x87A3A427, 0xC3D3D013, 0x81919011, 0x01111011, 0x06020406, 0x0C101C1C, 0x8CB0BC3C, 0x06323436, 0x4B43480B, 0xCFE3EC2F, 0x88808808, 0x4C606C2C, 0x88A0A828, 0x07131417, 0xC4C0C404, 0x06121416, 0xC4F0F434, 0xC2C2C002, 0x45414405, 0xC1E1E021, 0xC6D2D416, 0x0F333C3F, 0x0D313C3D, 0x8E828C0E, 0x88909818, 0x08202828, 0x4E424C0E, 0xC6F2F436, 0x0E323C3E, 0x85A1A425, 0xC9F1F839, 0x0D010C0D, 0xCFD3DC1F, 0xC8D0D818, 0x0B23282B, 0x46626426, 0x4A72783A, 0x07232427, 0x0F232C2F, 0xC1F1F031, 0x42727032, 0x42424002, 0xC4D0D414, 0x41414001, 0xC0C0C000, 0x43737033, 0x47636427, 0x8CA0AC2C, 0x8B83880B, 0xC7F3F437, 0x8DA1AC2D, 0x80808000, 0x0F131C1F, 0xCAC2C80A, 0x0C202C2C, 0x8AA2A82A, 0x04303434, 0xC2D2D012, 0x0B03080B, 0xCEE2EC2E, 0xC9E1E829, 0x4D515C1D, 0x84909414, 0x08101818, 0xC8F0F838, 0x47535417, 0x8EA2AC2E, 0x08000808, 0xC5C1C405, 0x03131013, 0xCDC1CC0D, 0x86828406, 0x89B1B839, 0xCFF3FC3F, 0x4D717C3D, 0xC1C1C001, 0x01313031, 0xC5F1F435, 0x8A82880A, 0x4A62682A, 0x81B1B031, 0xC1D1D011, 0x00202020, 0xC7D3D417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031, 0x07030407, 0xCBD3D81B, 0x8D919C1D, 0x89919819, 0x41616021, 0x8EB2BC3E, 0xC6E2E426, 0x49515819, 0xCDD1DC1D, 0x41515011, 0x80909010, 0xCCD0DC1C, 0x8A92981A, 0x83A3A023, 0x8BA3A82B, 0xC0D0D010, 0x81818001, 0x0F030C0F, 0x47434407, 0x0A12181A, 0xC3E3E023, 0xCCE0EC2C, 0x8D818C0D, 0x8FB3BC3F, 0x86929416, 0x4B73783B, 0x4C505C1C, 0x82A2A022, 0x81A1A021, 0x43636023, 0x03232023, 0x4D414C0D, 0xC8C0C808, 0x8E929C1E, 0x8C909C1C, 0x0A32383A, 0x0C000C0C, 0x0E222C2E, 0x8AB2B83A, 0x4E626C2E, 0x8F939C1F, 0x4A52581A, 0xC2F2F032, 0x82929012, 0xC3F3F033, 0x49414809, 0x48707838, 0xCCC0CC0C, 0x05111415, 0xCBF3F83B, 0x40707030, 0x45717435, 0x4F737C3F, 0x05313435, 0x00101010, 0x03030003, 0x44606424, 0x4D616C2D, 0xC6C2C406, 0x44707434, 0xC5D1D415, 0x84B0B434, 0xCAE2E82A, 0x09010809, 0x46727436, 0x09111819, 0xCEF2FC3E, 0x40404000, 0x02121012, 0xC0E0E020, 0x8DB1BC3D, 0x05010405, 0xCAF2F83A, 0x01010001, 0xC0F0F030, 0x0A22282A, 0x4E525C1E, 0x89A1A829, 0x46525416, 0x43434003, 0x85818405, 0x04101414, 0x89818809, 0x8B93981B, 0x80B0B030, 0xC5E1E425, 0x48404808, 0x49717839, 0x87939417, 0xCCF0FC3C, 0x0E121C1E, 0x82828002, 0x01212021, 0x8C808C0C, 0x0B13181B, 0x4F535C1F, 0x47737437, 0x44505414, 0x82B2B032, 0x0D111C1D, 0x05212425, 0x4F434C0F, 0x00000000, 0x46424406, 0xCDE1EC2D, 0x48505818, 0x42525012, 0xCBE3E82B, 0x4E727C3E, 0xCAD2D81A, 0xC9C1C809, 0xCDF1FC3D, 0x00303030, 0x85919415, 0x45616425, 0x0C303C3C, 0x86B2B436, 0xC4E0E424, 0x8BB3B83B, 0x4C707C3C, 0x0E020C0E, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013, 0x07333437, 0xC7E3E427, 0x04202424, 0x84A0A424, 0xCBC3C80B, 0x43535013, 0x0A02080A, 0x87838407, 0xC9D1D819, 0x4C404C0C, 0x83838003, 0x8F838C0F, 0xCEC2CC0E, 0x0B33383B, 0x4A42480A, 0x87B3B437 }; /* * SEED G Function */ inline uint32_t SEED_G(uint32_t X) { return (SEED_S0[get_byte(3, X)] ^ SEED_S1[get_byte(2, X)] ^ SEED_S2[get_byte(1, X)] ^ SEED_S3[get_byte(0, X)]); } } /* * SEED Encryption */ void SEED::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_K.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be(in, 0); uint32_t B1 = load_be(in, 1); uint32_t B2 = load_be(in, 2); uint32_t B3 = load_be(in, 3); for(size_t j = 0; j != 16; j += 2) { uint32_t T0, T1; T0 = B2 ^ m_K[2*j]; T1 = SEED_G(B2 ^ B3 ^ m_K[2*j+1]); T0 = SEED_G(T1 + T0); T1 = SEED_G(T1 + T0); B1 ^= T1; B0 ^= T0 + T1; T0 = B0 ^ m_K[2*j+2]; T1 = SEED_G(B0 ^ B1 ^ m_K[2*j+3]); T0 = SEED_G(T1 + T0); T1 = SEED_G(T1 + T0); B3 ^= T1; B2 ^= T0 + T1; } store_be(out, B2, B3, B0, B1); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * SEED Decryption */ void SEED::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_K.empty() == false); for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be(in, 0); uint32_t B1 = load_be(in, 1); uint32_t B2 = load_be(in, 2); uint32_t B3 = load_be(in, 3); for(size_t j = 0; j != 16; j += 2) { uint32_t T0, T1; T0 = B2 ^ m_K[30-2*j]; T1 = SEED_G(B2 ^ B3 ^ m_K[31-2*j]); T0 = SEED_G(T1 + T0); T1 = SEED_G(T1 + T0); B1 ^= T1; B0 ^= T0 + T1; T0 = B0 ^ m_K[28-2*j]; T1 = SEED_G(B0 ^ B1 ^ m_K[29-2*j]); T0 = SEED_G(T1 + T0); T1 = SEED_G(T1 + T0); B3 ^= T1; B2 ^= T0 + T1; } store_be(out, B2, B3, B0, B1); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * SEED Key Schedule */ void SEED::key_schedule(const uint8_t key[], size_t) { const uint32_t RC[16] = { 0x9E3779B9, 0x3C6EF373, 0x78DDE6E6, 0xF1BBCDCC, 0xE3779B99, 0xC6EF3733, 0x8DDE6E67, 0x1BBCDCCF, 0x3779B99E, 0x6EF3733C, 0xDDE6E678, 0xBBCDCCF1, 0x779B99E3, 0xEF3733C6, 0xDE6E678D, 0xBCDCCF1B }; secure_vector WK(4); for(size_t i = 0; i != 4; ++i) WK[i] = load_be(key, i); m_K.resize(32); for(size_t i = 0; i != 16; i += 2) { m_K[2*i ] = SEED_G(WK[0] + WK[2] - RC[i]); m_K[2*i+1] = SEED_G(WK[1] - WK[3] + RC[i]) ^ m_K[2*i]; uint32_t T = (WK[0] & 0xFF) << 24; WK[0] = (WK[0] >> 8) | (get_byte(3, WK[1]) << 24); WK[1] = (WK[1] >> 8) | T; m_K[2*i+2] = SEED_G(WK[0] + WK[2] - RC[i+1]); m_K[2*i+3] = SEED_G(WK[1] - WK[3] + RC[i+1]) ^ m_K[2*i+2]; T = get_byte(0, WK[3]); WK[3] = (WK[3] << 8) | get_byte(0, WK[2]); WK[2] = (WK[2] << 8) | T; } } void SEED::clear() { zap(m_K); } } /* * Serpent * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_SERPENT_SIMD) || defined(BOTAN_HAS_SERPENT_AVX2) #endif namespace Botan { namespace { /* * Serpent's Linear Transform */ inline void transform(uint32_t& B0, uint32_t& B1, uint32_t& B2, uint32_t& B3) { B0 = rotl<13>(B0); B2 = rotl<3>(B2); B1 ^= B0 ^ B2; B3 ^= B2 ^ (B0 << 3); B1 = rotl<1>(B1); B3 = rotl<7>(B3); B0 ^= B1 ^ B3; B2 ^= B3 ^ (B1 << 7); B0 = rotl<5>(B0); B2 = rotl<22>(B2); } /* * Serpent's Inverse Linear Transform */ inline void i_transform(uint32_t& B0, uint32_t& B1, uint32_t& B2, uint32_t& B3) { B2 = rotr<22>(B2); B0 = rotr<5>(B0); B2 ^= B3 ^ (B1 << 7); B0 ^= B1 ^ B3; B3 = rotr<7>(B3); B1 = rotr<1>(B1); B3 ^= B2 ^ (B0 << 3); B1 ^= B0 ^ B2; B2 = rotr<3>(B2); B0 = rotr<13>(B0); } } /* * XOR a key block with a data block */ #define key_xor(round, B0, B1, B2, B3) \ B0 ^= m_round_key[4*round ]; \ B1 ^= m_round_key[4*round+1]; \ B2 ^= m_round_key[4*round+2]; \ B3 ^= m_round_key[4*round+3]; /* * Serpent Encryption */ void Serpent::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_round_key.empty() == false); #if defined(BOTAN_HAS_SERPENT_AVX2) if(CPUID::has_avx2()) { while(blocks >= 8) { avx2_encrypt_8(in, out); in += 8 * BLOCK_SIZE; out += 8 * BLOCK_SIZE; blocks -= 8; } } #endif #if defined(BOTAN_HAS_SERPENT_SIMD) if(CPUID::has_simd_32()) { while(blocks >= 4) { simd_encrypt_4(in, out); in += 4 * BLOCK_SIZE; out += 4 * BLOCK_SIZE; blocks -= 4; } } #endif BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) { uint32_t B0, B1, B2, B3; load_le(in + 16*i, B0, B1, B2, B3); key_xor( 0,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); store_le(out + 16*i, B0, B1, B2, B3); } } /* * Serpent Decryption */ void Serpent::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_round_key.empty() == false); #if defined(BOTAN_HAS_SERPENT_AVX2) if(CPUID::has_avx2()) { while(blocks >= 8) { avx2_decrypt_8(in, out); in += 8 * BLOCK_SIZE; out += 8 * BLOCK_SIZE; blocks -= 8; } } #endif #if defined(BOTAN_HAS_SERPENT_SIMD) if(CPUID::has_simd_32()) { while(blocks >= 4) { simd_decrypt_4(in, out); in += 4 * BLOCK_SIZE; out += 4 * BLOCK_SIZE; blocks -= 4; } } #endif BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) { uint32_t B0, B1, B2, B3; load_le(in + 16*i, B0, B1, B2, B3); key_xor(32,B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); store_le(out + 16*i, B0, B1, B2, B3); } } #undef key_xor #undef transform #undef i_transform /* * Serpent Key Schedule */ void Serpent::key_schedule(const uint8_t key[], size_t length) { const uint32_t PHI = 0x9E3779B9; secure_vector W(140); for(size_t i = 0; i != length / 4; ++i) W[i] = load_le(key, i); W[length / 4] |= uint32_t(1) << ((length%4)*8); for(size_t i = 8; i != 140; ++i) { uint32_t wi = W[i-8] ^ W[i-5] ^ W[i-3] ^ W[i-1] ^ PHI ^ uint32_t(i-8); W[i] = rotl<11>(wi); } SBoxE0(W[ 20],W[ 21],W[ 22],W[ 23]); SBoxE0(W[ 52],W[ 53],W[ 54],W[ 55]); SBoxE0(W[ 84],W[ 85],W[ 86],W[ 87]); SBoxE0(W[116],W[117],W[118],W[119]); SBoxE1(W[ 16],W[ 17],W[ 18],W[ 19]); SBoxE1(W[ 48],W[ 49],W[ 50],W[ 51]); SBoxE1(W[ 80],W[ 81],W[ 82],W[ 83]); SBoxE1(W[112],W[113],W[114],W[115]); SBoxE2(W[ 12],W[ 13],W[ 14],W[ 15]); SBoxE2(W[ 44],W[ 45],W[ 46],W[ 47]); SBoxE2(W[ 76],W[ 77],W[ 78],W[ 79]); SBoxE2(W[108],W[109],W[110],W[111]); SBoxE3(W[ 8],W[ 9],W[ 10],W[ 11]); SBoxE3(W[ 40],W[ 41],W[ 42],W[ 43]); SBoxE3(W[ 72],W[ 73],W[ 74],W[ 75]); SBoxE3(W[104],W[105],W[106],W[107]); SBoxE3(W[136],W[137],W[138],W[139]); SBoxE4(W[ 36],W[ 37],W[ 38],W[ 39]); SBoxE4(W[ 68],W[ 69],W[ 70],W[ 71]); SBoxE4(W[100],W[101],W[102],W[103]); SBoxE4(W[132],W[133],W[134],W[135]); SBoxE5(W[ 32],W[ 33],W[ 34],W[ 35]); SBoxE5(W[ 64],W[ 65],W[ 66],W[ 67]); SBoxE5(W[ 96],W[ 97],W[ 98],W[ 99]); SBoxE5(W[128],W[129],W[130],W[131]); SBoxE6(W[ 28],W[ 29],W[ 30],W[ 31]); SBoxE6(W[ 60],W[ 61],W[ 62],W[ 63]); SBoxE6(W[ 92],W[ 93],W[ 94],W[ 95]); SBoxE6(W[124],W[125],W[126],W[127]); SBoxE7(W[ 24],W[ 25],W[ 26],W[ 27]); SBoxE7(W[ 56],W[ 57],W[ 58],W[ 59]); SBoxE7(W[ 88],W[ 89],W[ 90],W[ 91]); SBoxE7(W[120],W[121],W[122],W[123]); m_round_key.assign(W.begin() + 8, W.end()); } void Serpent::clear() { zap(m_round_key); } std::string Serpent::provider() const { #if defined(BOTAN_HAS_SERPENT_AVX2) if(CPUID::has_avx2()) { return "avx2"; } #endif #if defined(BOTAN_HAS_SERPENT_SIMD) if(CPUID::has_simd_32()) { return "simd"; } #endif return "base"; } #undef key_xor } /* * Serpent (SIMD) * (C) 2009,2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { #define key_xor(round, B0, B1, B2, B3) \ do { \ B0 ^= SIMD_4x32::splat(m_round_key[4*round ]); \ B1 ^= SIMD_4x32::splat(m_round_key[4*round+1]); \ B2 ^= SIMD_4x32::splat(m_round_key[4*round+2]); \ B3 ^= SIMD_4x32::splat(m_round_key[4*round+3]); \ } while(0) /* * Serpent's linear transformations */ #define transform(B0, B1, B2, B3) \ do { \ B0 = B0.rotl<13>(); \ B2 = B2.rotl<3>(); \ B1 ^= B0 ^ B2; \ B3 ^= B2 ^ B0.shl<3>(); \ B1 = B1.rotl<1>(); \ B3 = B3.rotl<7>(); \ B0 ^= B1 ^ B3; \ B2 ^= B3 ^ B1.shl<7>(); \ B0 = B0.rotl<5>(); \ B2 = B2.rotl<22>(); \ } while(0) #define i_transform(B0, B1, B2, B3) \ do { \ B2 = B2.rotr<22>(); \ B0 = B0.rotr<5>(); \ B2 ^= B3 ^ B1.shl<7>(); \ B0 ^= B1 ^ B3; \ B3 = B3.rotr<7>(); \ B1 = B1.rotr<1>(); \ B3 ^= B2 ^ B0.shl<3>(); \ B1 ^= B0 ^ B2; \ B2 = B2.rotr<3>(); \ B0 = B0.rotr<13>(); \ } while(0) /* * SIMD Serpent Encryption of 4 blocks in parallel */ void Serpent::simd_encrypt_4(const uint8_t in[64], uint8_t out[64]) const { SIMD_4x32 B0 = SIMD_4x32::load_le(in); SIMD_4x32 B1 = SIMD_4x32::load_le(in + 16); SIMD_4x32 B2 = SIMD_4x32::load_le(in + 32); SIMD_4x32 B3 = SIMD_4x32::load_le(in + 48); SIMD_4x32::transpose(B0, B1, B2, B3); key_xor( 0,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); SIMD_4x32::transpose(B0, B1, B2, B3); B0.store_le(out); B1.store_le(out + 16); B2.store_le(out + 32); B3.store_le(out + 48); } /* * SIMD Serpent Decryption of 4 blocks in parallel */ void Serpent::simd_decrypt_4(const uint8_t in[64], uint8_t out[64]) const { SIMD_4x32 B0 = SIMD_4x32::load_le(in); SIMD_4x32 B1 = SIMD_4x32::load_le(in + 16); SIMD_4x32 B2 = SIMD_4x32::load_le(in + 32); SIMD_4x32 B3 = SIMD_4x32::load_le(in + 48); SIMD_4x32::transpose(B0, B1, B2, B3); key_xor(32,B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); SIMD_4x32::transpose(B0, B1, B2, B3); B0.store_le(out); B1.store_le(out + 16); B2.store_le(out + 32); B3.store_le(out + 48); } #undef key_xor #undef transform #undef i_transform } /* * SQL TLS Session Manager * (C) 2012,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { namespace TLS { Session_Manager_SQL::Session_Manager_SQL(std::shared_ptr db, const std::string& passphrase, RandomNumberGenerator& rng, size_t max_sessions, std::chrono::seconds session_lifetime) : m_db(db), m_rng(rng), m_max_sessions(max_sessions), m_session_lifetime(session_lifetime) { m_db->create_table( "create table if not exists tls_sessions " "(" "session_id TEXT PRIMARY KEY, " "session_start INTEGER, " "hostname TEXT, " "hostport INTEGER, " "session BLOB" ")"); m_db->create_table( "create table if not exists tls_sessions_metadata " "(" "passphrase_salt BLOB, " "passphrase_iterations INTEGER, " "passphrase_check INTEGER " ")"); const size_t salts = m_db->row_count("tls_sessions_metadata"); std::unique_ptr pbkdf(get_pbkdf("PBKDF2(SHA-512)")); if(salts == 1) { // existing db auto stmt = m_db->new_statement("select * from tls_sessions_metadata"); if(stmt->step()) { std::pair salt = stmt->get_blob(0); const size_t iterations = stmt->get_size_t(1); const size_t check_val_db = stmt->get_size_t(2); secure_vector x = pbkdf->pbkdf_iterations(32 + 2, passphrase, salt.first, salt.second, iterations); const size_t check_val_created = make_uint16(x[0], x[1]); m_session_key.assign(x.begin() + 2, x.end()); if(check_val_created != check_val_db) throw Invalid_Argument("Session database password not valid"); } } else { // maybe just zap the salts + sessions tables in this case? if(salts != 0) throw Internal_Error("Seemingly corrupted TLS session db, multiple salts found"); // new database case std::vector salt; rng.random_vec(salt, 16); size_t iterations = 0; secure_vector x = pbkdf->pbkdf_timed(32 + 2, passphrase, salt.data(), salt.size(), std::chrono::milliseconds(100), iterations); size_t check_val = make_uint16(x[0], x[1]); m_session_key.assign(x.begin() + 2, x.end()); auto stmt = m_db->new_statement("insert into tls_sessions_metadata values(?1, ?2, ?3)"); stmt->bind(1, salt); stmt->bind(2, iterations); stmt->bind(3, check_val); stmt->spin(); } } bool Session_Manager_SQL::load_from_session_id(const std::vector& session_id, Session& session) { auto stmt = m_db->new_statement("select session from tls_sessions where session_id = ?1"); stmt->bind(1, hex_encode(session_id)); while(stmt->step()) { std::pair blob = stmt->get_blob(0); try { session = Session::decrypt(blob.first, blob.second, m_session_key); return true; } catch(...) { } } return false; } bool Session_Manager_SQL::load_from_server_info(const Server_Information& server, Session& session) { auto stmt = m_db->new_statement("select session from tls_sessions" " where hostname = ?1 and hostport = ?2" " order by session_start desc"); stmt->bind(1, server.hostname()); stmt->bind(2, server.port()); while(stmt->step()) { std::pair blob = stmt->get_blob(0); try { session = Session::decrypt(blob.first, blob.second, m_session_key); return true; } catch(...) { } } return false; } void Session_Manager_SQL::remove_entry(const std::vector& session_id) { auto stmt = m_db->new_statement("delete from tls_sessions where session_id = ?1"); stmt->bind(1, hex_encode(session_id)); stmt->spin(); } size_t Session_Manager_SQL::remove_all() { auto stmt = m_db->new_statement("delete from tls_sessions"); return stmt->spin(); } void Session_Manager_SQL::save(const Session& session) { if(session.server_info().hostname().empty()) return; auto stmt = m_db->new_statement("insert or replace into tls_sessions" " values(?1, ?2, ?3, ?4, ?5)"); stmt->bind(1, hex_encode(session.session_id())); stmt->bind(2, session.start_time()); stmt->bind(3, session.server_info().hostname()); stmt->bind(4, session.server_info().port()); stmt->bind(5, session.encrypt(m_session_key, m_rng)); stmt->spin(); prune_session_cache(); } void Session_Manager_SQL::prune_session_cache() { // First expire old sessions auto remove_expired = m_db->new_statement("delete from tls_sessions where session_start <= ?1"); remove_expired->bind(1, std::chrono::system_clock::now() - m_session_lifetime); remove_expired->spin(); const size_t sessions = m_db->row_count("tls_sessions"); // Then if needed expire some more sessions at random if(sessions > m_max_sessions) { auto remove_some = m_db->new_statement("delete from tls_sessions where session_id in " "(select session_id from tls_sessions limit ?1)"); remove_some->bind(1, sessions - m_max_sessions); remove_some->spin(); } } } } /* * SHA-160 * (C) 1999-2008,2011 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr SHA_160::copy_state() const { return std::unique_ptr(new SHA_160(*this)); } namespace SHA1_F { namespace { /* * SHA-160 F1 Function */ inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotl<5>(A); B = rotl<30>(B); } /* * SHA-160 F2 Function */ inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotl<5>(A); B = rotl<30>(B); } /* * SHA-160 F3 Function */ inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotl<5>(A); B = rotl<30>(B); } /* * SHA-160 F4 Function */ inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotl<5>(A); B = rotl<30>(B); } } } /* * SHA-160 Compression Function */ void SHA_160::compress_n(const uint8_t input[], size_t blocks) { using namespace SHA1_F; #if defined(BOTAN_HAS_SHA1_X86_SHA_NI) if(CPUID::has_intel_sha()) { return sha1_compress_x86(m_digest, input, blocks); } #endif #if defined(BOTAN_HAS_SHA1_ARMV8) if(CPUID::has_arm_sha1()) { return sha1_armv8_compress_n(m_digest, input, blocks); } #endif #if defined(BOTAN_HAS_SHA1_SSE2) if(CPUID::has_sse2()) { return sse2_compress_n(m_digest, input, blocks); } #endif uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3], E = m_digest[4]; m_W.resize(80); for(size_t i = 0; i != blocks; ++i) { load_be(m_W.data(), input, 16); for(size_t j = 16; j != 80; j += 8) { m_W[j ] = rotl<1>(m_W[j-3] ^ m_W[j-8] ^ m_W[j-14] ^ m_W[j-16]); m_W[j+1] = rotl<1>(m_W[j-2] ^ m_W[j-7] ^ m_W[j-13] ^ m_W[j-15]); m_W[j+2] = rotl<1>(m_W[j-1] ^ m_W[j-6] ^ m_W[j-12] ^ m_W[j-14]); m_W[j+3] = rotl<1>(m_W[j ] ^ m_W[j-5] ^ m_W[j-11] ^ m_W[j-13]); m_W[j+4] = rotl<1>(m_W[j+1] ^ m_W[j-4] ^ m_W[j-10] ^ m_W[j-12]); m_W[j+5] = rotl<1>(m_W[j+2] ^ m_W[j-3] ^ m_W[j- 9] ^ m_W[j-11]); m_W[j+6] = rotl<1>(m_W[j+3] ^ m_W[j-2] ^ m_W[j- 8] ^ m_W[j-10]); m_W[j+7] = rotl<1>(m_W[j+4] ^ m_W[j-1] ^ m_W[j- 7] ^ m_W[j- 9]); } F1(A, B, C, D, E, m_W[ 0]); F1(E, A, B, C, D, m_W[ 1]); F1(D, E, A, B, C, m_W[ 2]); F1(C, D, E, A, B, m_W[ 3]); F1(B, C, D, E, A, m_W[ 4]); F1(A, B, C, D, E, m_W[ 5]); F1(E, A, B, C, D, m_W[ 6]); F1(D, E, A, B, C, m_W[ 7]); F1(C, D, E, A, B, m_W[ 8]); F1(B, C, D, E, A, m_W[ 9]); F1(A, B, C, D, E, m_W[10]); F1(E, A, B, C, D, m_W[11]); F1(D, E, A, B, C, m_W[12]); F1(C, D, E, A, B, m_W[13]); F1(B, C, D, E, A, m_W[14]); F1(A, B, C, D, E, m_W[15]); F1(E, A, B, C, D, m_W[16]); F1(D, E, A, B, C, m_W[17]); F1(C, D, E, A, B, m_W[18]); F1(B, C, D, E, A, m_W[19]); F2(A, B, C, D, E, m_W[20]); F2(E, A, B, C, D, m_W[21]); F2(D, E, A, B, C, m_W[22]); F2(C, D, E, A, B, m_W[23]); F2(B, C, D, E, A, m_W[24]); F2(A, B, C, D, E, m_W[25]); F2(E, A, B, C, D, m_W[26]); F2(D, E, A, B, C, m_W[27]); F2(C, D, E, A, B, m_W[28]); F2(B, C, D, E, A, m_W[29]); F2(A, B, C, D, E, m_W[30]); F2(E, A, B, C, D, m_W[31]); F2(D, E, A, B, C, m_W[32]); F2(C, D, E, A, B, m_W[33]); F2(B, C, D, E, A, m_W[34]); F2(A, B, C, D, E, m_W[35]); F2(E, A, B, C, D, m_W[36]); F2(D, E, A, B, C, m_W[37]); F2(C, D, E, A, B, m_W[38]); F2(B, C, D, E, A, m_W[39]); F3(A, B, C, D, E, m_W[40]); F3(E, A, B, C, D, m_W[41]); F3(D, E, A, B, C, m_W[42]); F3(C, D, E, A, B, m_W[43]); F3(B, C, D, E, A, m_W[44]); F3(A, B, C, D, E, m_W[45]); F3(E, A, B, C, D, m_W[46]); F3(D, E, A, B, C, m_W[47]); F3(C, D, E, A, B, m_W[48]); F3(B, C, D, E, A, m_W[49]); F3(A, B, C, D, E, m_W[50]); F3(E, A, B, C, D, m_W[51]); F3(D, E, A, B, C, m_W[52]); F3(C, D, E, A, B, m_W[53]); F3(B, C, D, E, A, m_W[54]); F3(A, B, C, D, E, m_W[55]); F3(E, A, B, C, D, m_W[56]); F3(D, E, A, B, C, m_W[57]); F3(C, D, E, A, B, m_W[58]); F3(B, C, D, E, A, m_W[59]); F4(A, B, C, D, E, m_W[60]); F4(E, A, B, C, D, m_W[61]); F4(D, E, A, B, C, m_W[62]); F4(C, D, E, A, B, m_W[63]); F4(B, C, D, E, A, m_W[64]); F4(A, B, C, D, E, m_W[65]); F4(E, A, B, C, D, m_W[66]); F4(D, E, A, B, C, m_W[67]); F4(C, D, E, A, B, m_W[68]); F4(B, C, D, E, A, m_W[69]); F4(A, B, C, D, E, m_W[70]); F4(E, A, B, C, D, m_W[71]); F4(D, E, A, B, C, m_W[72]); F4(C, D, E, A, B, m_W[73]); F4(B, C, D, E, A, m_W[74]); F4(A, B, C, D, E, m_W[75]); F4(E, A, B, C, D, m_W[76]); F4(D, E, A, B, C, m_W[77]); F4(C, D, E, A, B, m_W[78]); F4(B, C, D, E, A, m_W[79]); A = (m_digest[0] += A); B = (m_digest[1] += B); C = (m_digest[2] += C); D = (m_digest[3] += D); E = (m_digest[4] += E); input += hash_block_size(); } } /* * Copy out the digest */ void SHA_160::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void SHA_160::clear() { MDx_HashFunction::clear(); zeroise(m_W); m_digest[0] = 0x67452301; m_digest[1] = 0xEFCDAB89; m_digest[2] = 0x98BADCFE; m_digest[3] = 0x10325476; m_digest[4] = 0xC3D2E1F0; } } /* * SHA-1 using SSE2 * Based on public domain code by Dean Gaudet * (http://arctic.org/~dean/crypto/sha1.html) * (C) 2009-2011 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace SHA1_SSE2_F { namespace { /* * First 16 bytes just need byte swapping. Preparing just means * adding in the round constants. */ #define prep00_15(P, W) \ do { \ W = _mm_shufflehi_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ W = _mm_shufflelo_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ W = _mm_or_si128(_mm_slli_epi16(W, 8), \ _mm_srli_epi16(W, 8)); \ P.u128 = _mm_add_epi32(W, K00_19); \ } while(0) /* For each multiple of 4, t, we want to calculate this: W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); W[t+3] = rol(W[t] ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); we'll actually calculate this: W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); W[t+3] = rol( 0 ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); W[t+3] ^= rol(W[t+0], 1); the parameters are: W0 = &W[t-16]; W1 = &W[t-12]; W2 = &W[t- 8]; W3 = &W[t- 4]; and on output: prepared = W0 + K W0 = W[t]..W[t+3] */ /* note that there is a step here where i want to do a rol by 1, which * normally would look like this: * * r1 = psrld r0,$31 * r0 = pslld r0,$1 * r0 = por r0,r1 * * but instead i do this: * * r1 = pcmpltd r0,zero * r0 = paddd r0,r0 * r0 = psub r0,r1 * * because pcmpltd and paddd are available in both MMX units on * efficeon, pentium-m, and opteron but shifts are available in * only one unit. */ #define prep(prep, XW0, XW1, XW2, XW3, K) \ do { \ __m128i r0, r1, r2, r3; \ \ /* load W[t-4] 16-byte aligned, and shift */ \ r3 = _mm_srli_si128((XW3), 4); \ r0 = (XW0); \ /* get high 64-bits of XW0 into low 64-bits */ \ r1 = _mm_shuffle_epi32((XW0), _MM_SHUFFLE(1,0,3,2)); \ /* load high 64-bits of r1 */ \ r1 = _mm_unpacklo_epi64(r1, (XW1)); \ r2 = (XW2); \ \ r0 = _mm_xor_si128(r1, r0); \ r2 = _mm_xor_si128(r3, r2); \ r0 = _mm_xor_si128(r2, r0); \ /* unrotated W[t]..W[t+2] in r0 ... still need W[t+3] */ \ \ r2 = _mm_slli_si128(r0, 12); \ r1 = _mm_cmplt_epi32(r0, _mm_setzero_si128()); \ r0 = _mm_add_epi32(r0, r0); /* shift left by 1 */ \ r0 = _mm_sub_epi32(r0, r1); /* r0 has W[t]..W[t+2] */ \ \ r3 = _mm_srli_epi32(r2, 30); \ r2 = _mm_slli_epi32(r2, 2); \ \ r0 = _mm_xor_si128(r0, r3); \ r0 = _mm_xor_si128(r0, r2); /* r0 now has W[t+3] */ \ \ (XW0) = r0; \ (prep).u128 = _mm_add_epi32(r0, K); \ } while(0) /* * SHA-160 F1 Function */ inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += (D ^ (B & (C ^ D))) + msg + rotl<5>(A); B = rotl<30>(B); } /* * SHA-160 F2 Function */ inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += (B ^ C ^ D) + msg + rotl<5>(A); B = rotl<30>(B); } /* * SHA-160 F3 Function */ inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += ((B & C) | ((B | C) & D)) + msg + rotl<5>(A); B = rotl<30>(B); } /* * SHA-160 F4 Function */ inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) { E += (B ^ C ^ D) + msg + rotl<5>(A); B = rotl<30>(B); } } } /* * SHA-160 Compression Function using SSE for message expansion */ //static BOTAN_FUNC_ISA("sse2") void SHA_160::sse2_compress_n(secure_vector& digest, const uint8_t input[], size_t blocks) { using namespace SHA1_SSE2_F; const __m128i K00_19 = _mm_set1_epi32(0x5A827999); const __m128i K20_39 = _mm_set1_epi32(0x6ED9EBA1); const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC); const __m128i K60_79 = _mm_set1_epi32(0xCA62C1D6); uint32_t A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4]; const __m128i* input_mm = reinterpret_cast(input); for(size_t i = 0; i != blocks; ++i) { union v4si { uint32_t u32[4]; __m128i u128; }; v4si P0, P1, P2, P3; __m128i W0 = _mm_loadu_si128(&input_mm[0]); prep00_15(P0, W0); __m128i W1 = _mm_loadu_si128(&input_mm[1]); prep00_15(P1, W1); __m128i W2 = _mm_loadu_si128(&input_mm[2]); prep00_15(P2, W2); __m128i W3 = _mm_loadu_si128(&input_mm[3]); prep00_15(P3, W3); /* Using SSE4; slower on Core2 and Nehalem #define GET_P_32(P, i) _mm_extract_epi32(P.u128, i) Much slower on all tested platforms #define GET_P_32(P,i) _mm_cvtsi128_si32(_mm_srli_si128(P.u128, i*4)) */ #define GET_P_32(P, i) P.u32[i] F1(A, B, C, D, E, GET_P_32(P0, 0)); F1(E, A, B, C, D, GET_P_32(P0, 1)); F1(D, E, A, B, C, GET_P_32(P0, 2)); F1(C, D, E, A, B, GET_P_32(P0, 3)); prep(P0, W0, W1, W2, W3, K00_19); F1(B, C, D, E, A, GET_P_32(P1, 0)); F1(A, B, C, D, E, GET_P_32(P1, 1)); F1(E, A, B, C, D, GET_P_32(P1, 2)); F1(D, E, A, B, C, GET_P_32(P1, 3)); prep(P1, W1, W2, W3, W0, K20_39); F1(C, D, E, A, B, GET_P_32(P2, 0)); F1(B, C, D, E, A, GET_P_32(P2, 1)); F1(A, B, C, D, E, GET_P_32(P2, 2)); F1(E, A, B, C, D, GET_P_32(P2, 3)); prep(P2, W2, W3, W0, W1, K20_39); F1(D, E, A, B, C, GET_P_32(P3, 0)); F1(C, D, E, A, B, GET_P_32(P3, 1)); F1(B, C, D, E, A, GET_P_32(P3, 2)); F1(A, B, C, D, E, GET_P_32(P3, 3)); prep(P3, W3, W0, W1, W2, K20_39); F1(E, A, B, C, D, GET_P_32(P0, 0)); F1(D, E, A, B, C, GET_P_32(P0, 1)); F1(C, D, E, A, B, GET_P_32(P0, 2)); F1(B, C, D, E, A, GET_P_32(P0, 3)); prep(P0, W0, W1, W2, W3, K20_39); F2(A, B, C, D, E, GET_P_32(P1, 0)); F2(E, A, B, C, D, GET_P_32(P1, 1)); F2(D, E, A, B, C, GET_P_32(P1, 2)); F2(C, D, E, A, B, GET_P_32(P1, 3)); prep(P1, W1, W2, W3, W0, K20_39); F2(B, C, D, E, A, GET_P_32(P2, 0)); F2(A, B, C, D, E, GET_P_32(P2, 1)); F2(E, A, B, C, D, GET_P_32(P2, 2)); F2(D, E, A, B, C, GET_P_32(P2, 3)); prep(P2, W2, W3, W0, W1, K40_59); F2(C, D, E, A, B, GET_P_32(P3, 0)); F2(B, C, D, E, A, GET_P_32(P3, 1)); F2(A, B, C, D, E, GET_P_32(P3, 2)); F2(E, A, B, C, D, GET_P_32(P3, 3)); prep(P3, W3, W0, W1, W2, K40_59); F2(D, E, A, B, C, GET_P_32(P0, 0)); F2(C, D, E, A, B, GET_P_32(P0, 1)); F2(B, C, D, E, A, GET_P_32(P0, 2)); F2(A, B, C, D, E, GET_P_32(P0, 3)); prep(P0, W0, W1, W2, W3, K40_59); F2(E, A, B, C, D, GET_P_32(P1, 0)); F2(D, E, A, B, C, GET_P_32(P1, 1)); F2(C, D, E, A, B, GET_P_32(P1, 2)); F2(B, C, D, E, A, GET_P_32(P1, 3)); prep(P1, W1, W2, W3, W0, K40_59); F3(A, B, C, D, E, GET_P_32(P2, 0)); F3(E, A, B, C, D, GET_P_32(P2, 1)); F3(D, E, A, B, C, GET_P_32(P2, 2)); F3(C, D, E, A, B, GET_P_32(P2, 3)); prep(P2, W2, W3, W0, W1, K40_59); F3(B, C, D, E, A, GET_P_32(P3, 0)); F3(A, B, C, D, E, GET_P_32(P3, 1)); F3(E, A, B, C, D, GET_P_32(P3, 2)); F3(D, E, A, B, C, GET_P_32(P3, 3)); prep(P3, W3, W0, W1, W2, K60_79); F3(C, D, E, A, B, GET_P_32(P0, 0)); F3(B, C, D, E, A, GET_P_32(P0, 1)); F3(A, B, C, D, E, GET_P_32(P0, 2)); F3(E, A, B, C, D, GET_P_32(P0, 3)); prep(P0, W0, W1, W2, W3, K60_79); F3(D, E, A, B, C, GET_P_32(P1, 0)); F3(C, D, E, A, B, GET_P_32(P1, 1)); F3(B, C, D, E, A, GET_P_32(P1, 2)); F3(A, B, C, D, E, GET_P_32(P1, 3)); prep(P1, W1, W2, W3, W0, K60_79); F3(E, A, B, C, D, GET_P_32(P2, 0)); F3(D, E, A, B, C, GET_P_32(P2, 1)); F3(C, D, E, A, B, GET_P_32(P2, 2)); F3(B, C, D, E, A, GET_P_32(P2, 3)); prep(P2, W2, W3, W0, W1, K60_79); F4(A, B, C, D, E, GET_P_32(P3, 0)); F4(E, A, B, C, D, GET_P_32(P3, 1)); F4(D, E, A, B, C, GET_P_32(P3, 2)); F4(C, D, E, A, B, GET_P_32(P3, 3)); prep(P3, W3, W0, W1, W2, K60_79); F4(B, C, D, E, A, GET_P_32(P0, 0)); F4(A, B, C, D, E, GET_P_32(P0, 1)); F4(E, A, B, C, D, GET_P_32(P0, 2)); F4(D, E, A, B, C, GET_P_32(P0, 3)); F4(C, D, E, A, B, GET_P_32(P1, 0)); F4(B, C, D, E, A, GET_P_32(P1, 1)); F4(A, B, C, D, E, GET_P_32(P1, 2)); F4(E, A, B, C, D, GET_P_32(P1, 3)); F4(D, E, A, B, C, GET_P_32(P2, 0)); F4(C, D, E, A, B, GET_P_32(P2, 1)); F4(B, C, D, E, A, GET_P_32(P2, 2)); F4(A, B, C, D, E, GET_P_32(P2, 3)); F4(E, A, B, C, D, GET_P_32(P3, 0)); F4(D, E, A, B, C, GET_P_32(P3, 1)); F4(C, D, E, A, B, GET_P_32(P3, 2)); F4(B, C, D, E, A, GET_P_32(P3, 3)); A = (digest[0] += A); B = (digest[1] += B); C = (digest[2] += C); D = (digest[3] += D); E = (digest[4] += E); input_mm += (64 / 16); } #undef GET_P_32 } #undef prep00_15 #undef prep } /* * SHA-{224,256} * (C) 1999-2010,2017 Jack Lloyd * 2007 FlexSecure GmbH * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { std::string sha256_provider() { #if defined(BOTAN_HAS_SHA2_32_X86) if(CPUID::has_intel_sha()) { return "shani"; } #endif #if defined(BOTAN_HAS_SHA2_32_X86_BMI2) if(CPUID::has_bmi2()) { return "bmi2"; } #endif #if defined(BOTAN_HAS_SHA2_32_ARMV8) if(CPUID::has_arm_sha2()) { return "armv8"; } #endif return "base"; } } std::unique_ptr SHA_224::copy_state() const { return std::unique_ptr(new SHA_224(*this)); } std::unique_ptr SHA_256::copy_state() const { return std::unique_ptr(new SHA_256(*this)); } /* * SHA-256 F1 Function * * Use a macro as many compilers won't inline a function this big, * even though it is much faster if inlined. */ #define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do { \ uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); \ uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); \ uint32_t M2_sigma = rotr<17>(M2) ^ rotr<19>(M2) ^ (M2 >> 10); \ uint32_t M4_sigma = rotr<7>(M4) ^ rotr<18>(M4) ^ (M4 >> 3); \ H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ D += H; \ H += A_rho + ((A & B) | ((A | B) & C)); \ M1 += M2_sigma + M3 + M4_sigma; \ } while(0); /* * SHA-224 / SHA-256 compression function */ void SHA_256::compress_digest(secure_vector& digest, const uint8_t input[], size_t blocks) { #if defined(BOTAN_HAS_SHA2_32_X86) if(CPUID::has_intel_sha()) { return SHA_256::compress_digest_x86(digest, input, blocks); } #endif #if defined(BOTAN_HAS_SHA2_32_X86_BMI2) if(CPUID::has_bmi2()) { return SHA_256::compress_digest_x86_bmi2(digest, input, blocks); } #endif #if defined(BOTAN_HAS_SHA2_32_ARMV8) if(CPUID::has_arm_sha2()) { return SHA_256::compress_digest_armv8(digest, input, blocks); } #endif uint32_t A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4], F = digest[5], G = digest[6], H = digest[7]; for(size_t i = 0; i != blocks; ++i) { uint32_t W00 = load_be(input, 0); uint32_t W01 = load_be(input, 1); uint32_t W02 = load_be(input, 2); uint32_t W03 = load_be(input, 3); uint32_t W04 = load_be(input, 4); uint32_t W05 = load_be(input, 5); uint32_t W06 = load_be(input, 6); uint32_t W07 = load_be(input, 7); uint32_t W08 = load_be(input, 8); uint32_t W09 = load_be(input, 9); uint32_t W10 = load_be(input, 10); uint32_t W11 = load_be(input, 11); uint32_t W12 = load_be(input, 12); uint32_t W13 = load_be(input, 13); uint32_t W14 = load_be(input, 14); uint32_t W15 = load_be(input, 15); SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); A = (digest[0] += A); B = (digest[1] += B); C = (digest[2] += C); D = (digest[3] += D); E = (digest[4] += E); F = (digest[5] += F); G = (digest[6] += G); H = (digest[7] += H); input += 64; } } std::string SHA_224::provider() const { return sha256_provider(); } std::string SHA_256::provider() const { return sha256_provider(); } /* * SHA-224 compression function */ void SHA_224::compress_n(const uint8_t input[], size_t blocks) { SHA_256::compress_digest(m_digest, input, blocks); } /* * Copy out the digest */ void SHA_224::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void SHA_224::clear() { MDx_HashFunction::clear(); m_digest[0] = 0xC1059ED8; m_digest[1] = 0x367CD507; m_digest[2] = 0x3070DD17; m_digest[3] = 0xF70E5939; m_digest[4] = 0xFFC00B31; m_digest[5] = 0x68581511; m_digest[6] = 0x64F98FA7; m_digest[7] = 0xBEFA4FA4; } /* * SHA-256 compression function */ void SHA_256::compress_n(const uint8_t input[], size_t blocks) { SHA_256::compress_digest(m_digest, input, blocks); } /* * Copy out the digest */ void SHA_256::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void SHA_256::clear() { MDx_HashFunction::clear(); m_digest[0] = 0x6A09E667; m_digest[1] = 0xBB67AE85; m_digest[2] = 0x3C6EF372; m_digest[3] = 0xA54FF53A; m_digest[4] = 0x510E527F; m_digest[5] = 0x9B05688C; m_digest[6] = 0x1F83D9AB; m_digest[7] = 0x5BE0CD19; } } /* * SHA-{384,512} * (C) 1999-2011,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { std::string sha512_provider() { #if defined(BOTAN_HAS_SHA2_64_BMI2) if(CPUID::has_bmi2()) { return "bmi2"; } #endif return "base"; } } std::unique_ptr SHA_384::copy_state() const { return std::unique_ptr(new SHA_384(*this)); } std::unique_ptr SHA_512::copy_state() const { return std::unique_ptr(new SHA_512(*this)); } std::unique_ptr SHA_512_256::copy_state() const { return std::unique_ptr(new SHA_512_256(*this)); } /* * SHA-512 F1 Function * * Use a macro as many compilers won't inline a function this big, * even though it is much faster if inlined. */ #define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ do { \ const uint64_t E_rho = rotr<14>(E) ^ rotr<18>(E) ^ rotr<41>(E); \ const uint64_t A_rho = rotr<28>(A) ^ rotr<34>(A) ^ rotr<39>(A); \ const uint64_t M2_sigma = rotr<19>(M2) ^ rotr<61>(M2) ^ (M2 >> 6); \ const uint64_t M4_sigma = rotr<1>(M4) ^ rotr<8>(M4) ^ (M4 >> 7); \ H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ D += H; \ H += A_rho + ((A & B) | ((A | B) & C)); \ M1 += M2_sigma + M3 + M4_sigma; \ } while(0); /* * SHA-{384,512} Compression Function */ //static void SHA_512::compress_digest(secure_vector& digest, const uint8_t input[], size_t blocks) { #if defined(BOTAN_HAS_SHA2_64_BMI2) if(CPUID::has_bmi2()) { return compress_digest_bmi2(digest, input, blocks); } #endif uint64_t A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4], F = digest[5], G = digest[6], H = digest[7]; for(size_t i = 0; i != blocks; ++i) { uint64_t W00 = load_be(input, 0); uint64_t W01 = load_be(input, 1); uint64_t W02 = load_be(input, 2); uint64_t W03 = load_be(input, 3); uint64_t W04 = load_be(input, 4); uint64_t W05 = load_be(input, 5); uint64_t W06 = load_be(input, 6); uint64_t W07 = load_be(input, 7); uint64_t W08 = load_be(input, 8); uint64_t W09 = load_be(input, 9); uint64_t W10 = load_be(input, 10); uint64_t W11 = load_be(input, 11); uint64_t W12 = load_be(input, 12); uint64_t W13 = load_be(input, 13); uint64_t W14 = load_be(input, 14); uint64_t W15 = load_be(input, 15); SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22); SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CD); SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2F); SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBC); SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538); SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019); SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9B); SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118); SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242); SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBE); SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28C); SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2); SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896F); SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1); SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235); SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694); SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2); SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3); SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5); SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65); SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275); SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483); SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4); SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5); SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFAB); SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210); SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213F); SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4); SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2); SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725); SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826F); SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70); SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFC); SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926); SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AED); SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DF); SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DE); SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8); SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6); SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353B); SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364); SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001); SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791); SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30); SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218); SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910); SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202A); SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8); SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8); SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53); SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99); SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8); SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63); SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACB); SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373); SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3); SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FC); SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60); SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72); SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439EC); SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28); SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9); SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915); SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532B); SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619C); SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207); SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1E); SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178); SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBA); SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6); SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAE); SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471B); SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84); SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493); SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBC); SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4C); SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6); SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2A); SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAEC); SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817); A = (digest[0] += A); B = (digest[1] += B); C = (digest[2] += C); D = (digest[3] += D); E = (digest[4] += E); F = (digest[5] += F); G = (digest[6] += G); H = (digest[7] += H); input += 128; } } #undef SHA2_64_F std::string SHA_512_256::provider() const { return sha512_provider(); } std::string SHA_384::provider() const { return sha512_provider(); } std::string SHA_512::provider() const { return sha512_provider(); } void SHA_512_256::compress_n(const uint8_t input[], size_t blocks) { SHA_512::compress_digest(m_digest, input, blocks); } void SHA_384::compress_n(const uint8_t input[], size_t blocks) { SHA_512::compress_digest(m_digest, input, blocks); } void SHA_512::compress_n(const uint8_t input[], size_t blocks) { SHA_512::compress_digest(m_digest, input, blocks); } void SHA_512_256::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } void SHA_384::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } void SHA_512::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } void SHA_512_256::clear() { MDx_HashFunction::clear(); m_digest[0] = 0x22312194FC2BF72C; m_digest[1] = 0x9F555FA3C84C64C2; m_digest[2] = 0x2393B86B6F53B151; m_digest[3] = 0x963877195940EABD; m_digest[4] = 0x96283EE2A88EFFE3; m_digest[5] = 0xBE5E1E2553863992; m_digest[6] = 0x2B0199FC2C85B8AA; m_digest[7] = 0x0EB72DDC81C52CA2; } void SHA_384::clear() { MDx_HashFunction::clear(); m_digest[0] = 0xCBBB9D5DC1059ED8; m_digest[1] = 0x629A292A367CD507; m_digest[2] = 0x9159015A3070DD17; m_digest[3] = 0x152FECD8F70E5939; m_digest[4] = 0x67332667FFC00B31; m_digest[5] = 0x8EB44A8768581511; m_digest[6] = 0xDB0C2E0D64F98FA7; m_digest[7] = 0x47B5481DBEFA4FA4; } void SHA_512::clear() { MDx_HashFunction::clear(); m_digest[0] = 0x6A09E667F3BCC908; m_digest[1] = 0xBB67AE8584CAA73B; m_digest[2] = 0x3C6EF372FE94F82B; m_digest[3] = 0xA54FF53A5F1D36F1; m_digest[4] = 0x510E527FADE682D1; m_digest[5] = 0x9B05688C2B3E6C1F; m_digest[6] = 0x1F83D9ABFB41BD6B; m_digest[7] = 0x5BE0CD19137E2179; } } /* * SHA-3 * (C) 2010,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { inline void SHA3_round(uint64_t T[25], const uint64_t A[25], uint64_t RC) { const uint64_t C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20]; const uint64_t C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21]; const uint64_t C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22]; const uint64_t C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23]; const uint64_t C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]; const uint64_t D0 = rotl<1>(C0) ^ C3; const uint64_t D1 = rotl<1>(C1) ^ C4; const uint64_t D2 = rotl<1>(C2) ^ C0; const uint64_t D3 = rotl<1>(C3) ^ C1; const uint64_t D4 = rotl<1>(C4) ^ C2; const uint64_t B00 = A[ 0] ^ D1; const uint64_t B01 = rotl<44>(A[ 6] ^ D2); const uint64_t B02 = rotl<43>(A[12] ^ D3); const uint64_t B03 = rotl<21>(A[18] ^ D4); const uint64_t B04 = rotl<14>(A[24] ^ D0); T[ 0] = B00 ^ (~B01 & B02) ^ RC; T[ 1] = B01 ^ (~B02 & B03); T[ 2] = B02 ^ (~B03 & B04); T[ 3] = B03 ^ (~B04 & B00); T[ 4] = B04 ^ (~B00 & B01); const uint64_t B05 = rotl<28>(A[ 3] ^ D4); const uint64_t B06 = rotl<20>(A[ 9] ^ D0); const uint64_t B07 = rotl< 3>(A[10] ^ D1); const uint64_t B08 = rotl<45>(A[16] ^ D2); const uint64_t B09 = rotl<61>(A[22] ^ D3); T[ 5] = B05 ^ (~B06 & B07); T[ 6] = B06 ^ (~B07 & B08); T[ 7] = B07 ^ (~B08 & B09); T[ 8] = B08 ^ (~B09 & B05); T[ 9] = B09 ^ (~B05 & B06); const uint64_t B10 = rotl< 1>(A[ 1] ^ D2); const uint64_t B11 = rotl< 6>(A[ 7] ^ D3); const uint64_t B12 = rotl<25>(A[13] ^ D4); const uint64_t B13 = rotl< 8>(A[19] ^ D0); const uint64_t B14 = rotl<18>(A[20] ^ D1); T[10] = B10 ^ (~B11 & B12); T[11] = B11 ^ (~B12 & B13); T[12] = B12 ^ (~B13 & B14); T[13] = B13 ^ (~B14 & B10); T[14] = B14 ^ (~B10 & B11); const uint64_t B15 = rotl<27>(A[ 4] ^ D0); const uint64_t B16 = rotl<36>(A[ 5] ^ D1); const uint64_t B17 = rotl<10>(A[11] ^ D2); const uint64_t B18 = rotl<15>(A[17] ^ D3); const uint64_t B19 = rotl<56>(A[23] ^ D4); T[15] = B15 ^ (~B16 & B17); T[16] = B16 ^ (~B17 & B18); T[17] = B17 ^ (~B18 & B19); T[18] = B18 ^ (~B19 & B15); T[19] = B19 ^ (~B15 & B16); const uint64_t B20 = rotl<62>(A[ 2] ^ D3); const uint64_t B21 = rotl<55>(A[ 8] ^ D4); const uint64_t B22 = rotl<39>(A[14] ^ D0); const uint64_t B23 = rotl<41>(A[15] ^ D1); const uint64_t B24 = rotl< 2>(A[21] ^ D2); T[20] = B20 ^ (~B21 & B22); T[21] = B21 ^ (~B22 & B23); T[22] = B22 ^ (~B23 & B24); T[23] = B23 ^ (~B24 & B20); T[24] = B24 ^ (~B20 & B21); } } //static void SHA_3::permute(uint64_t A[25]) { #if defined(BOTAN_HAS_SHA3_BMI2) if(CPUID::has_bmi2()) { return permute_bmi2(A); } #endif static const uint64_t RC[24] = { 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 }; uint64_t T[25]; for(size_t i = 0; i != 24; i += 2) { SHA3_round(T, A, RC[i+0]); SHA3_round(A, T, RC[i+1]); } } //static size_t SHA_3::absorb(size_t bitrate, secure_vector& S, size_t S_pos, const uint8_t input[], size_t length) { while(length > 0) { size_t to_take = std::min(length, bitrate / 8 - S_pos); length -= to_take; while(to_take && S_pos % 8) { S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); ++S_pos; ++input; --to_take; } while(to_take && to_take % 8 == 0) { S[S_pos / 8] ^= load_le(input, 0); S_pos += 8; input += 8; to_take -= 8; } while(to_take) { S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); ++S_pos; ++input; --to_take; } if(S_pos == bitrate / 8) { SHA_3::permute(S.data()); S_pos = 0; } } return S_pos; } //static void SHA_3::finish(size_t bitrate, secure_vector& S, size_t S_pos, uint8_t init_pad, uint8_t fini_pad) { BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64"); S[S_pos / 8] ^= static_cast(init_pad) << (8 * (S_pos % 8)); S[(bitrate / 64) - 1] ^= static_cast(fini_pad) << 56; SHA_3::permute(S.data()); } //static void SHA_3::expand(size_t bitrate, secure_vector& S, uint8_t output[], size_t output_length) { BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64"); const size_t byterate = bitrate / 8; while(output_length > 0) { const size_t copying = std::min(byterate, output_length); copy_out_vec_le(output, copying, S); output += copying; output_length -= copying; if(output_length > 0) { SHA_3::permute(S.data()); } } } SHA_3::SHA_3(size_t output_bits) : m_output_bits(output_bits), m_bitrate(1600 - 2*output_bits), m_S(25), m_S_pos(0) { // We only support the parameters for SHA-3 in this constructor if(output_bits != 224 && output_bits != 256 && output_bits != 384 && output_bits != 512) throw Invalid_Argument("SHA_3: Invalid output length " + std::to_string(output_bits)); } std::string SHA_3::name() const { return "SHA-3(" + std::to_string(m_output_bits) + ")"; } std::string SHA_3::provider() const { #if defined(BOTAN_HAS_SHA3_BMI2) if(CPUID::has_bmi2()) { return "bmi2"; } #endif return "base"; } std::unique_ptr SHA_3::copy_state() const { return std::unique_ptr(new SHA_3(*this)); } HashFunction* SHA_3::clone() const { return new SHA_3(m_output_bits); } void SHA_3::clear() { zeroise(m_S); m_S_pos = 0; } void SHA_3::add_data(const uint8_t input[], size_t length) { m_S_pos = SHA_3::absorb(m_bitrate, m_S, m_S_pos, input, length); } void SHA_3::final_result(uint8_t output[]) { SHA_3::finish(m_bitrate, m_S, m_S_pos, 0x06, 0x80); /* * We never have to run the permutation again because we only support * limited output lengths */ copy_out_vec_le(output, m_output_bits/8, m_S); clear(); } } /* * SHACAL-2 * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { inline void SHACAL2_Fwd(uint32_t A, uint32_t B, uint32_t C, uint32_t& D, uint32_t E, uint32_t F, uint32_t G, uint32_t& H, uint32_t RK) { const uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); const uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); H += E_rho + ((E & F) ^ (~E & G)) + RK; D += H; H += A_rho + ((A & B) | ((A | B) & C)); } inline void SHACAL2_Rev(uint32_t A, uint32_t B, uint32_t C, uint32_t& D, uint32_t E, uint32_t F, uint32_t G, uint32_t& H, uint32_t RK) { const uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); const uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); H -= A_rho + ((A & B) | ((A | B) & C)); D -= H; H -= E_rho + ((E & F) ^ (~E & G)) + RK; } } /* * SHACAL2 Encryption */ void SHACAL2::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); #if defined(BOTAN_HAS_SHACAL2_X86) if(CPUID::has_intel_sha()) { return x86_encrypt_blocks(in, out, blocks); } #endif #if defined(BOTAN_HAS_SHACAL2_AVX2) if(CPUID::has_avx2()) { while(blocks >= 8) { avx2_encrypt_8(in, out); in += 8*BLOCK_SIZE; out += 8*BLOCK_SIZE; blocks -= 8; } } #endif #if defined(BOTAN_HAS_SHACAL2_SIMD) if(CPUID::has_simd_32()) { while(blocks >= 4) { simd_encrypt_4(in, out); in += 4*BLOCK_SIZE; out += 4*BLOCK_SIZE; blocks -= 4; } } #endif for(size_t i = 0; i != blocks; ++i) { uint32_t A = load_be(in, 0); uint32_t B = load_be(in, 1); uint32_t C = load_be(in, 2); uint32_t D = load_be(in, 3); uint32_t E = load_be(in, 4); uint32_t F = load_be(in, 5); uint32_t G = load_be(in, 6); uint32_t H = load_be(in, 7); for(size_t r = 0; r != 64; r += 8) { SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r+0]); SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r+1]); SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r+2]); SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r+3]); SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r+4]); SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r+5]); SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r+6]); SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r+7]); } store_be(out, A, B, C, D, E, F, G, H); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * SHACAL2 Encryption */ void SHACAL2::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); #if defined(BOTAN_HAS_SHACAL2_AVX2) if(CPUID::has_avx2()) { while(blocks >= 8) { avx2_decrypt_8(in, out); in += 8*BLOCK_SIZE; out += 8*BLOCK_SIZE; blocks -= 8; } } #endif #if defined(BOTAN_HAS_SHACAL2_SIMD) if(CPUID::has_simd_32()) { while(blocks >= 4) { simd_decrypt_4(in, out); in += 4*BLOCK_SIZE; out += 4*BLOCK_SIZE; blocks -= 4; } } #endif for(size_t i = 0; i != blocks; ++i) { uint32_t A = load_be(in, 0); uint32_t B = load_be(in, 1); uint32_t C = load_be(in, 2); uint32_t D = load_be(in, 3); uint32_t E = load_be(in, 4); uint32_t F = load_be(in, 5); uint32_t G = load_be(in, 6); uint32_t H = load_be(in, 7); for(size_t r = 0; r != 64; r += 8) { SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63-r]); SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62-r]); SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61-r]); SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60-r]); SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59-r]); SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58-r]); SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57-r]); SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56-r]); } store_be(out, A, B, C, D, E, F, G, H); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * SHACAL2 Key Schedule */ void SHACAL2::key_schedule(const uint8_t key[], size_t len) { const uint32_t RC[64] = { 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 }; if(m_RK.empty()) m_RK.resize(64); else clear_mem(m_RK.data(), m_RK.size()); load_be(m_RK.data(), key, len/4); for(size_t i = 16; i != 64; ++i) { const uint32_t sigma0_15 = rotr< 7>(m_RK[i-15]) ^ rotr<18>(m_RK[i-15]) ^ (m_RK[i-15] >> 3); const uint32_t sigma1_2 = rotr<17>(m_RK[i- 2]) ^ rotr<19>(m_RK[i- 2]) ^ (m_RK[i- 2] >> 10); m_RK[i] = m_RK[i-16] + sigma0_15 + m_RK[i-7] + sigma1_2; } for(size_t i = 0; i != 64; ++i) { m_RK[i] += RC[i]; } } size_t SHACAL2::parallelism() const { #if defined(BOTAN_HAS_SHACAL2_X86) if(CPUID::has_intel_sha()) { return 4; } #endif #if defined(BOTAN_HAS_SHACAL2_AVX2) if(CPUID::has_avx2()) { return 8; } #endif #if defined(BOTAN_HAS_SHACAL2_SIMD) if(CPUID::has_simd_32()) { return 4; } #endif return 1; } std::string SHACAL2::provider() const { #if defined(BOTAN_HAS_SHACAL2_X86) if(CPUID::has_intel_sha()) { return "intel_sha"; } #endif #if defined(BOTAN_HAS_SHACAL2_AVX2) if(CPUID::has_avx2()) { return "avx2"; } #endif #if defined(BOTAN_HAS_SHACAL2_SIMD) if(CPUID::has_simd_32()) { return "simd"; } #endif return "base"; } /* * Clear memory of sensitive data */ void SHACAL2::clear() { zap(m_RK); } } /* * SHACAL-2 using SIMD * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { inline void SHACAL2_Fwd(const SIMD_4x32& A, const SIMD_4x32& B, const SIMD_4x32& C, SIMD_4x32& D, const SIMD_4x32& E, const SIMD_4x32& F, const SIMD_4x32& G, SIMD_4x32& H, uint32_t RK) { H += E.rho<6,11,25>() + ((E & F) ^ (~E & G)) + SIMD_4x32::splat(RK); D += H; H += A.rho<2,13,22>() + ((A & B) | ((A | B) & C)); } inline void SHACAL2_Rev(const SIMD_4x32& A, const SIMD_4x32& B, const SIMD_4x32& C, SIMD_4x32& D, const SIMD_4x32& E, const SIMD_4x32& F, const SIMD_4x32& G, SIMD_4x32& H, uint32_t RK) { H -= A.rho<2,13,22>() + ((A & B) | ((A | B) & C)); D -= H; H -= E.rho<6,11,25>() + ((E & F) ^ (~E & G)) + SIMD_4x32::splat(RK); } } void SHACAL2::simd_encrypt_4(const uint8_t in[], uint8_t out[]) const { SIMD_4x32 A = SIMD_4x32::load_be(in); SIMD_4x32 E = SIMD_4x32::load_be(in+16); SIMD_4x32 B = SIMD_4x32::load_be(in+32); SIMD_4x32 F = SIMD_4x32::load_be(in+48); SIMD_4x32 C = SIMD_4x32::load_be(in+64); SIMD_4x32 G = SIMD_4x32::load_be(in+80); SIMD_4x32 D = SIMD_4x32::load_be(in+96); SIMD_4x32 H = SIMD_4x32::load_be(in+112); SIMD_4x32::transpose(A, B, C, D); SIMD_4x32::transpose(E, F, G, H); for(size_t r = 0; r != 64; r += 8) { SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r+0]); SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r+1]); SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r+2]); SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r+3]); SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r+4]); SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r+5]); SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r+6]); SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r+7]); } SIMD_4x32::transpose(A, B, C, D); SIMD_4x32::transpose(E, F, G, H); A.store_be(out); E.store_be(out+16); B.store_be(out+32); F.store_be(out+48); C.store_be(out+64); G.store_be(out+80); D.store_be(out+96); H.store_be(out+112); } void SHACAL2::simd_decrypt_4(const uint8_t in[], uint8_t out[]) const { SIMD_4x32 A = SIMD_4x32::load_be(in); SIMD_4x32 E = SIMD_4x32::load_be(in+16); SIMD_4x32 B = SIMD_4x32::load_be(in+32); SIMD_4x32 F = SIMD_4x32::load_be(in+48); SIMD_4x32 C = SIMD_4x32::load_be(in+64); SIMD_4x32 G = SIMD_4x32::load_be(in+80); SIMD_4x32 D = SIMD_4x32::load_be(in+96); SIMD_4x32 H = SIMD_4x32::load_be(in+112); SIMD_4x32::transpose(A, B, C, D); SIMD_4x32::transpose(E, F, G, H); for(size_t r = 0; r != 64; r += 8) { SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63-r]); SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62-r]); SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61-r]); SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60-r]); SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59-r]); SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58-r]); SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57-r]); SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56-r]); } SIMD_4x32::transpose(A, B, C, D); SIMD_4x32::transpose(E, F, G, H); A.store_be(out); E.store_be(out+16); B.store_be(out+32); F.store_be(out+48); C.store_be(out+64); G.store_be(out+80); D.store_be(out+96); H.store_be(out+112); } } /* * SHAKE-128/256 as a hash * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { SHAKE_128::SHAKE_128(size_t output_bits) : m_output_bits(output_bits), m_S(25), m_S_pos(0) { if(output_bits % 8 != 0) throw Invalid_Argument("SHAKE_128: Invalid output length " + std::to_string(output_bits)); } std::string SHAKE_128::name() const { return "SHAKE-128(" + std::to_string(m_output_bits) + ")"; } HashFunction* SHAKE_128::clone() const { return new SHAKE_128(m_output_bits); } std::unique_ptr SHAKE_128::copy_state() const { return std::unique_ptr(new SHAKE_128(*this)); } void SHAKE_128::clear() { zeroise(m_S); m_S_pos = 0; } void SHAKE_128::add_data(const uint8_t input[], size_t length) { m_S_pos = SHA_3::absorb(SHAKE_128_BITRATE, m_S, m_S_pos, input, length); } void SHAKE_128::final_result(uint8_t output[]) { SHA_3::finish(SHAKE_128_BITRATE, m_S, m_S_pos, 0x1F, 0x80); SHA_3::expand(SHAKE_128_BITRATE, m_S, output, output_length()); clear(); } SHAKE_256::SHAKE_256(size_t output_bits) : m_output_bits(output_bits), m_S(25), m_S_pos(0) { if(output_bits % 8 != 0) throw Invalid_Argument("SHAKE_256: Invalid output length " + std::to_string(output_bits)); } std::string SHAKE_256::name() const { return "SHAKE-256(" + std::to_string(m_output_bits) + ")"; } HashFunction* SHAKE_256::clone() const { return new SHAKE_256(m_output_bits); } std::unique_ptr SHAKE_256::copy_state() const { return std::unique_ptr(new SHAKE_256(*this)); } void SHAKE_256::clear() { zeroise(m_S); m_S_pos = 0; } void SHAKE_256::add_data(const uint8_t input[], size_t length) { m_S_pos = SHA_3::absorb(SHAKE_256_BITRATE, m_S, m_S_pos, input, length); } void SHAKE_256::final_result(uint8_t output[]) { SHA_3::finish(SHAKE_256_BITRATE, m_S, m_S_pos, 0x1F, 0x80); SHA_3::expand(SHAKE_256_BITRATE, m_S, output, output_length()); clear(); } } /* * SHAKE-128 * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { SHAKE_128_Cipher::SHAKE_128_Cipher() : m_buf_pos(0) {} void SHAKE_128_Cipher::cipher(const uint8_t in[], uint8_t out[], size_t length) { const size_t SHAKE_128_BYTERATE = (1600-256)/8; verify_key_set(m_state.empty() == false); while(length >= SHAKE_128_BYTERATE - m_buf_pos) { xor_buf(out, in, &m_buffer[m_buf_pos], SHAKE_128_BYTERATE - m_buf_pos); length -= (SHAKE_128_BYTERATE - m_buf_pos); in += (SHAKE_128_BYTERATE - m_buf_pos); out += (SHAKE_128_BYTERATE - m_buf_pos); SHA_3::permute(m_state.data()); copy_out_le(m_buffer.data(), SHAKE_128_BYTERATE, m_state.data()); m_buf_pos = 0; } xor_buf(out, in, &m_buffer[m_buf_pos], length); m_buf_pos += length; } void SHAKE_128_Cipher::key_schedule(const uint8_t key[], size_t length) { const size_t SHAKE_128_BITRATE = (1600-256); m_state.resize(25); m_buffer.resize(SHAKE_128_BITRATE/8); zeroise(m_state); const size_t S_pos = SHA_3::absorb(SHAKE_128_BITRATE, m_state, 0, key, length); SHA_3::finish(SHAKE_128_BITRATE, m_state, S_pos, 0x1F, 0x80); copy_out_le(m_buffer.data(), m_buffer.size(), m_state.data()); } void SHAKE_128_Cipher::clear() { zap(m_state); zap(m_buffer); m_buf_pos = 0; } void SHAKE_128_Cipher::set_iv(const uint8_t[], size_t length) { /* * This could be supported in some way (say, by treating iv as * a prefix or suffix of the key). */ if(length != 0) throw Invalid_IV_Length(name(), length); } void SHAKE_128_Cipher::seek(uint64_t) { throw Not_Implemented("SHAKE_128_Cipher::seek"); } Key_Length_Specification SHAKE_128_Cipher::key_spec() const { return Key_Length_Specification(1, 160); } std::string SHAKE_128_Cipher::name() const { return "SHAKE-128"; } StreamCipher* SHAKE_128_Cipher::clone() const { return new SHAKE_128_Cipher; } } /* * SipHash * (C) 2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void SipRounds(uint64_t M, secure_vector& V, size_t r) { uint64_t V0 = V[0], V1 = V[1], V2 = V[2], V3 = V[3]; V3 ^= M; for(size_t i = 0; i != r; ++i) { V0 += V1; V2 += V3; V1 = rotl<13>(V1); V3 = rotl<16>(V3); V1 ^= V0; V3 ^= V2; V0 = rotl<32>(V0); V2 += V1; V0 += V3; V1 = rotl<17>(V1); V3 = rotl<21>(V3); V1 ^= V2; V3 ^= V0; V2 = rotl<32>(V2); } V0 ^= M; V[0] = V0; V[1] = V1; V[2] = V2; V[3] = V3; } } void SipHash::add_data(const uint8_t input[], size_t length) { verify_key_set(m_V.empty() == false); // SipHash counts the message length mod 256 m_words += static_cast(length); if(m_mbuf_pos) { while(length && m_mbuf_pos != 8) { m_mbuf = (m_mbuf >> 8) | (static_cast(input[0]) << 56); ++m_mbuf_pos; ++input; length--; } if(m_mbuf_pos == 8) { SipRounds(m_mbuf, m_V, m_C); m_mbuf_pos = 0; m_mbuf = 0; } } while(length >= 8) { SipRounds(load_le(input, 0), m_V, m_C); input += 8; length -= 8; } for(size_t i = 0; i != length; ++i) { m_mbuf = (m_mbuf >> 8) | (static_cast(input[i]) << 56); m_mbuf_pos++; } } void SipHash::final_result(uint8_t mac[]) { verify_key_set(m_V.empty() == false); if(m_mbuf_pos == 0) { m_mbuf = (static_cast(m_words) << 56); } else if(m_mbuf_pos < 8) { m_mbuf = (m_mbuf >> (64-m_mbuf_pos*8)) | (static_cast(m_words) << 56); } SipRounds(m_mbuf, m_V, m_C); m_V[2] ^= 0xFF; SipRounds(0, m_V, m_D); const uint64_t X = m_V[0] ^ m_V[1] ^ m_V[2] ^ m_V[3]; store_le(X, mac); clear(); } void SipHash::key_schedule(const uint8_t key[], size_t) { const uint64_t K0 = load_le(key, 0); const uint64_t K1 = load_le(key, 1); m_V.resize(4); m_V[0] = K0 ^ 0x736F6D6570736575; m_V[1] = K1 ^ 0x646F72616E646F6D; m_V[2] = K0 ^ 0x6C7967656E657261; m_V[3] = K1 ^ 0x7465646279746573; } void SipHash::clear() { zap(m_V); m_mbuf = 0; m_mbuf_pos = 0; m_words = 0; } std::string SipHash::name() const { return "SipHash(" + std::to_string(m_C) + "," + std::to_string(m_D) + ")"; } MessageAuthenticationCode* SipHash::clone() const { return new SipHash(m_C, m_D); } } /* * SIV Mode Encryption * (C) 2013,2017 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { SIV_Mode::SIV_Mode(BlockCipher* cipher) : m_name(cipher->name() + "/SIV"), m_ctr(new CTR_BE(cipher->clone(), 8)), m_mac(new CMAC(cipher)), m_bs(cipher->block_size()) { // Not really true but only 128 bit allowed at the moment if(m_bs != 16) throw Invalid_Argument("SIV requires a 128 bit block cipher"); } SIV_Mode::~SIV_Mode() { // for ~unique_ptr } void SIV_Mode::clear() { m_ctr->clear(); m_mac->clear(); reset(); } void SIV_Mode::reset() { m_nonce.clear(); m_msg_buf.clear(); m_ad_macs.clear(); } std::string SIV_Mode::name() const { return m_name; } bool SIV_Mode::valid_nonce_length(size_t) const { return true; } size_t SIV_Mode::update_granularity() const { /* This value does not particularly matter as regardless SIV_Mode::update buffers all input, so in theory this could be 1. However as for instance Transform_Filter creates update_granularity() uint8_t buffers, use a somewhat large size to avoid bouncing on a tiny buffer. */ return 128; } Key_Length_Specification SIV_Mode::key_spec() const { return m_mac->key_spec().multiple(2); } void SIV_Mode::key_schedule(const uint8_t key[], size_t length) { const size_t keylen = length / 2; m_mac->set_key(key, keylen); m_ctr->set_key(key + keylen, keylen); m_ad_macs.clear(); } size_t SIV_Mode::maximum_associated_data_inputs() const { return block_size() * 8 - 2; } void SIV_Mode::set_associated_data_n(size_t n, const uint8_t ad[], size_t length) { const size_t max_ads = maximum_associated_data_inputs(); if(n > max_ads) throw Invalid_Argument(name() + " allows no more than " + std::to_string(max_ads) + " ADs"); if(n >= m_ad_macs.size()) m_ad_macs.resize(n+1); m_ad_macs[n] = m_mac->process(ad, length); } void SIV_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); if(nonce_len) m_nonce = m_mac->process(nonce, nonce_len); else m_nonce.clear(); m_msg_buf.clear(); } size_t SIV_Mode::process(uint8_t buf[], size_t sz) { // all output is saved for processing in finish m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz); return 0; } secure_vector SIV_Mode::S2V(const uint8_t* text, size_t text_len) { const std::vector zeros(block_size()); secure_vector V = m_mac->process(zeros.data(), zeros.size()); for(size_t i = 0; i != m_ad_macs.size(); ++i) { poly_double_n(V.data(), V.size()); V ^= m_ad_macs[i]; } if(m_nonce.size()) { poly_double_n(V.data(), V.size()); V ^= m_nonce; } if(text_len < block_size()) { poly_double_n(V.data(), V.size()); xor_buf(V.data(), text, text_len); V[text_len] ^= 0x80; return m_mac->process(V); } m_mac->update(text, text_len - block_size()); xor_buf(V.data(), &text[text_len - block_size()], block_size()); m_mac->update(V); return m_mac->final(); } void SIV_Mode::set_ctr_iv(secure_vector V) { V[m_bs-8] &= 0x7F; V[m_bs-4] &= 0x7F; ctr().set_iv(V.data(), V.size()); } void SIV_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); msg_buf().clear(); const secure_vector V = S2V(buffer.data() + offset, buffer.size() - offset); buffer.insert(buffer.begin() + offset, V.begin(), V.end()); if(buffer.size() != offset + V.size()) { set_ctr_iv(V); ctr().cipher1(&buffer[offset + V.size()], buffer.size() - offset - V.size()); } } void SIV_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); if(msg_buf().size() > 0) { buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); msg_buf().clear(); } const size_t sz = buffer.size() - offset; BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); secure_vector V(buffer.data() + offset, buffer.data() + offset + block_size()); if(buffer.size() != offset + V.size()) { set_ctr_iv(V); ctr().cipher(buffer.data() + offset + V.size(), buffer.data() + offset, buffer.size() - offset - V.size()); } const secure_vector T = S2V(buffer.data() + offset, buffer.size() - offset - V.size()); if(!constant_time_compare(T.data(), V.data(), T.size())) throw Invalid_Authentication_Tag("SIV tag check failed"); buffer.resize(buffer.size() - tag_size()); } } /* * The Skein-512 hash function * (C) 2009,2010,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Skein_512::Skein_512(size_t arg_output_bits, const std::string& arg_personalization) : m_personalization(arg_personalization), m_output_bits(arg_output_bits), m_threefish(new Threefish_512), m_T(2), m_buffer(64), m_buf_pos(0) { if(m_output_bits == 0 || m_output_bits % 8 != 0 || m_output_bits > 512) throw Invalid_Argument("Bad output bits size for Skein-512"); initial_block(); } std::string Skein_512::name() const { if(m_personalization != "") return "Skein-512(" + std::to_string(m_output_bits) + "," + m_personalization + ")"; return "Skein-512(" + std::to_string(m_output_bits) + ")"; } HashFunction* Skein_512::clone() const { return new Skein_512(m_output_bits, m_personalization); } std::unique_ptr Skein_512::copy_state() const { std::unique_ptr copy(new Skein_512(m_output_bits, m_personalization)); copy->m_threefish->m_K = this->m_threefish->m_K; copy->m_T = this->m_T; copy->m_buffer = this->m_buffer; copy->m_buf_pos = this->m_buf_pos; // work around GCC 4.8 bug return std::unique_ptr(copy.release()); } void Skein_512::clear() { zeroise(m_buffer); m_buf_pos = 0; initial_block(); } void Skein_512::reset_tweak(type_code type, bool is_final) { m_T[0] = 0; m_T[1] = (static_cast(type) << 56) | (static_cast(1) << 62) | (static_cast(is_final) << 63); } void Skein_512::initial_block() { const uint8_t zeros[64] = { 0 }; m_threefish->set_key(zeros, sizeof(zeros)); // ASCII("SHA3") followed by version (0x0001) code uint8_t config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 }; store_le(uint32_t(m_output_bits), config_str + 8); reset_tweak(SKEIN_CONFIG, true); ubi_512(config_str, sizeof(config_str)); if(m_personalization != "") { /* This is a limitation of this implementation, and not of the algorithm specification. Could be fixed relatively easily, but doesn't seem worth the trouble. */ if(m_personalization.length() > 64) throw Invalid_Argument("Skein personalization must be less than 64 bytes"); const uint8_t* bits = cast_char_ptr_to_uint8(m_personalization.data()); reset_tweak(SKEIN_PERSONALIZATION, true); ubi_512(bits, m_personalization.length()); } reset_tweak(SKEIN_MSG, false); } void Skein_512::ubi_512(const uint8_t msg[], size_t msg_len) { secure_vector M(8); do { const size_t to_proc = std::min(msg_len, 64); m_T[0] += to_proc; load_le(M.data(), msg, to_proc / 8); if(to_proc % 8) { for(size_t j = 0; j != to_proc % 8; ++j) M[to_proc/8] |= static_cast(msg[8*(to_proc/8)+j]) << (8*j); } m_threefish->skein_feedfwd(M, m_T); // clear first flag if set m_T[1] &= ~(static_cast(1) << 62); msg_len -= to_proc; msg += to_proc; } while(msg_len); } void Skein_512::add_data(const uint8_t input[], size_t length) { if(length == 0) return; if(m_buf_pos) { buffer_insert(m_buffer, m_buf_pos, input, length); if(m_buf_pos + length > 64) { ubi_512(m_buffer.data(), m_buffer.size()); input += (64 - m_buf_pos); length -= (64 - m_buf_pos); m_buf_pos = 0; } } const size_t full_blocks = (length - 1) / 64; if(full_blocks) ubi_512(input, 64*full_blocks); length -= full_blocks * 64; buffer_insert(m_buffer, m_buf_pos, input + full_blocks * 64, length); m_buf_pos += length; } void Skein_512::final_result(uint8_t out[]) { m_T[1] |= (static_cast(1) << 63); // final block flag for(size_t i = m_buf_pos; i != m_buffer.size(); ++i) m_buffer[i] = 0; ubi_512(m_buffer.data(), m_buf_pos); const uint8_t counter[8] = { 0 }; reset_tweak(SKEIN_OUTPUT, true); ubi_512(counter, sizeof(counter)); copy_out_vec_le(out, m_output_bits / 8, m_threefish->m_K); m_buf_pos = 0; initial_block(); } } /* * SM2 Signatures * (C) 2017,2018 Ribose Inc * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string SM2_PublicKey::algo_name() const { return "SM2"; } bool SM2_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { if(!public_point().on_the_curve()) return false; if(!strong) return true; return KeyPair::signature_consistency_check(rng, *this, "user@example.com,SM3"); } SM2_PrivateKey::SM2_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits) : EC_PrivateKey(alg_id, key_bits) { m_da_inv = domain().inverse_mod_order(m_private_key + 1); } SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) : EC_PrivateKey(rng, domain, x) { m_da_inv = domain.inverse_mod_order(m_private_key + 1); } std::vector sm2_compute_za(HashFunction& hash, const std::string& user_id, const EC_Group& domain, const PointGFp& pubkey) { if(user_id.size() >= 8192) throw Invalid_Argument("SM2 user id too long to represent"); const uint16_t uid_len = static_cast(8 * user_id.size()); hash.update(get_byte(0, uid_len)); hash.update(get_byte(1, uid_len)); hash.update(user_id); const size_t p_bytes = domain.get_p_bytes(); hash.update(BigInt::encode_1363(domain.get_a(), p_bytes)); hash.update(BigInt::encode_1363(domain.get_b(), p_bytes)); hash.update(BigInt::encode_1363(domain.get_g_x(), p_bytes)); hash.update(BigInt::encode_1363(domain.get_g_y(), p_bytes)); hash.update(BigInt::encode_1363(pubkey.get_affine_x(), p_bytes)); hash.update(BigInt::encode_1363(pubkey.get_affine_y(), p_bytes)); std::vector za(hash.output_length()); hash.final(za.data()); return za; } namespace { /** * SM2 signature operation */ class SM2_Signature_Operation final : public PK_Ops::Signature { public: SM2_Signature_Operation(const SM2_PrivateKey& sm2, const std::string& ident, const std::string& hash) : m_group(sm2.domain()), m_x(sm2.private_value()), m_da_inv(sm2.get_da_inv()) { if(hash == "Raw") { // m_hash is null, m_za is empty } else { m_hash = HashFunction::create_or_throw(hash); // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA) m_za = sm2_compute_za(*m_hash, ident, m_group, sm2.public_point()); m_hash->update(m_za); } } size_t signature_length() const override { return 2*m_group.get_order_bytes(); } void update(const uint8_t msg[], size_t msg_len) override { if(m_hash) { m_hash->update(msg, msg_len); } else { m_digest.insert(m_digest.end(), msg, msg + msg_len); } } secure_vector sign(RandomNumberGenerator& rng) override; private: const EC_Group m_group; const BigInt& m_x; const BigInt& m_da_inv; std::vector m_za; secure_vector m_digest; std::unique_ptr m_hash; std::vector m_ws; }; secure_vector SM2_Signature_Operation::sign(RandomNumberGenerator& rng) { BigInt e; if(m_hash) { e = BigInt::decode(m_hash->final()); // prepend ZA for next signature if any m_hash->update(m_za); } else { e = BigInt::decode(m_digest); m_digest.clear(); } const BigInt k = m_group.random_scalar(rng); const BigInt r = m_group.mod_order( m_group.blinded_base_point_multiply_x(k, rng, m_ws) + e); const BigInt s = m_group.multiply_mod_order(m_da_inv, m_group.mod_order(k - r*m_x)); return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order().bytes()); } /** * SM2 verification operation */ class SM2_Verification_Operation final : public PK_Ops::Verification { public: SM2_Verification_Operation(const SM2_PublicKey& sm2, const std::string& ident, const std::string& hash) : m_group(sm2.domain()), m_gy_mul(m_group.get_base_point(), sm2.public_point()) { if(hash == "Raw") { // m_hash is null, m_za is empty } else { m_hash = HashFunction::create_or_throw(hash); // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA) m_za = sm2_compute_za(*m_hash, ident, m_group, sm2.public_point()); m_hash->update(m_za); } } void update(const uint8_t msg[], size_t msg_len) override { if(m_hash) { m_hash->update(msg, msg_len); } else { m_digest.insert(m_digest.end(), msg, msg + msg_len); } } bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; private: const EC_Group m_group; const PointGFp_Multi_Point_Precompute m_gy_mul; secure_vector m_digest; std::vector m_za; std::unique_ptr m_hash; }; bool SM2_Verification_Operation::is_valid_signature(const uint8_t sig[], size_t sig_len) { BigInt e; if(m_hash) { e = BigInt::decode(m_hash->final()); // prepend ZA for next signature if any m_hash->update(m_za); } else { e = BigInt::decode(m_digest); m_digest.clear(); } if(sig_len != m_group.get_order().bytes()*2) return false; const BigInt r(sig, sig_len / 2); const BigInt s(sig + sig_len / 2, sig_len / 2); if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) return false; const BigInt t = m_group.mod_order(r + s); if(t == 0) return false; const PointGFp R = m_gy_mul.multi_exp(s, t); // ??? if(R.is_zero()) return false; return (m_group.mod_order(R.get_affine_x() + e) == r); } void parse_sm2_param_string(const std::string& params, std::string& userid, std::string& hash) { // GM/T 0009-2012 specifies this as the default userid const std::string default_userid = "1234567812345678"; // defaults: userid = default_userid; hash = "SM3"; /* * SM2 parameters have the following possible formats: * Ident [since 2.2.0] * Ident,Hash [since 2.3.0] */ auto comma = params.find(','); if(comma == std::string::npos) { userid = params; } else { userid = params.substr(0, comma); hash = params.substr(comma+1, std::string::npos); } } } std::unique_ptr SM2_PublicKey::create_verification_op(const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) { std::string userid, hash; parse_sm2_param_string(params, userid, hash); return std::unique_ptr(new SM2_Verification_Operation(*this, userid, hash)); } throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr SM2_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) { std::string userid, hash; parse_sm2_param_string(params, userid, hash); return std::unique_ptr(new SM2_Signature_Operation(*this, userid, hash)); } throw Provider_Not_Found(algo_name(), provider); } } /* * SM2 Encryption * (C) 2017 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { class SM2_Encryption_Operation final : public PK_Ops::Encryption { public: SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key, RandomNumberGenerator& rng, const std::string& kdf_hash) : m_group(key.domain()), m_kdf_hash(kdf_hash), m_ws(PointGFp::WORKSPACE_SIZE), m_mul_public_point(key.public_point(), rng, m_ws) { std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); m_hash_size = hash->output_length(); } size_t max_input_bits() const override { // This is arbitrary, but assumes SM2 is used for key encapsulation return 512; } size_t ciphertext_length(size_t ptext_len) const override { const size_t elem_size = m_group.get_order_bytes(); const size_t der_overhead = 16; return der_overhead + 2*elem_size + m_hash_size + ptext_len; } secure_vector encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override { std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); std::unique_ptr kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")"); const size_t p_bytes = m_group.get_p_bytes(); const BigInt k = m_group.random_scalar(rng); const PointGFp C1 = m_group.blinded_base_point_multiply(k, rng, m_ws); const BigInt x1 = C1.get_affine_x(); const BigInt y1 = C1.get_affine_y(); std::vector x1_bytes(p_bytes); std::vector y1_bytes(p_bytes); BigInt::encode_1363(x1_bytes.data(), x1_bytes.size(), x1); BigInt::encode_1363(y1_bytes.data(), y1_bytes.size(), y1); const PointGFp kPB = m_mul_public_point.mul(k, rng, m_group.get_order(), m_ws); const BigInt x2 = kPB.get_affine_x(); const BigInt y2 = kPB.get_affine_y(); std::vector x2_bytes(p_bytes); std::vector y2_bytes(p_bytes); BigInt::encode_1363(x2_bytes.data(), x2_bytes.size(), x2); BigInt::encode_1363(y2_bytes.data(), y2_bytes.size(), y2); secure_vector kdf_input; kdf_input += x2_bytes; kdf_input += y2_bytes; const secure_vector kdf_output = kdf->derive_key(msg_len, kdf_input.data(), kdf_input.size()); secure_vector masked_msg(msg_len); xor_buf(masked_msg.data(), msg, kdf_output.data(), msg_len); hash->update(x2_bytes); hash->update(msg, msg_len); hash->update(y2_bytes); std::vector C3(hash->output_length()); hash->final(C3.data()); return DER_Encoder() .start_cons(SEQUENCE) .encode(x1) .encode(y1) .encode(C3, OCTET_STRING) .encode(masked_msg, OCTET_STRING) .end_cons() .get_contents(); } private: const EC_Group m_group; const std::string m_kdf_hash; std::vector m_ws; PointGFp_Var_Point_Precompute m_mul_public_point; size_t m_hash_size; }; class SM2_Decryption_Operation final : public PK_Ops::Decryption { public: SM2_Decryption_Operation(const SM2_Encryption_PrivateKey& key, RandomNumberGenerator& rng, const std::string& kdf_hash) : m_key(key), m_rng(rng), m_kdf_hash(kdf_hash) { std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); m_hash_size = hash->output_length(); } size_t plaintext_length(size_t ptext_len) const override { /* * This ignores the DER encoding and so overestimates the * plaintext length by 12 bytes or so */ const size_t elem_size = m_key.domain().get_order_bytes(); if(ptext_len < 2*elem_size + m_hash_size) return 0; return ptext_len - (2*elem_size + m_hash_size); } secure_vector decrypt(uint8_t& valid_mask, const uint8_t ciphertext[], size_t ciphertext_len) override { const EC_Group& group = m_key.domain(); const BigInt& cofactor = group.get_cofactor(); const size_t p_bytes = group.get_p_bytes(); valid_mask = 0x00; std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); std::unique_ptr kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")"); // Too short to be valid - no timing problem from early return if(ciphertext_len < 1 + p_bytes*2 + hash->output_length()) { return secure_vector(); } BigInt x1, y1; secure_vector C3, masked_msg; BER_Decoder(ciphertext, ciphertext_len) .start_cons(SEQUENCE) .decode(x1) .decode(y1) .decode(C3, OCTET_STRING) .decode(masked_msg, OCTET_STRING) .end_cons() .verify_end(); std::vector recode_ctext; DER_Encoder(recode_ctext) .start_cons(SEQUENCE) .encode(x1) .encode(y1) .encode(C3, OCTET_STRING) .encode(masked_msg, OCTET_STRING) .end_cons(); if(recode_ctext.size() != ciphertext_len) return secure_vector(); if(same_mem(recode_ctext.data(), ciphertext, ciphertext_len) == false) return secure_vector(); PointGFp C1 = group.point(x1, y1); C1.randomize_repr(m_rng); // Here C1 is publically invalid, so no problem with early return: if(!C1.on_the_curve()) return secure_vector(); if(cofactor > 1 && (C1 * cofactor).is_zero()) { return secure_vector(); } const PointGFp dbC1 = group.blinded_var_point_multiply( C1, m_key.private_value(), m_rng, m_ws); const BigInt x2 = dbC1.get_affine_x(); const BigInt y2 = dbC1.get_affine_y(); secure_vector x2_bytes(p_bytes); secure_vector y2_bytes(p_bytes); BigInt::encode_1363(x2_bytes.data(), x2_bytes.size(), x2); BigInt::encode_1363(y2_bytes.data(), y2_bytes.size(), y2); secure_vector kdf_input; kdf_input += x2_bytes; kdf_input += y2_bytes; const secure_vector kdf_output = kdf->derive_key(masked_msg.size(), kdf_input.data(), kdf_input.size()); xor_buf(masked_msg.data(), kdf_output.data(), kdf_output.size()); hash->update(x2_bytes); hash->update(masked_msg); hash->update(y2_bytes); secure_vector u = hash->final(); if(constant_time_compare(u.data(), C3.data(), hash->output_length()) == false) return secure_vector(); valid_mask = 0xFF; return masked_msg; } private: const SM2_Encryption_PrivateKey& m_key; RandomNumberGenerator& m_rng; const std::string m_kdf_hash; std::vector m_ws; size_t m_hash_size; }; } std::unique_ptr SM2_PublicKey::create_encryption_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) { const std::string kdf_hash = (params.empty() ? "SM3" : params); return std::unique_ptr(new SM2_Encryption_Operation(*this, rng, kdf_hash)); } throw Provider_Not_Found(algo_name(), provider); } std::unique_ptr SM2_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const { if(provider == "base" || provider.empty()) { const std::string kdf_hash = (params.empty() ? "SM3" : params); return std::unique_ptr(new SM2_Decryption_Operation(*this, rng, kdf_hash)); } throw Provider_Not_Found(algo_name(), provider); } } /* * SM3 * (C) 2017 Ribose Inc. * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr SM3::copy_state() const { return std::unique_ptr(new SM3(*this)); } namespace { const uint32_t SM3_IV[] = { 0x7380166fUL, 0x4914b2b9UL, 0x172442d7UL, 0xda8a0600UL, 0xa96f30bcUL, 0x163138aaUL, 0xe38dee4dUL, 0xb0fb0e4eUL }; inline uint32_t P0(uint32_t X) { return X ^ rotl<9>(X) ^ rotl<17>(X); } inline uint32_t FF1(uint32_t X, uint32_t Y, uint32_t Z) { return (X & Y) | ((X | Y) & Z); //return (X & Y) | (X & Z) | (Y & Z); } inline uint32_t GG1(uint32_t X, uint32_t Y, uint32_t Z) { //return (X & Y) | (~X & Z); return ((Z ^ (X & (Y ^ Z)))); } inline void R1(uint32_t A, uint32_t& B, uint32_t C, uint32_t& D, uint32_t E, uint32_t& F, uint32_t G, uint32_t& H, uint32_t TJ, uint32_t Wi, uint32_t Wj) { const uint32_t A12 = rotl<12>(A); const uint32_t SS1 = rotl<7>(A12 + E + TJ); const uint32_t TT1 = (A ^ B ^ C) + D + (SS1 ^ A12) + Wj; const uint32_t TT2 = (E ^ F ^ G) + H + SS1 + Wi; B = rotl<9>(B); D = TT1; F = rotl<19>(F); H = P0(TT2); } inline void R2(uint32_t A, uint32_t& B, uint32_t C, uint32_t& D, uint32_t E, uint32_t& F, uint32_t G, uint32_t& H, uint32_t TJ, uint32_t Wi, uint32_t Wj) { const uint32_t A12 = rotl<12>(A); const uint32_t SS1 = rotl<7>(A12 + E + TJ); const uint32_t TT1 = FF1(A, B, C) + D + (SS1 ^ A12) + Wj; const uint32_t TT2 = GG1(E, F, G) + H + SS1 + Wi; B = rotl<9>(B); D = TT1; F = rotl<19>(F); H = P0(TT2); } inline uint32_t P1(uint32_t X) { return X ^ rotl<15>(X) ^ rotl<23>(X); } inline uint32_t SM3_E(uint32_t W0, uint32_t W7, uint32_t W13, uint32_t W3, uint32_t W10) { return P1(W0 ^ W7 ^ rotl<15>(W13)) ^ rotl<7>(W3) ^ W10; } } /* * SM3 Compression Function */ void SM3::compress_n(const uint8_t input[], size_t blocks) { uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3], E = m_digest[4], F = m_digest[5], G = m_digest[6], H = m_digest[7]; for(size_t i = 0; i != blocks; ++i) { uint32_t W00 = load_be(input, 0); uint32_t W01 = load_be(input, 1); uint32_t W02 = load_be(input, 2); uint32_t W03 = load_be(input, 3); uint32_t W04 = load_be(input, 4); uint32_t W05 = load_be(input, 5); uint32_t W06 = load_be(input, 6); uint32_t W07 = load_be(input, 7); uint32_t W08 = load_be(input, 8); uint32_t W09 = load_be(input, 9); uint32_t W10 = load_be(input, 10); uint32_t W11 = load_be(input, 11); uint32_t W12 = load_be(input, 12); uint32_t W13 = load_be(input, 13); uint32_t W14 = load_be(input, 14); uint32_t W15 = load_be(input, 15); R1(A, B, C, D, E, F, G, H, 0x79CC4519, W00, W00 ^ W04); W00 = SM3_E(W00, W07, W13, W03, W10); R1(D, A, B, C, H, E, F, G, 0xF3988A32, W01, W01 ^ W05); W01 = SM3_E(W01, W08, W14, W04, W11); R1(C, D, A, B, G, H, E, F, 0xE7311465, W02, W02 ^ W06); W02 = SM3_E(W02, W09, W15, W05, W12); R1(B, C, D, A, F, G, H, E, 0xCE6228CB, W03, W03 ^ W07); W03 = SM3_E(W03, W10, W00, W06, W13); R1(A, B, C, D, E, F, G, H, 0x9CC45197, W04, W04 ^ W08); W04 = SM3_E(W04, W11, W01, W07, W14); R1(D, A, B, C, H, E, F, G, 0x3988A32F, W05, W05 ^ W09); W05 = SM3_E(W05, W12, W02, W08, W15); R1(C, D, A, B, G, H, E, F, 0x7311465E, W06, W06 ^ W10); W06 = SM3_E(W06, W13, W03, W09, W00); R1(B, C, D, A, F, G, H, E, 0xE6228CBC, W07, W07 ^ W11); W07 = SM3_E(W07, W14, W04, W10, W01); R1(A, B, C, D, E, F, G, H, 0xCC451979, W08, W08 ^ W12); W08 = SM3_E(W08, W15, W05, W11, W02); R1(D, A, B, C, H, E, F, G, 0x988A32F3, W09, W09 ^ W13); W09 = SM3_E(W09, W00, W06, W12, W03); R1(C, D, A, B, G, H, E, F, 0x311465E7, W10, W10 ^ W14); W10 = SM3_E(W10, W01, W07, W13, W04); R1(B, C, D, A, F, G, H, E, 0x6228CBCE, W11, W11 ^ W15); W11 = SM3_E(W11, W02, W08, W14, W05); R1(A, B, C, D, E, F, G, H, 0xC451979C, W12, W12 ^ W00); W12 = SM3_E(W12, W03, W09, W15, W06); R1(D, A, B, C, H, E, F, G, 0x88A32F39, W13, W13 ^ W01); W13 = SM3_E(W13, W04, W10, W00, W07); R1(C, D, A, B, G, H, E, F, 0x11465E73, W14, W14 ^ W02); W14 = SM3_E(W14, W05, W11, W01, W08); R1(B, C, D, A, F, G, H, E, 0x228CBCE6, W15, W15 ^ W03); W15 = SM3_E(W15, W06, W12, W02, W09); R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); W00 = SM3_E(W00, W07, W13, W03, W10); R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); W01 = SM3_E(W01, W08, W14, W04, W11); R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); W02 = SM3_E(W02, W09, W15, W05, W12); R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); W03 = SM3_E(W03, W10, W00, W06, W13); R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); W04 = SM3_E(W04, W11, W01, W07, W14); R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); W05 = SM3_E(W05, W12, W02, W08, W15); R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); W06 = SM3_E(W06, W13, W03, W09, W00); R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); W07 = SM3_E(W07, W14, W04, W10, W01); R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); W08 = SM3_E(W08, W15, W05, W11, W02); R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); W09 = SM3_E(W09, W00, W06, W12, W03); R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); W10 = SM3_E(W10, W01, W07, W13, W04); R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); W11 = SM3_E(W11, W02, W08, W14, W05); R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); W12 = SM3_E(W12, W03, W09, W15, W06); R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); W13 = SM3_E(W13, W04, W10, W00, W07); R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); W14 = SM3_E(W14, W05, W11, W01, W08); R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); W15 = SM3_E(W15, W06, W12, W02, W09); R2(A, B, C, D, E, F, G, H, 0x7A879D8A, W00, W00 ^ W04); W00 = SM3_E(W00, W07, W13, W03, W10); R2(D, A, B, C, H, E, F, G, 0xF50F3B14, W01, W01 ^ W05); W01 = SM3_E(W01, W08, W14, W04, W11); R2(C, D, A, B, G, H, E, F, 0xEA1E7629, W02, W02 ^ W06); W02 = SM3_E(W02, W09, W15, W05, W12); R2(B, C, D, A, F, G, H, E, 0xD43CEC53, W03, W03 ^ W07); W03 = SM3_E(W03, W10, W00, W06, W13); R2(A, B, C, D, E, F, G, H, 0xA879D8A7, W04, W04 ^ W08); W04 = SM3_E(W04, W11, W01, W07, W14); R2(D, A, B, C, H, E, F, G, 0x50F3B14F, W05, W05 ^ W09); W05 = SM3_E(W05, W12, W02, W08, W15); R2(C, D, A, B, G, H, E, F, 0xA1E7629E, W06, W06 ^ W10); W06 = SM3_E(W06, W13, W03, W09, W00); R2(B, C, D, A, F, G, H, E, 0x43CEC53D, W07, W07 ^ W11); W07 = SM3_E(W07, W14, W04, W10, W01); R2(A, B, C, D, E, F, G, H, 0x879D8A7A, W08, W08 ^ W12); W08 = SM3_E(W08, W15, W05, W11, W02); R2(D, A, B, C, H, E, F, G, 0x0F3B14F5, W09, W09 ^ W13); W09 = SM3_E(W09, W00, W06, W12, W03); R2(C, D, A, B, G, H, E, F, 0x1E7629EA, W10, W10 ^ W14); W10 = SM3_E(W10, W01, W07, W13, W04); R2(B, C, D, A, F, G, H, E, 0x3CEC53D4, W11, W11 ^ W15); W11 = SM3_E(W11, W02, W08, W14, W05); R2(A, B, C, D, E, F, G, H, 0x79D8A7A8, W12, W12 ^ W00); W12 = SM3_E(W12, W03, W09, W15, W06); R2(D, A, B, C, H, E, F, G, 0xF3B14F50, W13, W13 ^ W01); W13 = SM3_E(W13, W04, W10, W00, W07); R2(C, D, A, B, G, H, E, F, 0xE7629EA1, W14, W14 ^ W02); W14 = SM3_E(W14, W05, W11, W01, W08); R2(B, C, D, A, F, G, H, E, 0xCEC53D43, W15, W15 ^ W03); W15 = SM3_E(W15, W06, W12, W02, W09); R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); W00 = SM3_E(W00, W07, W13, W03, W10); R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); W01 = SM3_E(W01, W08, W14, W04, W11); R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); W02 = SM3_E(W02, W09, W15, W05, W12); R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); W03 = SM3_E(W03, W10, W00, W06, W13); R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); A = (m_digest[0] ^= A); B = (m_digest[1] ^= B); C = (m_digest[2] ^= C); D = (m_digest[3] ^= D); E = (m_digest[4] ^= E); F = (m_digest[5] ^= F); G = (m_digest[6] ^= G); H = (m_digest[7] ^= H); input += hash_block_size(); } } /* * Copy out the digest */ void SM3::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void SM3::clear() { MDx_HashFunction::clear(); std::copy(std::begin(SM3_IV), std::end(SM3_IV), m_digest.begin()); } } /* * SM4 * (C) 2017 Ribose Inc * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { alignas(64) const uint8_t SM4_SBOX[256] = { 0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, 0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, 0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, 0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, 0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, 0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, 0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, 0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, 0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48 }; /* * SM4_SBOX_T[j] == L(SM4_SBOX[j]). */ alignas(64) const uint32_t SM4_SBOX_T[256] = { 0x8ED55B5B, 0xD0924242, 0x4DEAA7A7, 0x06FDFBFB, 0xFCCF3333, 0x65E28787, 0xC93DF4F4, 0x6BB5DEDE, 0x4E165858, 0x6EB4DADA, 0x44145050, 0xCAC10B0B, 0x8828A0A0, 0x17F8EFEF, 0x9C2CB0B0, 0x11051414, 0x872BACAC, 0xFB669D9D, 0xF2986A6A, 0xAE77D9D9, 0x822AA8A8, 0x46BCFAFA, 0x14041010, 0xCFC00F0F, 0x02A8AAAA, 0x54451111, 0x5F134C4C, 0xBE269898, 0x6D482525, 0x9E841A1A, 0x1E061818, 0xFD9B6666, 0xEC9E7272, 0x4A430909, 0x10514141, 0x24F7D3D3, 0xD5934646, 0x53ECBFBF, 0xF89A6262, 0x927BE9E9, 0xFF33CCCC, 0x04555151, 0x270B2C2C, 0x4F420D0D, 0x59EEB7B7, 0xF3CC3F3F, 0x1CAEB2B2, 0xEA638989, 0x74E79393, 0x7FB1CECE, 0x6C1C7070, 0x0DABA6A6, 0xEDCA2727, 0x28082020, 0x48EBA3A3, 0xC1975656, 0x80820202, 0xA3DC7F7F, 0xC4965252, 0x12F9EBEB, 0xA174D5D5, 0xB38D3E3E, 0xC33FFCFC, 0x3EA49A9A, 0x5B461D1D, 0x1B071C1C, 0x3BA59E9E, 0x0CFFF3F3, 0x3FF0CFCF, 0xBF72CDCD, 0x4B175C5C, 0x52B8EAEA, 0x8F810E0E, 0x3D586565, 0xCC3CF0F0, 0x7D196464, 0x7EE59B9B, 0x91871616, 0x734E3D3D, 0x08AAA2A2, 0xC869A1A1, 0xC76AADAD, 0x85830606, 0x7AB0CACA, 0xB570C5C5, 0xF4659191, 0xB2D96B6B, 0xA7892E2E, 0x18FBE3E3, 0x47E8AFAF, 0x330F3C3C, 0x674A2D2D, 0xB071C1C1, 0x0E575959, 0xE99F7676, 0xE135D4D4, 0x661E7878, 0xB4249090, 0x360E3838, 0x265F7979, 0xEF628D8D, 0x38596161, 0x95D24747, 0x2AA08A8A, 0xB1259494, 0xAA228888, 0x8C7DF1F1, 0xD73BECEC, 0x05010404, 0xA5218484, 0x9879E1E1, 0x9B851E1E, 0x84D75353, 0x00000000, 0x5E471919, 0x0B565D5D, 0xE39D7E7E, 0x9FD04F4F, 0xBB279C9C, 0x1A534949, 0x7C4D3131, 0xEE36D8D8, 0x0A020808, 0x7BE49F9F, 0x20A28282, 0xD4C71313, 0xE8CB2323, 0xE69C7A7A, 0x42E9ABAB, 0x43BDFEFE, 0xA2882A2A, 0x9AD14B4B, 0x40410101, 0xDBC41F1F, 0xD838E0E0, 0x61B7D6D6, 0x2FA18E8E, 0x2BF4DFDF, 0x3AF1CBCB, 0xF6CD3B3B, 0x1DFAE7E7, 0xE5608585, 0x41155454, 0x25A38686, 0x60E38383, 0x16ACBABA, 0x295C7575, 0x34A69292, 0xF7996E6E, 0xE434D0D0, 0x721A6868, 0x01545555, 0x19AFB6B6, 0xDF914E4E, 0xFA32C8C8, 0xF030C0C0, 0x21F6D7D7, 0xBC8E3232, 0x75B3C6C6, 0x6FE08F8F, 0x691D7474, 0x2EF5DBDB, 0x6AE18B8B, 0x962EB8B8, 0x8A800A0A, 0xFE679999, 0xE2C92B2B, 0xE0618181, 0xC0C30303, 0x8D29A4A4, 0xAF238C8C, 0x07A9AEAE, 0x390D3434, 0x1F524D4D, 0x764F3939, 0xD36EBDBD, 0x81D65757, 0xB7D86F6F, 0xEB37DCDC, 0x51441515, 0xA6DD7B7B, 0x09FEF7F7, 0xB68C3A3A, 0x932FBCBC, 0x0F030C0C, 0x03FCFFFF, 0xC26BA9A9, 0xBA73C9C9, 0xD96CB5B5, 0xDC6DB1B1, 0x375A6D6D, 0x15504545, 0xB98F3636, 0x771B6C6C, 0x13ADBEBE, 0xDA904A4A, 0x57B9EEEE, 0xA9DE7777, 0x4CBEF2F2, 0x837EFDFD, 0x55114444, 0xBDDA6767, 0x2C5D7171, 0x45400505, 0x631F7C7C, 0x50104040, 0x325B6969, 0xB8DB6363, 0x220A2828, 0xC5C20707, 0xF531C4C4, 0xA88A2222, 0x31A79696, 0xF9CE3737, 0x977AEDED, 0x49BFF6F6, 0x992DB4B4, 0xA475D1D1, 0x90D34343, 0x5A124848, 0x58BAE2E2, 0x71E69797, 0x64B6D2D2, 0x70B2C2C2, 0xAD8B2626, 0xCD68A5A5, 0xCB955E5E, 0x624B2929, 0x3C0C3030, 0xCE945A5A, 0xAB76DDDD, 0x867FF9F9, 0xF1649595, 0x5DBBE6E6, 0x35F2C7C7, 0x2D092424, 0xD1C61717, 0xD66FB9B9, 0xDEC51B1B, 0x94861212, 0x78186060, 0x30F3C3C3, 0x897CF5F5, 0x5CEFB3B3, 0xD23AE8E8, 0xACDF7373, 0x794C3535, 0xA0208080, 0x9D78E5E5, 0x56EDBBBB, 0x235E7D7D, 0xC63EF8F8, 0x8BD45F5F, 0xE7C82F2F, 0xDD39E4E4, 0x68492121 }; inline uint32_t SM4_T_slow(uint32_t b) { const uint32_t t = make_uint32(SM4_SBOX[get_byte(0,b)], SM4_SBOX[get_byte(1,b)], SM4_SBOX[get_byte(2,b)], SM4_SBOX[get_byte(3,b)]); // L linear transform return t ^ rotl<2>(t) ^ rotl<10>(t) ^ rotl<18>(t) ^ rotl<24>(t); } inline uint32_t SM4_T(uint32_t b) { return SM4_SBOX_T[get_byte(0,b)] ^ rotr< 8>(SM4_SBOX_T[get_byte(1,b)]) ^ rotr<16>(SM4_SBOX_T[get_byte(2,b)]) ^ rotr<24>(SM4_SBOX_T[get_byte(3,b)]); } // Variant of T for key schedule inline uint32_t SM4_Tp(uint32_t b) { const uint32_t t = make_uint32(SM4_SBOX[get_byte(0,b)], SM4_SBOX[get_byte(1,b)], SM4_SBOX[get_byte(2,b)], SM4_SBOX[get_byte(3,b)]); // L' linear transform return t ^ rotl<13>(t) ^ rotl<23>(t); } #define SM4_E_RNDS(B, R, F) do { \ B##0 ^= F(B##1 ^ B##2 ^ B##3 ^ m_RK[4*R+0]); \ B##1 ^= F(B##2 ^ B##3 ^ B##0 ^ m_RK[4*R+1]); \ B##2 ^= F(B##3 ^ B##0 ^ B##1 ^ m_RK[4*R+2]); \ B##3 ^= F(B##0 ^ B##1 ^ B##2 ^ m_RK[4*R+3]); \ } while(0) #define SM4_D_RNDS(B, R, F) do { \ B##0 ^= F(B##1 ^ B##2 ^ B##3 ^ m_RK[4*R+3]); \ B##1 ^= F(B##2 ^ B##3 ^ B##0 ^ m_RK[4*R+2]); \ B##2 ^= F(B##3 ^ B##0 ^ B##1 ^ m_RK[4*R+1]); \ B##3 ^= F(B##0 ^ B##1 ^ B##2 ^ m_RK[4*R+0]); \ } while(0) } /* * SM4 Encryption */ void SM4::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); #if defined(BOTAN_HAS_SM4_ARMV8) if(CPUID::has_arm_sm4()) return sm4_armv8_encrypt(in, out, blocks); #endif while(blocks >= 2) { uint32_t B0 = load_be(in, 0); uint32_t B1 = load_be(in, 1); uint32_t B2 = load_be(in, 2); uint32_t B3 = load_be(in, 3); uint32_t C0 = load_be(in, 4); uint32_t C1 = load_be(in, 5); uint32_t C2 = load_be(in, 6); uint32_t C3 = load_be(in, 7); SM4_E_RNDS(B, 0, SM4_T_slow); SM4_E_RNDS(C, 0, SM4_T_slow); SM4_E_RNDS(B, 1, SM4_T); SM4_E_RNDS(C, 1, SM4_T); SM4_E_RNDS(B, 2, SM4_T); SM4_E_RNDS(C, 2, SM4_T); SM4_E_RNDS(B, 3, SM4_T); SM4_E_RNDS(C, 3, SM4_T); SM4_E_RNDS(B, 4, SM4_T); SM4_E_RNDS(C, 4, SM4_T); SM4_E_RNDS(B, 5, SM4_T); SM4_E_RNDS(C, 5, SM4_T); SM4_E_RNDS(B, 6, SM4_T); SM4_E_RNDS(C, 6, SM4_T); SM4_E_RNDS(B, 7, SM4_T_slow); SM4_E_RNDS(C, 7, SM4_T_slow); store_be(out, B3, B2, B1, B0, C3, C2, C1, C0); in += 2*BLOCK_SIZE; out += 2*BLOCK_SIZE; blocks -= 2; } for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be(in, 0); uint32_t B1 = load_be(in, 1); uint32_t B2 = load_be(in, 2); uint32_t B3 = load_be(in, 3); SM4_E_RNDS(B, 0, SM4_T_slow); SM4_E_RNDS(B, 1, SM4_T); SM4_E_RNDS(B, 2, SM4_T); SM4_E_RNDS(B, 3, SM4_T); SM4_E_RNDS(B, 4, SM4_T); SM4_E_RNDS(B, 5, SM4_T); SM4_E_RNDS(B, 6, SM4_T); SM4_E_RNDS(B, 7, SM4_T_slow); store_be(out, B3, B2, B1, B0); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * SM4 Decryption */ void SM4::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_RK.empty() == false); #if defined(BOTAN_HAS_SM4_ARMV8) if(CPUID::has_arm_sm4()) return sm4_armv8_decrypt(in, out, blocks); #endif while(blocks >= 2) { uint32_t B0 = load_be(in, 0); uint32_t B1 = load_be(in, 1); uint32_t B2 = load_be(in, 2); uint32_t B3 = load_be(in, 3); uint32_t C0 = load_be(in, 4); uint32_t C1 = load_be(in, 5); uint32_t C2 = load_be(in, 6); uint32_t C3 = load_be(in, 7); SM4_D_RNDS(B, 7, SM4_T_slow); SM4_D_RNDS(C, 7, SM4_T_slow); SM4_D_RNDS(B, 6, SM4_T); SM4_D_RNDS(C, 6, SM4_T); SM4_D_RNDS(B, 5, SM4_T); SM4_D_RNDS(C, 5, SM4_T); SM4_D_RNDS(B, 4, SM4_T); SM4_D_RNDS(C, 4, SM4_T); SM4_D_RNDS(B, 3, SM4_T); SM4_D_RNDS(C, 3, SM4_T); SM4_D_RNDS(B, 2, SM4_T); SM4_D_RNDS(C, 2, SM4_T); SM4_D_RNDS(B, 1, SM4_T); SM4_D_RNDS(C, 1, SM4_T); SM4_D_RNDS(B, 0, SM4_T_slow); SM4_D_RNDS(C, 0, SM4_T_slow); store_be(out, B3, B2, B1, B0, C3, C2, C1, C0); in += 2*BLOCK_SIZE; out += 2*BLOCK_SIZE; blocks -= 2; } for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be(in, 0); uint32_t B1 = load_be(in, 1); uint32_t B2 = load_be(in, 2); uint32_t B3 = load_be(in, 3); SM4_D_RNDS(B, 7, SM4_T_slow); SM4_D_RNDS(B, 6, SM4_T); SM4_D_RNDS(B, 5, SM4_T); SM4_D_RNDS(B, 4, SM4_T); SM4_D_RNDS(B, 3, SM4_T); SM4_D_RNDS(B, 2, SM4_T); SM4_D_RNDS(B, 1, SM4_T); SM4_D_RNDS(B, 0, SM4_T_slow); store_be(out, B3, B2, B1, B0); in += BLOCK_SIZE; out += BLOCK_SIZE; } } #undef SM4_E_RNDS #undef SM4_D_RNDS /* * SM4 Key Schedule */ void SM4::key_schedule(const uint8_t key[], size_t) { // System parameter or family key const uint32_t FK[4] = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc }; const uint32_t CK[32] = { 0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269, 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9, 0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249, 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9, 0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229, 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299, 0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209, 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279 }; secure_vector K(4); K[0] = load_be(key, 0) ^ FK[0]; K[1] = load_be(key, 1) ^ FK[1]; K[2] = load_be(key, 2) ^ FK[2]; K[3] = load_be(key, 3) ^ FK[3]; m_RK.resize(32); for(size_t i = 0; i != 32; ++i) { K[i % 4] ^= SM4_Tp(K[(i+1)%4] ^ K[(i+2)%4] ^ K[(i+3)%4] ^ CK[i]); m_RK[i] = K[i % 4]; } } void SM4::clear() { zap(m_RK); } size_t SM4::parallelism() const { #if defined(BOTAN_HAS_SM4_ARMV8) if(CPUID::has_arm_sm4()) { return 4; } #endif return 1; } std::string SM4::provider() const { #if defined(BOTAN_HAS_SM4_ARMV8) if(CPUID::has_arm_sm4()) { return "armv8"; } #endif return "base"; } } /* * (C) 2015,2016,2017 Jack Lloyd * (C) 2016 Daniel Neus * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_BOOST_ASIO) /* * We don't need serial port support anyway, and asking for it causes * macro conflicts with termios.h when this file is included in the * amalgamation. */ #define BOOST_ASIO_DISABLE_SERIAL_PORT #include #include #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) #include #include #include #include #include #include #include #include #elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) #include #endif namespace Botan { namespace { #if defined(BOTAN_HAS_BOOST_ASIO) class Asio_Socket final : public OS::Socket { public: Asio_Socket(const std::string& hostname, const std::string& service, std::chrono::milliseconds timeout) : m_timeout(timeout), m_timer(m_io), m_tcp(m_io) { m_timer.expires_from_now(m_timeout); check_timeout(); boost::asio::ip::tcp::resolver resolver(m_io); boost::asio::ip::tcp::resolver::query query(hostname, service); boost::asio::ip::tcp::resolver::iterator dns_iter = resolver.resolve(query); boost::system::error_code ec = boost::asio::error::would_block; auto connect_cb = [&ec](const boost::system::error_code& e, boost::asio::ip::tcp::resolver::iterator) { ec = e; }; boost::asio::async_connect(m_tcp, dns_iter, connect_cb); while(ec == boost::asio::error::would_block) { m_io.run_one(); } if(ec) throw boost::system::system_error(ec); if(m_tcp.is_open() == false) throw System_Error("Connection to host " + hostname + " failed"); } void write(const uint8_t buf[], size_t len) override { m_timer.expires_from_now(m_timeout); boost::system::error_code ec = boost::asio::error::would_block; m_tcp.async_send(boost::asio::buffer(buf, len), [&ec](boost::system::error_code e, size_t) { ec = e; }); while(ec == boost::asio::error::would_block) { m_io.run_one(); } if(ec) { throw boost::system::system_error(ec); } } size_t read(uint8_t buf[], size_t len) override { m_timer.expires_from_now(m_timeout); boost::system::error_code ec = boost::asio::error::would_block; size_t got = 0; m_tcp.async_read_some(boost::asio::buffer(buf, len), [&](boost::system::error_code cb_ec, size_t cb_got) { ec = cb_ec; got = cb_got; }); while(ec == boost::asio::error::would_block) { m_io.run_one(); } if(ec) { if(ec == boost::asio::error::eof) return 0; throw boost::system::system_error(ec); // Some other error. } return got; } private: void check_timeout() { if(m_tcp.is_open() && m_timer.expires_at() < std::chrono::system_clock::now()) { boost::system::error_code err; m_tcp.close(err); } m_timer.async_wait(std::bind(&Asio_Socket::check_timeout, this)); } const std::chrono::milliseconds m_timeout; boost::asio::io_service m_io; boost::asio::system_timer m_timer; boost::asio::ip::tcp::socket m_tcp; }; #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) class BSD_Socket final : public OS::Socket { private: #if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) typedef SOCKET socket_type; typedef int socket_op_ret_type; typedef int socklen_type; typedef int sendrecv_len_type; static socket_type invalid_socket() { return INVALID_SOCKET; } static void close_socket(socket_type s) { ::closesocket(s); } static std::string get_last_socket_error() { return std::to_string(::WSAGetLastError()); } static bool nonblocking_connect_in_progress() { return (::WSAGetLastError() == WSAEWOULDBLOCK); } static void set_nonblocking(socket_type s) { u_long nonblocking = 1; ::ioctlsocket(s, FIONBIO, &nonblocking); } static void socket_init() { WSAData wsa_data; WORD wsa_version = MAKEWORD(2, 2); if (::WSAStartup(wsa_version, &wsa_data) != 0) { throw System_Error("WSAStartup() failed", WSAGetLastError()); } if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { ::WSACleanup(); throw System_Error("Could not find a usable version of Winsock.dll"); } } static void socket_fini() { ::WSACleanup(); } #else typedef int socket_type; typedef ssize_t socket_op_ret_type; typedef socklen_t socklen_type; typedef size_t sendrecv_len_type; static socket_type invalid_socket() { return -1; } static void close_socket(socket_type s) { ::close(s); } static std::string get_last_socket_error() { return ::strerror(errno); } static bool nonblocking_connect_in_progress() { return (errno == EINPROGRESS); } static void set_nonblocking(socket_type s) { if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) throw System_Error("Setting socket to non-blocking state failed", errno); } static void socket_init() {} static void socket_fini() {} #endif public: BSD_Socket(const std::string& hostname, const std::string& service, std::chrono::microseconds timeout) : m_timeout(timeout) { socket_init(); m_socket = invalid_socket(); addrinfo hints; clear_mem(&hints, 1); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; addrinfo* res; int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res); if(rc != 0) { throw System_Error("Name resolution failed for " + hostname, rc); } for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) { if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) continue; m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(m_socket == invalid_socket()) { // unsupported socket type? continue; } set_nonblocking(m_socket); int err = ::connect(m_socket, rp->ai_addr, static_cast(rp->ai_addrlen)); if(err == -1) { int active = 0; if(nonblocking_connect_in_progress()) { struct timeval timeout_tv = make_timeout_tv(); fd_set write_set; FD_ZERO(&write_set); // Weirdly, Winsock uses a SOCKET type but wants FD_SET to get an int instead FD_SET(static_cast(m_socket), &write_set); active = ::select(static_cast(m_socket + 1), nullptr, &write_set, nullptr, &timeout_tv); if(active) { int socket_error = 0; socklen_t len = sizeof(socket_error); if(::getsockopt(m_socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&socket_error), &len) < 0) throw System_Error("Error calling getsockopt", errno); if(socket_error != 0) { active = 0; } } } if(active == 0) { close_socket(m_socket); m_socket = invalid_socket(); continue; } } } ::freeaddrinfo(res); if(m_socket == invalid_socket()) { throw System_Error("Connecting to " + hostname + " for service " + service + " failed", errno); } } ~BSD_Socket() { close_socket(m_socket); m_socket = invalid_socket(); socket_fini(); } void write(const uint8_t buf[], size_t len) override { fd_set write_set; FD_ZERO(&write_set); FD_SET(m_socket, &write_set); size_t sent_so_far = 0; while(sent_so_far != len) { struct timeval timeout = make_timeout_tv(); int active = ::select(static_cast(m_socket + 1), nullptr, &write_set, nullptr, &timeout); if(active == 0) throw System_Error("Timeout during socket write"); const size_t left = len - sent_so_far; socket_op_ret_type sent = ::send(m_socket, cast_uint8_ptr_to_char(&buf[sent_so_far]), static_cast(left), 0); if(sent < 0) throw System_Error("Socket write failed", errno); else sent_so_far += static_cast(sent); } } size_t read(uint8_t buf[], size_t len) override { fd_set read_set; FD_ZERO(&read_set); FD_SET(m_socket, &read_set); struct timeval timeout = make_timeout_tv(); int active = ::select(static_cast(m_socket + 1), &read_set, nullptr, nullptr, &timeout); if(active == 0) throw System_Error("Timeout during socket read"); socket_op_ret_type got = ::recv(m_socket, cast_uint8_ptr_to_char(buf), static_cast(len), 0); if(got < 0) throw System_Error("Socket read failed", errno); return static_cast(got); } private: struct timeval make_timeout_tv() const { struct timeval tv; tv.tv_sec = static_cast(m_timeout.count() / 1000000); tv.tv_usec = static_cast(m_timeout.count() % 1000000);; return tv; } const std::chrono::microseconds m_timeout; socket_type m_socket; }; #endif } std::unique_ptr OS::open_socket(const std::string& hostname, const std::string& service, std::chrono::milliseconds timeout) { #if defined(BOTAN_HAS_BOOST_ASIO) return std::unique_ptr(new Asio_Socket(hostname, service, timeout)); #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) return std::unique_ptr(new BSD_Socket(hostname, service, timeout)); #else BOTAN_UNUSED(hostname); BOTAN_UNUSED(service); BOTAN_UNUSED(timeout); // No sockets for you return std::unique_ptr(); #endif } } /* * (C) 2015,2016,2017 Jack Lloyd * (C) 2016 Daniel Neus * (C) 2019 Nuno Goncalves * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_BOOST_ASIO) /* * We don't need serial port support anyway, and asking for it * causes macro conflicts with Darwin's termios.h when this * file is included in the amalgamation. GH #350 */ #define BOOST_ASIO_DISABLE_SERIAL_PORT #include #include #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) #include #include #include #include #include #include #include #include #elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) #include #endif namespace Botan { namespace { #if defined(BOTAN_HAS_BOOST_ASIO) class Asio_SocketUDP final : public OS::SocketUDP { public: Asio_SocketUDP(const std::string& hostname, const std::string& service, std::chrono::microseconds timeout) : m_timeout(timeout), m_timer(m_io), m_udp(m_io) { m_timer.expires_from_now(m_timeout); check_timeout(); boost::asio::ip::udp::resolver resolver(m_io); boost::asio::ip::udp::resolver::query query(hostname, service); boost::asio::ip::udp::resolver::iterator dns_iter = resolver.resolve(query); boost::system::error_code ec = boost::asio::error::would_block; auto connect_cb = [&ec](const boost::system::error_code& e, boost::asio::ip::udp::resolver::iterator) { ec = e; }; boost::asio::async_connect(m_udp, dns_iter, connect_cb); while(ec == boost::asio::error::would_block) { m_io.run_one(); } if(ec) { throw boost::system::system_error(ec); } if(m_udp.is_open() == false) { throw System_Error("Connection to host " + hostname + " failed"); } } void write(const uint8_t buf[], size_t len) override { m_timer.expires_from_now(m_timeout); boost::system::error_code ec = boost::asio::error::would_block; m_udp.async_send(boost::asio::buffer(buf, len), [&ec](boost::system::error_code e, size_t) { ec = e; }); while(ec == boost::asio::error::would_block) { m_io.run_one(); } if(ec) { throw boost::system::system_error(ec); } } size_t read(uint8_t buf[], size_t len) override { m_timer.expires_from_now(m_timeout); boost::system::error_code ec = boost::asio::error::would_block; size_t got = 0; m_udp.async_receive(boost::asio::buffer(buf, len), [&](boost::system::error_code cb_ec, size_t cb_got) { ec = cb_ec; got = cb_got; }); while(ec == boost::asio::error::would_block) { m_io.run_one(); } if(ec) { if(ec == boost::asio::error::eof) { return 0; } throw boost::system::system_error(ec); // Some other error. } return got; } private: void check_timeout() { if(m_udp.is_open() && m_timer.expires_at() < std::chrono::system_clock::now()) { boost::system::error_code err; m_udp.close(err); } m_timer.async_wait(std::bind(&Asio_SocketUDP::check_timeout, this)); } const std::chrono::microseconds m_timeout; boost::asio::io_service m_io; boost::asio::system_timer m_timer; boost::asio::ip::udp::socket m_udp; }; #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) class BSD_SocketUDP final : public OS::SocketUDP { public: BSD_SocketUDP(const std::string& hostname, const std::string& service, std::chrono::microseconds timeout) : m_timeout(timeout) { socket_init(); m_socket = invalid_socket(); addrinfo* res; addrinfo hints; clear_mem(&hints, 1); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res); if(rc != 0) { throw System_Error("Name resolution failed for " + hostname, rc); } for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) { if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) { continue; } m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(m_socket == invalid_socket()) { // unsupported socket type? continue; } set_nonblocking(m_socket); memcpy(&sa, res->ai_addr, res->ai_addrlen); salen = static_cast(res->ai_addrlen); } ::freeaddrinfo(res); if(m_socket == invalid_socket()) { throw System_Error("Connecting to " + hostname + " for service " + service + " failed", errno); } } ~BSD_SocketUDP() { close_socket(m_socket); m_socket = invalid_socket(); socket_fini(); } void write(const uint8_t buf[], size_t len) override { fd_set write_set; FD_ZERO(&write_set); FD_SET(m_socket, &write_set); size_t sent_so_far = 0; while(sent_so_far != len) { struct timeval timeout = make_timeout_tv(); int active = ::select(static_cast(m_socket + 1), nullptr, &write_set, nullptr, &timeout); if(active == 0) { throw System_Error("Timeout during socket write"); } const size_t left = len - sent_so_far; socket_op_ret_type sent = ::sendto(m_socket, cast_uint8_ptr_to_char(buf + sent_so_far), static_cast(left), 0, reinterpret_cast(&sa), salen); if(sent < 0) { throw System_Error("Socket write failed", errno); } else { sent_so_far += static_cast(sent); } } } size_t read(uint8_t buf[], size_t len) override { fd_set read_set; FD_ZERO(&read_set); FD_SET(m_socket, &read_set); struct timeval timeout = make_timeout_tv(); int active = ::select(static_cast(m_socket + 1), &read_set, nullptr, nullptr, &timeout); if(active == 0) { throw System_Error("Timeout during socket read"); } socket_op_ret_type got = ::recvfrom(m_socket, cast_uint8_ptr_to_char(buf), static_cast(len), 0, nullptr, nullptr); if(got < 0) { throw System_Error("Socket read failed", errno); } return static_cast(got); } private: #if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) typedef SOCKET socket_type; typedef int socket_op_ret_type; typedef int sendrecv_len_type; static socket_type invalid_socket() { return INVALID_SOCKET; } static void close_socket(socket_type s) { ::closesocket(s); } static std::string get_last_socket_error() { return std::to_string(::WSAGetLastError()); } static bool nonblocking_connect_in_progress() { return (::WSAGetLastError() == WSAEWOULDBLOCK); } static void set_nonblocking(socket_type s) { u_long nonblocking = 1; ::ioctlsocket(s, FIONBIO, &nonblocking); } static void socket_init() { WSAData wsa_data; WORD wsa_version = MAKEWORD(2, 2); if(::WSAStartup(wsa_version, &wsa_data) != 0) { throw System_Error("WSAStartup() failed", WSAGetLastError()); } if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { ::WSACleanup(); throw System_Error("Could not find a usable version of Winsock.dll"); } } static void socket_fini() { ::WSACleanup(); } #else typedef int socket_type; typedef ssize_t socket_op_ret_type; typedef size_t sendrecv_len_type; static socket_type invalid_socket() { return -1; } static void close_socket(socket_type s) { ::close(s); } static std::string get_last_socket_error() { return ::strerror(errno); } static bool nonblocking_connect_in_progress() { return (errno == EINPROGRESS); } static void set_nonblocking(socket_type s) { if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) { throw System_Error("Setting socket to non-blocking state failed", errno); } } static void socket_init() {} static void socket_fini() {} #endif sockaddr_storage sa; socklen_t salen; struct timeval make_timeout_tv() const { struct timeval tv; tv.tv_sec = static_cast(m_timeout.count() / 1000000); tv.tv_usec = static_cast(m_timeout.count() % 1000000);; return tv; } const std::chrono::microseconds m_timeout; socket_type m_socket; }; #endif } std::unique_ptr OS::open_socket_udp(const std::string& hostname, const std::string& service, std::chrono::microseconds timeout) { #if defined(BOTAN_HAS_BOOST_ASIO) return std::unique_ptr(new Asio_SocketUDP(hostname, service, timeout)); #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) return std::unique_ptr(new BSD_SocketUDP(hostname, service, timeout)); #else BOTAN_UNUSED(hostname); BOTAN_UNUSED(service); BOTAN_UNUSED(timeout); return std::unique_ptr(); #endif } std::unique_ptr OS::open_socket_udp(const std::string& uri_string, std::chrono::microseconds timeout) { const auto uri = URI::fromAny(uri_string); if(uri.port == 0) { throw Invalid_Argument("UDP port not specified"); } return open_socket_udp(uri.host, std::to_string(uri.port), timeout); } } /* * (C) 2019 Nuno Goncalves * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_TARGET_OS_HAS_SOCKETS) #include #include #include #elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) #include #endif #if defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) namespace { constexpr bool isdigit(char ch) { return ch >= '0' && ch <= '9'; } bool isDomain(const std::string& domain) { #if defined(__GLIBCXX__) && (__GLIBCXX__ < 20160726) // GCC 4.8 does not support regex BOTAN_UNUSED(domain); return true; #else std::regex re( R"(^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$)"); std::cmatch m; return std::regex_match(domain.c_str(), m, re); #endif } bool isIPv4(const std::string& ip) { sockaddr_storage inaddr; return !!inet_pton(AF_INET, ip.c_str(), &inaddr); } bool isIPv6(const std::string& ip) { sockaddr_storage in6addr; return !!inet_pton(AF_INET6, ip.c_str(), &in6addr); } } namespace Botan { URI URI::fromDomain(const std::string& uri) { unsigned port = 0; const auto port_pos = uri.find(':'); if(port_pos != std::string::npos) { for(char c : uri.substr(port_pos+1)) { if(!isdigit(c)) { throw Invalid_Argument("invalid"); } port = port*10 + c - '0'; if(port > 65535) { throw Invalid_Argument("invalid"); } } } const auto domain = uri.substr(0, port_pos); if(isIPv4(domain)) { throw Invalid_Argument("invalid"); } if(!isDomain(domain)) { throw Invalid_Argument("invalid"); } return {Type::Domain, domain, uint16_t(port)}; } URI URI::fromIPv4(const std::string& uri) { unsigned port = 0; const auto port_pos = uri.find(':'); if(port_pos != std::string::npos) { for(char c : uri.substr(port_pos+1)) { if(!isdigit(c)) { throw Invalid_Argument("invalid"); } port = port*10 + c - '0'; if(port > 65535) { throw Invalid_Argument("invalid"); } } } const auto ip = uri.substr(0, port_pos); if(!isIPv4(ip)) { throw Invalid_Argument("invalid"); } return { Type::IPv4, ip, uint16_t(port) }; } URI URI::fromIPv6(const std::string& uri) { unsigned port = 0; const auto port_pos = uri.find(']'); const bool with_braces = (port_pos != std::string::npos); if((uri[0]=='[') != with_braces) { throw Invalid_Argument("invalid"); } if(with_braces && (uri.size() > port_pos + 1)) { if(uri[port_pos+1]!=':') { throw Invalid_Argument("invalid"); } for(char c : uri.substr(port_pos+2)) { if(!isdigit(c)) { throw Invalid_Argument("invalid"); } port = port*10 + c - '0'; if(port > 65535) { throw Invalid_Argument("invalid"); } } } const auto ip = uri.substr((with_braces ? 1 : 0), port_pos - with_braces); if(!isIPv6(ip)) { throw Invalid_Argument("invalid"); } return { Type::IPv6, ip, uint16_t(port) }; } URI URI::fromAny(const std::string& uri) { bool colon_seen=false; bool non_number=false; if(uri[0]=='[') { return fromIPv6(uri); } for(auto c : uri) { if(c == ':') { if(colon_seen) //seen two ':' { return fromIPv6(uri); } colon_seen = true; } else if(!isdigit(c) && c != '.') { non_number=true; } } if(!non_number) { if(isIPv4(uri.substr(0, uri.find(':')))) { return fromIPv4(uri); } } return fromDomain(uri); } std::string URI::to_string() const { if(type == Type::NotSet) { throw Invalid_Argument("not set"); } if(port != 0) { if(type == Type::IPv6) { return "[" + host + "]:" + std::to_string(port); } return host + ":" + std::to_string(port); } return host; } } #else namespace Botan { URI URI::fromDomain(const std::string&) {throw Not_Implemented("No socket support enabled in build");} URI URI::fromIPv4(const std::string&) {throw Not_Implemented("No socket support enabled in build");} URI URI::fromIPv6(const std::string&) {throw Not_Implemented("No socket support enabled in build");} URI URI::fromAny(const std::string&) {throw Not_Implemented("No socket support enabled in build");} } #endif /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { int Sodium::crypto_scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]) { curve25519_donna(out, scalar, point); return 0; } int Sodium::crypto_scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]) { curve25519_basepoint(out, scalar); return 0; } int Sodium::crypto_sign_ed25519_detached(uint8_t sig[], unsigned long long* sig_len, const uint8_t msg[], size_t msg_len, const uint8_t sk[32]) { ed25519_sign(sig, msg, msg_len, sk, nullptr, 0); if(sig_len) *sig_len = 64; return 0; } int Sodium::crypto_sign_ed25519_verify_detached(const uint8_t sig[], const uint8_t msg[], size_t msg_len, const uint8_t pk[32]) { const bool ok = ed25519_verify(msg, msg_len, sig, pk, nullptr, 0); return ok ? 0 : -1; } int Sodium::crypto_sign_ed25519_keypair(uint8_t pk[32], uint8_t sk[64]) { secure_vector seed(32); randombytes_buf(seed.data(), seed.size()); return crypto_sign_ed25519_seed_keypair(pk, sk, seed.data()); } int Sodium::crypto_sign_ed25519_seed_keypair(uint8_t pk[], uint8_t sk[], const uint8_t seed[]) { ed25519_gen_keypair(pk, sk, seed); return 0; } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { int sodium_aead_chacha20poly1305_encrypt(uint8_t ctext[], unsigned long long* ctext_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t nonce[], size_t nonce_len, const uint8_t key[]) { auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", ENCRYPTION); chacha20poly1305->set_key(key, 32); chacha20poly1305->set_associated_data(ad, ad_len); chacha20poly1305->start(nonce, nonce_len); // FIXME do this in-place secure_vector buf; buf.reserve(ptext_len + 16); buf.assign(ptext, ptext + ptext_len); chacha20poly1305->finish(buf); copy_mem(ctext, buf.data(), buf.size()); if(ctext_len) *ctext_len = buf.size(); return 0; } int sodium_aead_chacha20poly1305_decrypt(uint8_t ptext[], unsigned long long* ptext_len, const uint8_t ctext[], size_t ctext_len, const uint8_t ad[], size_t ad_len, const uint8_t nonce[], size_t nonce_len, const uint8_t key[]) { if(ctext_len < 16) return -1; *ptext_len = 0; auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", DECRYPTION); chacha20poly1305->set_key(key, 32); chacha20poly1305->set_associated_data(ad, ad_len); chacha20poly1305->start(nonce, nonce_len); // FIXME do this in-place secure_vector buf; buf.assign(ctext, ctext + ctext_len); try { chacha20poly1305->finish(buf); } catch(Invalid_Authentication_Tag&) { return -1; } *ptext_len = ctext_len - 16; copy_mem(ptext, buf.data(), buf.size()); return 0; } int sodium_aead_chacha20poly1305_encrypt_detached(uint8_t ctext[], uint8_t mac[], const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t nonce[], size_t nonce_len, const uint8_t key[]) { auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", ENCRYPTION); chacha20poly1305->set_key(key, 32); chacha20poly1305->set_associated_data(ad, ad_len); chacha20poly1305->start(nonce, nonce_len); // FIXME do this in-place secure_vector buf; buf.reserve(ptext_len + 16); buf.assign(ptext, ptext + ptext_len); chacha20poly1305->finish(buf); copy_mem(ctext, buf.data(), ptext_len); copy_mem(mac, buf.data() + ptext_len, 16); return 0; } int sodium_aead_chacha20poly1305_decrypt_detached(uint8_t ptext[], const uint8_t ctext[], size_t ctext_len, const uint8_t mac[], const uint8_t ad[], size_t ad_len, const uint8_t nonce[], size_t nonce_len, const uint8_t key[]) { auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", DECRYPTION); chacha20poly1305->set_key(key, 32); chacha20poly1305->set_associated_data(ad, ad_len); chacha20poly1305->start(nonce, nonce_len); // FIXME do this in-place secure_vector buf; buf.reserve(ctext_len + 16); buf.assign(ctext, ctext + ctext_len); buf.insert(buf.end(), mac, mac + 16); try { chacha20poly1305->finish(buf); } catch(Invalid_Authentication_Tag&) { return -1; } copy_mem(ptext, buf.data(), buf.size()); return 0; } } int Sodium::crypto_aead_chacha20poly1305_ietf_encrypt(uint8_t ctext[], unsigned long long* ctext_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t unused_secret_nonce[], const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_encrypt( ctext, ctext_len, ptext, ptext_len, ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_ietf_decrypt(uint8_t ptext[], unsigned long long* ptext_len, uint8_t unused_secret_nonce[], const uint8_t ctext[], size_t ctext_len, const uint8_t ad[], size_t ad_len, const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_decrypt( ptext, ptext_len, ctext, ctext_len, ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_ietf_encrypt_detached(uint8_t ctext[], uint8_t mac[], unsigned long long* mac_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t unused_secret_nonce[], const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); if(mac_len) *mac_len = 16; return sodium_aead_chacha20poly1305_encrypt_detached( ctext, mac, ptext, ptext_len, ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_ietf_decrypt_detached(uint8_t ptext[], uint8_t unused_secret_nonce[], const uint8_t ctext[], size_t ctext_len, const uint8_t mac[], const uint8_t ad[], size_t ad_len, const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_decrypt_detached( ptext, ctext, ctext_len, mac, ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_encrypt(uint8_t ctext[], unsigned long long* ctext_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t unused_secret_nonce[], const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_encrypt( ctext, ctext_len, ptext, ptext_len, ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_decrypt(uint8_t ptext[], unsigned long long* ptext_len, uint8_t unused_secret_nonce[], const uint8_t ctext[], size_t ctext_len, const uint8_t ad[], size_t ad_len, const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_decrypt( ptext, ptext_len, ctext, ctext_len, ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_encrypt_detached(uint8_t ctext[], uint8_t mac[], unsigned long long* mac_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t unused_secret_nonce[], const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); if(mac_len) *mac_len = 16; return sodium_aead_chacha20poly1305_encrypt_detached( ctext, mac, ptext, ptext_len, ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); } int Sodium::crypto_aead_chacha20poly1305_decrypt_detached(uint8_t ptext[], uint8_t unused_secret_nonce[], const uint8_t ctext[], size_t ctext_len, const uint8_t mac[], const uint8_t ad[], size_t ad_len, const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_decrypt_detached( ptext, ctext, ctext_len, mac, ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); } int Sodium::crypto_aead_xchacha20poly1305_ietf_encrypt(uint8_t ctext[], unsigned long long* ctext_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t unused_secret_nonce[], const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_encrypt( ctext, ctext_len, ptext, ptext_len, ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_xchacha20poly1305_ietf_decrypt(uint8_t ptext[], unsigned long long* ptext_len, uint8_t unused_secret_nonce[], const uint8_t ctext[], size_t ctext_len, const uint8_t ad[], size_t ad_len, const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_decrypt( ptext, ptext_len, ctext, ctext_len, ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_xchacha20poly1305_ietf_encrypt_detached(uint8_t ctext[], uint8_t mac[], unsigned long long* mac_len, const uint8_t ptext[], size_t ptext_len, const uint8_t ad[], size_t ad_len, const uint8_t unused_secret_nonce[], const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); if(mac_len) *mac_len = 16; return sodium_aead_chacha20poly1305_encrypt_detached( ctext, mac, ptext, ptext_len, ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); } int Sodium::crypto_aead_xchacha20poly1305_ietf_decrypt_detached(uint8_t ptext[], uint8_t unused_secret_nonce[], const uint8_t ctext[], size_t ctext_len, const uint8_t mac[], const uint8_t ad[], size_t ad_len, const uint8_t nonce[], const uint8_t key[]) { BOTAN_UNUSED(unused_secret_nonce); return sodium_aead_chacha20poly1305_decrypt_detached( ptext, ctext, ctext_len, mac, ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { int Sodium::crypto_hash_sha512(uint8_t out[64], const uint8_t in[], size_t in_len) { auto sha512 = HashFunction::create_or_throw("SHA-512"); sha512->update(in, in_len); sha512->final(out); return 0; } int Sodium::crypto_hash_sha256(uint8_t out[], const uint8_t in[], size_t in_len) { auto sha256 = HashFunction::create_or_throw("SHA-256"); sha256->update(in, in_len); sha256->final(out); return 0; } int Sodium::crypto_shorthash_siphash24(uint8_t out[8], const uint8_t in[], size_t in_len, const uint8_t key[16]) { auto mac = MessageAuthenticationCode::create_or_throw("SipHash(2,4)"); mac->set_key(key, crypto_shorthash_siphash24_KEYBYTES); mac->update(in, in_len); mac->final(out); return 0; } int Sodium::crypto_onetimeauth_poly1305(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t key[]) { auto mac = MessageAuthenticationCode::create_or_throw("Poly1305"); mac->set_key(key, crypto_onetimeauth_poly1305_KEYBYTES); mac->update(in, in_len); mac->final(out); return 0; } int Sodium::crypto_onetimeauth_poly1305_verify(const uint8_t mac[], const uint8_t in[], size_t in_len, const uint8_t key[]) { secure_vector computed(crypto_onetimeauth_poly1305_BYTES); crypto_onetimeauth_poly1305(computed.data(), in, in_len, key); return crypto_verify_16(computed.data(), mac) ? 0 : -1; } int Sodium::crypto_auth_hmacsha512(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t key[]) { auto mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); mac->set_key(key, crypto_auth_hmacsha512_KEYBYTES); mac->update(in, in_len); mac->final(out); return 0; } int Sodium::crypto_auth_hmacsha512_verify(const uint8_t mac[], const uint8_t in[], size_t in_len, const uint8_t key[]) { secure_vector computed(crypto_auth_hmacsha512_BYTES); crypto_auth_hmacsha512(computed.data(), in, in_len, key); return crypto_verify_64(computed.data(), mac) ? 0 : -1; } int Sodium::crypto_auth_hmacsha512256(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t key[]) { auto mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); mac->set_key(key, crypto_auth_hmacsha512256_KEYBYTES); mac->update(in, in_len); secure_vector buf(64); mac->final(buf); copy_mem(out, buf.data(), crypto_auth_hmacsha512256_BYTES); return 0; } int Sodium::crypto_auth_hmacsha512256_verify(const uint8_t mac[], const uint8_t in[], size_t in_len, const uint8_t key[]) { secure_vector computed(crypto_auth_hmacsha512256_BYTES); crypto_auth_hmacsha512256(computed.data(), in, in_len, key); return crypto_verify_32(computed.data(), mac) ? 0 : -1; } int Sodium::crypto_auth_hmacsha256(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t key[]) { auto mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); mac->set_key(key, crypto_auth_hmacsha256_KEYBYTES); mac->update(in, in_len); mac->final(out); return 0; } int Sodium::crypto_auth_hmacsha256_verify(const uint8_t mac[], const uint8_t in[], size_t in_len, const uint8_t key[]) { secure_vector computed(crypto_auth_hmacsha256_BYTES); crypto_auth_hmacsha256(computed.data(), in, in_len, key); return crypto_verify_32(computed.data(), mac) ? 0 : -1; } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { int Sodium::crypto_box_curve25519xsalsa20poly1305_seed_keypair(uint8_t pk[32], uint8_t sk[32], const uint8_t seed[32]) { secure_vector digest(64); crypto_hash_sha512(digest.data(), seed, 32); copy_mem(sk, digest.data(), 32); return crypto_scalarmult_curve25519_base(pk, sk); } int Sodium::crypto_box_curve25519xsalsa20poly1305_keypair(uint8_t pk[32], uint8_t sk[32]) { randombytes_buf(sk, 32); return crypto_scalarmult_curve25519_base(pk, sk); } int Sodium::crypto_box_curve25519xsalsa20poly1305_beforenm(uint8_t key[], const uint8_t pk[32], const uint8_t sk[32]) { const uint8_t zero[16] = { 0 }; secure_vector shared(32); if(crypto_scalarmult_curve25519(shared.data(), sk, pk) != 0) return -1; return crypto_core_hsalsa20(key, zero, shared.data(), nullptr); } int Sodium::crypto_box_curve25519xsalsa20poly1305(uint8_t ctext[], const uint8_t ptext[], size_t ptext_len, const uint8_t nonce[], const uint8_t pk[32], const uint8_t sk[32]) { secure_vector shared(32); if(crypto_box_curve25519xsalsa20poly1305_beforenm(shared.data(), pk, sk) != 0) return -1; return crypto_box_curve25519xsalsa20poly1305_afternm(ctext, ptext, ptext_len, nonce, shared.data()); } int Sodium::crypto_box_curve25519xsalsa20poly1305_open(uint8_t ptext[], const uint8_t ctext[], size_t ctext_len, const uint8_t nonce[], const uint8_t pk[32], const uint8_t sk[32]) { secure_vector shared(32); if(crypto_box_curve25519xsalsa20poly1305_beforenm(shared.data(), pk, sk) != 0) return -1; return crypto_box_curve25519xsalsa20poly1305_open_afternm(ptext, ctext, ctext_len, nonce, shared.data()); } int Sodium::crypto_box_detached(uint8_t ctext[], uint8_t mac[], const uint8_t ptext[], size_t ptext_len, const uint8_t nonce[], const uint8_t pk[32], const uint8_t sk[32]) { secure_vector shared(32); if(crypto_box_beforenm(shared.data(), pk, sk) != 0) return -1; return crypto_box_detached_afternm(ctext, mac, ptext, ptext_len, nonce, shared.data()); } int Sodium::crypto_box_open_detached(uint8_t ptext[], const uint8_t ctext[], const uint8_t mac[], size_t ctext_len, const uint8_t nonce[], const uint8_t pk[32], const uint8_t sk[32]) { secure_vector shared(32); if(crypto_box_beforenm(shared.data(), pk, sk) != 0) return -1; return crypto_box_open_detached_afternm(ptext, ctext, mac, ctext_len, nonce, shared.data()); } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { int Sodium::crypto_stream_chacha20(uint8_t out[], size_t out_len, const uint8_t nonce[], const uint8_t key[]) { auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); chacha->set_key(key, crypto_stream_chacha20_KEYBYTES); chacha->set_iv(nonce, crypto_stream_chacha20_NONCEBYTES); chacha->write_keystream(out, out_len); return 0; } int Sodium::crypto_stream_chacha20_xor(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], const uint8_t key[]) { return crypto_stream_chacha20_xor_ic(out, in, in_len, nonce, 0, key); } int Sodium::crypto_stream_chacha20_xor_ic(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], uint64_t ic, const uint8_t key[]) { if((ic >> 6) != 0) // otherwise multiply overflows return -1; auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); chacha->set_key(key, crypto_stream_chacha20_KEYBYTES); chacha->set_iv(nonce, crypto_stream_chacha20_NONCEBYTES); chacha->seek(ic * 64); chacha->cipher(in, out, in_len); return 0; } int Sodium::crypto_stream_chacha20_ietf(uint8_t out[], size_t out_len, const uint8_t nonce[], const uint8_t key[]) { auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); chacha->set_key(key, crypto_stream_chacha20_ietf_KEYBYTES); chacha->set_iv(nonce, crypto_stream_chacha20_ietf_NONCEBYTES); chacha->write_keystream(out, out_len); return 0; } int Sodium::crypto_stream_chacha20_ietf_xor(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], const uint8_t key[]) { return crypto_stream_chacha20_ietf_xor_ic(out, in, in_len, nonce, 0, key); } int Sodium::crypto_stream_chacha20_ietf_xor_ic(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], uint32_t ic, const uint8_t key[]) { auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); chacha->set_key(key, crypto_stream_chacha20_ietf_KEYBYTES); chacha->set_iv(nonce, crypto_stream_chacha20_ietf_NONCEBYTES); chacha->seek(static_cast(ic) * 64); chacha->cipher(in, out, in_len); return 0; } int Sodium::crypto_stream_xchacha20(uint8_t out[], size_t out_len, const uint8_t nonce[], const uint8_t key[]) { auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); chacha->set_key(key, crypto_stream_xchacha20_KEYBYTES); chacha->set_iv(nonce, crypto_stream_xchacha20_NONCEBYTES); chacha->write_keystream(out, out_len); return 0; } int Sodium::crypto_stream_xchacha20_xor(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], const uint8_t key[]) { return crypto_stream_xchacha20_xor_ic(out, in, in_len, nonce, 0, key); } int Sodium::crypto_stream_xchacha20_xor_ic(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], uint64_t ic, const uint8_t key[]) { if((ic >> 6) != 0) // otherwise multiply overflows return -1; auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); chacha->set_key(key, crypto_stream_xchacha20_KEYBYTES); chacha->set_iv(nonce, crypto_stream_xchacha20_NONCEBYTES); chacha->seek(ic * 64); chacha->cipher(in, out, in_len); return 0; } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { int Sodium::crypto_core_hsalsa20(uint8_t out[], const uint8_t in[], const uint8_t key[], const uint8_t c[]) { uint32_t in32[16] = { 0 }; static const uint32_t SIGMA[] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; if(c == nullptr) { in32[0] = SIGMA[0]; in32[5] = SIGMA[1]; in32[10] = SIGMA[2]; in32[15] = SIGMA[3]; } else { in32[0] = load_le(c, 0); in32[5] = load_le(c, 1); in32[10] = load_le(c, 2); in32[15] = load_le(c, 3); } in32[1] = load_le(key, 0); in32[2] = load_le(key, 1); in32[3] = load_le(key, 2); in32[4] = load_le(key, 3); in32[6] = load_le(in, 0); in32[7] = load_le(in, 1); in32[8] = load_le(in, 2); in32[9] = load_le(in, 3); in32[11] = load_le(key, 4); in32[12] = load_le(key, 5); in32[13] = load_le(key, 6); in32[14] = load_le(key, 7); uint32_t out32[8] = { 0 }; Salsa20::hsalsa20(out32, in32); copy_out_le(out, 32, out32); return 0; } int Sodium::crypto_stream_salsa20(uint8_t out[], size_t out_len, const uint8_t nonce[], const uint8_t key[]) { Salsa20 salsa; salsa.set_key(key, crypto_stream_salsa20_KEYBYTES); salsa.set_iv(nonce, crypto_stream_salsa20_NONCEBYTES); salsa.write_keystream(out, out_len); return 0; } int Sodium::crypto_stream_salsa20_xor(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], const uint8_t key[]) { return crypto_stream_salsa20_xor_ic(out, in, in_len, nonce, 0, key); } int Sodium::crypto_stream_salsa20_xor_ic(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], uint64_t ic, const uint8_t key[]) { if((ic >> 6) != 0) // otherwise multiply overflows return -1; Salsa20 salsa; salsa.set_key(key, crypto_stream_salsa20_KEYBYTES); salsa.set_iv(nonce, crypto_stream_salsa20_NONCEBYTES); salsa.seek(ic * 64); salsa.cipher(in, out, in_len); return 0; } int Sodium::crypto_stream_xsalsa20(uint8_t out[], size_t out_len, const uint8_t nonce[], const uint8_t key[]) { Salsa20 salsa; salsa.set_key(key, crypto_stream_xsalsa20_KEYBYTES); salsa.set_iv(nonce, crypto_stream_xsalsa20_NONCEBYTES); salsa.write_keystream(out, out_len); return 0; } int Sodium::crypto_stream_xsalsa20_xor(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], const uint8_t key[]) { return crypto_stream_xsalsa20_xor_ic(out, in, in_len, nonce, 0, key); } int Sodium::crypto_stream_xsalsa20_xor_ic(uint8_t out[], const uint8_t in[], size_t in_len, const uint8_t nonce[], uint64_t ic, const uint8_t key[]) { if((ic >> 6) != 0) // otherwise multiply overflows return -1; Salsa20 salsa; salsa.set_key(key, crypto_stream_xsalsa20_KEYBYTES); salsa.set_iv(nonce, crypto_stream_xsalsa20_NONCEBYTES); salsa.seek(ic * 64); salsa.cipher(in, out, in_len); return 0; } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { int Sodium::crypto_secretbox_xsalsa20poly1305(uint8_t ctext[], const uint8_t ptext[], size_t ptext_len, const uint8_t nonce[], const uint8_t key[]) { if(ptext_len < 32) return -1; auto salsa = StreamCipher::create_or_throw("Salsa20"); salsa->set_key(key, crypto_secretbox_KEYBYTES); salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); secure_vector auth_key(32); salsa->write_keystream(auth_key.data(), auth_key.size()); salsa->cipher(ptext + 32, ctext + 32, ptext_len - 32); auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); poly1305->set_key(auth_key); poly1305->update(ctext + 32, ptext_len - 32); poly1305->final(ctext + 16); clear_mem(ctext, 16); return 0; } int Sodium::crypto_secretbox_xsalsa20poly1305_open(uint8_t ptext[], const uint8_t ctext[], size_t ctext_len, const uint8_t nonce[], const uint8_t key[]) { if(ctext_len < crypto_box_curve25519xsalsa20poly1305_ZEROBYTES) { return -1; } auto salsa = StreamCipher::create_or_throw("Salsa20"); salsa->set_key(key, crypto_secretbox_KEYBYTES); salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); secure_vector auth_key(32); salsa->write_keystream(auth_key.data(), auth_key.size()); auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); poly1305->set_key(auth_key); poly1305->update(ctext + 32, ctext_len - 32); secure_vector computed = poly1305->final(); if(!constant_time_compare(computed.data(), ctext + 16, 16)) return -1; salsa->cipher(ctext + 32, ptext + 32, ctext_len - 32); clear_mem(ptext, 32); return 0; } int Sodium::crypto_secretbox_detached(uint8_t ctext[], uint8_t mac[], const uint8_t ptext[], size_t ptext_len, const uint8_t nonce[], const uint8_t key[]) { auto salsa = StreamCipher::create_or_throw("Salsa20"); salsa->set_key(key, crypto_secretbox_KEYBYTES); salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); secure_vector auth_key(32); salsa->write_keystream(auth_key.data(), auth_key.size()); salsa->cipher(ptext, ctext, ptext_len); auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); poly1305->set_key(auth_key); poly1305->update(ctext, ptext_len); poly1305->final(mac); return 0; } int Sodium::crypto_secretbox_open_detached(uint8_t ptext[], const uint8_t ctext[], const uint8_t mac[], size_t ctext_len, const uint8_t nonce[], const uint8_t key[]) { auto salsa = StreamCipher::create_or_throw("Salsa20"); salsa->set_key(key, crypto_secretbox_KEYBYTES); salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); secure_vector auth_key(32); salsa->write_keystream(auth_key.data(), auth_key.size()); auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); poly1305->set_key(auth_key); poly1305->update(ctext, ctext_len); secure_vector computed_mac = poly1305->final(); if(!constant_time_compare(mac, computed_mac.data(), computed_mac.size())) return -1; salsa->cipher(ctext, ptext, ctext_len); return 0; } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Sodium::randombytes_buf(void* buf, size_t len) { system_rng().randomize(static_cast(buf), len); } uint32_t Sodium::randombytes_uniform(uint32_t upper_bound) { if(upper_bound <= 1) return 0; // Not completely uniform uint64_t x; randombytes_buf(&x, sizeof(x)); return x % upper_bound; } void Sodium::randombytes_buf_deterministic(void* buf, size_t size, const uint8_t seed[randombytes_SEEDBYTES]) { const unsigned char nonce[12] = { 'L', 'i', 'b', 's', 'o', 'd', 'i', 'u', 'm', 'D', 'R', 'G' }; ChaCha chacha(20); chacha.set_key(seed, randombytes_SEEDBYTES); chacha.set_iv(nonce, sizeof(nonce)); chacha.write_keystream(static_cast(buf), size); } int Sodium::crypto_verify_16(const uint8_t x[16], const uint8_t y[16]) { return same_mem(x, y, 16); } int Sodium::crypto_verify_32(const uint8_t x[32], const uint8_t y[32]) { return same_mem(x, y, 32); } int Sodium::crypto_verify_64(const uint8_t x[64], const uint8_t y[64]) { return same_mem(x, y, 64); } void Sodium::sodium_memzero(void* ptr, size_t len) { secure_scrub_memory(ptr, len); } int Sodium::sodium_memcmp(const void* x, const void* y, size_t len) { const bool same = constant_time_compare(static_cast(x), static_cast(y), len); return same ? 0 : -1; } int Sodium::sodium_compare(const uint8_t x[], const uint8_t y[], size_t len) { const uint8_t LT = static_cast(-1); const uint8_t EQ = 0; const uint8_t GT = 1; uint8_t result = EQ; // until found otherwise for(size_t i = 0; i != len; ++i) { const auto is_eq = CT::Mask::is_equal(x[i], y[i]); const auto is_lt = CT::Mask::is_lt(x[i], y[i]); result = is_eq.select(result, is_lt.select(LT, GT)); } return static_cast(result); } int Sodium::sodium_is_zero(const uint8_t b[], size_t len) { uint8_t sum = 0; for(size_t i = 0; i != len; ++i) sum |= b[i]; return static_cast(CT::Mask::expand(sum).if_not_set_return(1)); } void Sodium::sodium_increment(uint8_t b[], size_t len) { uint8_t carry = 1; for(size_t i = 0; i != len; ++i) { b[i] += carry; carry &= (b[i] == 0); } } void Sodium::sodium_add(uint8_t a[], const uint8_t b[], size_t len) { uint8_t carry = 0; for(size_t i = 0; i != len; ++i) { a[i] += b[i] + carry; carry = (a[i] < b[i]); } } void* Sodium::sodium_malloc(size_t size) { const uint64_t len = size; if(size + sizeof(len) < size) return nullptr; uint8_t* p = static_cast(std::calloc(size + sizeof(len), 1)); store_le(len, p); return p + 8; } void Sodium::sodium_free(void* ptr) { if(ptr == nullptr) return; uint8_t* p = static_cast(ptr) - 8; const uint64_t len = load_le(p, 0); secure_scrub_memory(ptr, static_cast(len)); std::free(p); } void* Sodium::sodium_allocarray(size_t count, size_t size) { const size_t bytes = count * size; if(bytes < count || bytes < size) return nullptr; return sodium_malloc(bytes); } int Sodium::sodium_mprotect_noaccess(void* ptr) { OS::page_prohibit_access(ptr); return 0; } int Sodium::sodium_mprotect_readwrite(void* ptr) { OS::page_allow_access(ptr); return 0; } } /* * KDFs defined in NIST SP 800-108 * (C) 2016 Kai Michaelis * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { size_t SP800_108_Counter::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { const std::size_t prf_len = m_prf->output_length(); const uint64_t blocks_required = (key_len + prf_len - 1) / prf_len; if(blocks_required > 0xFFFFFFFF) throw Invalid_Argument("SP800_108_Counter output size too large"); const uint8_t delim = 0; const uint32_t length = static_cast(key_len * 8); uint8_t *p = key; uint32_t counter = 1; uint8_t be_len[4] = { 0 }; secure_vector tmp; store_be(length, be_len); m_prf->set_key(secret, secret_len); while(p < key + key_len) { const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); uint8_t be_cnt[4] = { 0 }; store_be(counter, be_cnt); m_prf->update(be_cnt,4); m_prf->update(label,label_len); m_prf->update(delim); m_prf->update(salt,salt_len); m_prf->update(be_len,4); m_prf->final(tmp); copy_mem(p, tmp.data(), to_copy); p += to_copy; ++counter; BOTAN_ASSERT(counter != 0, "No counter overflow"); } return key_len; } size_t SP800_108_Feedback::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { const uint32_t length = static_cast(key_len * 8); const std::size_t prf_len = m_prf->output_length(); const std::size_t iv_len = (salt_len >= prf_len ? prf_len : 0); const uint8_t delim = 0; const uint64_t blocks_required = (key_len + prf_len - 1) / prf_len; if(blocks_required > 0xFFFFFFFF) throw Invalid_Argument("SP800_108_Feedback output size too large"); uint8_t *p = key; uint32_t counter = 1; uint8_t be_len[4] = { 0 }; secure_vector< uint8_t > prev(salt, salt + iv_len); secure_vector< uint8_t > ctx(salt + iv_len, salt + salt_len); store_be(length, be_len); m_prf->set_key(secret, secret_len); while(p < key + key_len) { const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); uint8_t be_cnt[4] = { 0 }; store_be(counter, be_cnt); m_prf->update(prev); m_prf->update(be_cnt,4); m_prf->update(label,label_len); m_prf->update(delim); m_prf->update(ctx); m_prf->update(be_len,4); m_prf->final(prev); copy_mem(p, prev.data(), to_copy); p += to_copy; ++counter; BOTAN_ASSERT(counter != 0, "No overflow"); } return key_len; } size_t SP800_108_Pipeline::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { const uint32_t length = static_cast(key_len * 8); const std::size_t prf_len = m_prf->output_length(); const uint8_t delim = 0; const uint64_t blocks_required = (key_len + prf_len - 1) / prf_len; if(blocks_required > 0xFFFFFFFF) throw Invalid_Argument("SP800_108_Feedback output size too large"); uint8_t *p = key; uint32_t counter = 1; uint8_t be_len[4] = { 0 }; secure_vector ai, ki; store_be(length, be_len); m_prf->set_key(secret,secret_len); // A(0) std::copy(label,label + label_len,std::back_inserter(ai)); ai.emplace_back(delim); std::copy(salt,salt + salt_len,std::back_inserter(ai)); std::copy(be_len,be_len + 4,std::back_inserter(ai)); while(p < key + key_len) { // A(i) m_prf->update(ai); m_prf->final(ai); // K(i) const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); uint8_t be_cnt[4] = { 0 }; store_be(counter, be_cnt); m_prf->update(ai); m_prf->update(be_cnt,4); m_prf->update(label, label_len); m_prf->update(delim); m_prf->update(salt, salt_len); m_prf->update(be_len,4); m_prf->final(ki); copy_mem(p, ki.data(), to_copy); p += to_copy; ++counter; BOTAN_ASSERT(counter != 0, "No overflow"); } return key_len; } } /* * KDF defined in NIST SP 800-56a (Approved Alternative 1) * * (C) 2017 Ribose Inc. Written by Krzysztof Kwiatkowski. * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { template size_t SP800_56A_kdf( AuxiliaryFunction_t& auxfunc, uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t label[], size_t label_len) { const uint64_t kRepsUpperBound = (1ULL << 32); const size_t digest_len = auxfunc.output_length(); const size_t reps = key_len / digest_len + ((key_len % digest_len) ? 1 : 0); if (reps >= kRepsUpperBound) { // See SP-800-56A, point 5.8.1 throw Invalid_Argument("SP800-56A KDF requested output too large"); } uint32_t counter = 1; secure_vector result; for(size_t i = 0; i < reps; i++) { auxfunc.update_be(counter++); auxfunc.update(secret, secret_len); auxfunc.update(label, label_len); auxfunc.final(result); const size_t offset = digest_len * i; const size_t len = std::min(result.size(), key_len - offset); copy_mem(&key[offset], result.data(), len); } return key_len; } } size_t SP800_56A_Hash::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { /* * TODO: should we reject a non-empty salt with an exception? * Ignoring the salt seems quite dangerous to applications which * don't expect it. */ BOTAN_UNUSED(salt, salt_len); return SP800_56A_kdf(*m_hash, key, key_len, secret, secret_len, label, label_len); } SP800_56A_HMAC::SP800_56A_HMAC(MessageAuthenticationCode* mac) : m_mac(mac) { // TODO: we need a MessageAuthenticationCode::is_hmac const SCAN_Name req(m_mac->name()); if(req.algo_name() != "HMAC") { throw Algorithm_Not_Found("Only HMAC can be used with KDF SP800-56A"); } } size_t SP800_56A_HMAC::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { /* * SP 800-56A specifies if the salt is empty then a block of zeros * equal to the hash's underlying block size are used. However this * is equivalent to setting a zero-length key, so the same call * works for either case. */ m_mac->set_key(salt, salt_len); return SP800_56A_kdf(*m_mac, key, key_len, secret, secret_len, label, label_len); } } /* * KDF defined in NIST SP 800-56c * (C) 2016 Kai Michaelis * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { size_t SP800_56C::kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const { // Randomness Extraction secure_vector k_dk; m_prf->set_key(salt, salt_len); m_prf->update(secret, secret_len); m_prf->final(k_dk); // Key Expansion return m_exp->kdf(key, key_len, k_dk.data(), k_dk.size(), nullptr, 0, label, label_len); } } /* * SRP-6a (RFC 5054 compatatible) * (C) 2011,2012,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { BigInt hash_seq(const std::string& hash_id, size_t pad_to, const BigInt& in1, const BigInt& in2) { std::unique_ptr hash_fn(HashFunction::create_or_throw(hash_id)); hash_fn->update(BigInt::encode_1363(in1, pad_to)); hash_fn->update(BigInt::encode_1363(in2, pad_to)); return BigInt::decode(hash_fn->final()); } BigInt compute_x(const std::string& hash_id, const std::string& identifier, const std::string& password, const std::vector& salt) { std::unique_ptr hash_fn(HashFunction::create_or_throw(hash_id)); hash_fn->update(identifier); hash_fn->update(":"); hash_fn->update(password); secure_vector inner_h = hash_fn->final(); hash_fn->update(salt); hash_fn->update(inner_h); secure_vector outer_h = hash_fn->final(); return BigInt::decode(outer_h); } } std::string srp6_group_identifier(const BigInt& N, const BigInt& g) { /* This function assumes that only one 'standard' SRP parameter set has been defined for a particular bitsize. As of this writing that is the case. */ try { const std::string group_name = "modp/srp/" + std::to_string(N.bits()); DL_Group group(group_name); if(group.get_p() == N && group.get_g() == g) return group_name; } catch(...) { } // If we didn't return, the group was unknown or did not match throw Invalid_Argument("Invalid or unknown SRP group parameters"); } std::pair srp6_client_agree(const std::string& identifier, const std::string& password, const std::string& group_id, const std::string& hash_id, const std::vector& salt, const BigInt& B, RandomNumberGenerator& rng) { DL_Group group(group_id); const size_t a_bits = group.exponent_bits(); return srp6_client_agree(identifier, password, group, hash_id, salt, B, a_bits, rng); } std::pair srp6_client_agree(const std::string& identifier, const std::string& password, const DL_Group& group, const std::string& hash_id, const std::vector& salt, const BigInt& B, const size_t a_bits, RandomNumberGenerator& rng) { const BigInt& g = group.get_g(); const BigInt& p = group.get_p(); const size_t p_bytes = group.p_bytes(); if(B <= 0 || B >= p) throw Decoding_Error("Invalid SRP parameter from server"); const BigInt k = hash_seq(hash_id, p_bytes, p, g); const BigInt a(rng, a_bits); const BigInt A = group.power_g_p(a, a_bits); const BigInt u = hash_seq(hash_id, p_bytes, A, B); const BigInt x = compute_x(hash_id, identifier, password, salt); const BigInt S = power_mod(group.mod_p(B - (k * power_mod(g, x, p))), group.mod_p(a + (u * x)), p); const SymmetricKey Sk(BigInt::encode_1363(S, p_bytes)); return std::make_pair(A, Sk); } BigInt generate_srp6_verifier(const std::string& identifier, const std::string& password, const std::vector& salt, const std::string& group_id, const std::string& hash_id) { DL_Group group(group_id); return generate_srp6_verifier(identifier, password, salt, group, hash_id); } BigInt generate_srp6_verifier(const std::string& identifier, const std::string& password, const std::vector& salt, const DL_Group& group, const std::string& hash_id) { const BigInt x = compute_x(hash_id, identifier, password, salt); // FIXME: x should be size of hash fn so avoid computing x.bits() here return group.power_g_p(x, x.bits()); } BigInt SRP6_Server_Session::step1(const BigInt& v, const std::string& group_id, const std::string& hash_id, RandomNumberGenerator& rng) { DL_Group group(group_id); const size_t b_bits = group.exponent_bits(); return this->step1(v, group, hash_id, b_bits, rng); } BigInt SRP6_Server_Session::step1(const BigInt& v, const DL_Group& group, const std::string& hash_id, size_t b_bits, RandomNumberGenerator& rng) { const BigInt& g = group.get_g(); const BigInt& p = group.get_p(); m_p_bytes = p.bytes(); m_v = v; m_b = BigInt(rng, b_bits); m_p = p; m_hash_id = hash_id; const BigInt k = hash_seq(hash_id, m_p_bytes, p, g); m_B = group.mod_p(v*k + group.power_g_p(m_b, b_bits)); return m_B; } SymmetricKey SRP6_Server_Session::step2(const BigInt& A) { if(A <= 0 || A >= m_p) throw Decoding_Error("Invalid SRP parameter from client"); const BigInt u = hash_seq(m_hash_id, m_p_bytes, A, m_B); const BigInt S = power_mod(A * power_mod(m_v, u, m_p), m_b, m_p); return BigInt::encode_1363(S, m_p_bytes); } } /* * (C) 2016,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_SYSTEM_RNG) #endif namespace Botan { void Stateful_RNG::clear() { lock_guard_type lock(m_mutex); m_reseed_counter = 0; m_last_pid = 0; clear_state(); } void Stateful_RNG::force_reseed() { lock_guard_type lock(m_mutex); m_reseed_counter = 0; } bool Stateful_RNG::is_seeded() const { lock_guard_type lock(m_mutex); return m_reseed_counter > 0; } void Stateful_RNG::add_entropy(const uint8_t input[], size_t input_len) { lock_guard_type lock(m_mutex); update(input, input_len); if(8*input_len >= security_level()) { reset_reseed_counter(); } } void Stateful_RNG::initialize_with(const uint8_t input[], size_t len) { lock_guard_type lock(m_mutex); clear(); add_entropy(input, len); } void Stateful_RNG::randomize(uint8_t output[], size_t output_len) { randomize_with_input(output, output_len, nullptr, 0); } void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len) { uint8_t additional_input[20] = { 0 }; store_le(OS::get_high_resolution_clock(), additional_input); #if defined(BOTAN_HAS_SYSTEM_RNG) System_RNG system_rng; system_rng.randomize(additional_input + 8, sizeof(additional_input) - 8); #else store_le(OS::get_system_timestamp_ns(), additional_input + 8); store_le(OS::get_process_id(), additional_input + 16); #endif randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); } void Stateful_RNG::randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) { if(output_len == 0) return; lock_guard_type lock(m_mutex); const size_t max_per_request = max_number_of_bytes_per_request(); if(max_per_request == 0) // no limit { reseed_check(); this->generate_output(output, output_len, input, input_len); } else { while(output_len > 0) { const size_t this_req = std::min(max_per_request, output_len); /* * We split the request into several requests to the underlying DRBG but * pass the input to each invocation. It might be more sensible to only * provide it for the first invocation, however between 2.0 and 2.15 * HMAC_DRBG always provided it for all requests so retain that here. */ reseed_check(); this->generate_output(output, this_req, input, input_len); output += this_req; output_len -= this_req; } } } size_t Stateful_RNG::reseed(Entropy_Sources& srcs, size_t poll_bits, std::chrono::milliseconds poll_timeout) { lock_guard_type lock(m_mutex); const size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout); if(bits_collected >= security_level()) { reset_reseed_counter(); } return bits_collected; } void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) { lock_guard_type lock(m_mutex); RandomNumberGenerator::reseed_from_rng(rng, poll_bits); if(poll_bits >= security_level()) { reset_reseed_counter(); } } void Stateful_RNG::reset_reseed_counter() { // Lock is held whenever this function is called m_reseed_counter = 1; } void Stateful_RNG::reseed_check() { // Lock is held whenever this function is called const uint32_t cur_pid = OS::get_process_id(); const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid); if(is_seeded() == false || fork_detected || (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval)) { m_reseed_counter = 0; m_last_pid = cur_pid; if(m_underlying_rng) { reseed_from_rng(*m_underlying_rng, security_level()); } if(m_entropy_sources) { reseed(*m_entropy_sources, security_level()); } if(!is_seeded()) { if(fork_detected) throw Invalid_State("Detected use of fork but cannot reseed DRBG"); else throw PRNG_Unseeded(name()); } } else { BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded"); m_reseed_counter += 1; } } } /* * Stream Ciphers * (C) 2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_CHACHA) #endif #if defined(BOTAN_HAS_SALSA20) #endif #if defined(BOTAN_HAS_SHAKE_CIPHER) #endif #if defined(BOTAN_HAS_CTR_BE) #endif #if defined(BOTAN_HAS_OFB) #endif #if defined(BOTAN_HAS_RC4) #endif #if defined(BOTAN_HAS_OPENSSL) #endif namespace Botan { std::unique_ptr StreamCipher::create(const std::string& algo_spec, const std::string& provider) { const SCAN_Name req(algo_spec); #if defined(BOTAN_HAS_CTR_BE) if((req.algo_name() == "CTR-BE" || req.algo_name() == "CTR") && req.arg_count_between(1,2)) { if(provider.empty() || provider == "base") { auto cipher = BlockCipher::create(req.arg(0)); if(cipher) { size_t ctr_size = req.arg_as_integer(1, cipher->block_size()); return std::unique_ptr(new CTR_BE(cipher.release(), ctr_size)); } } } #endif #if defined(BOTAN_HAS_CHACHA) if(req.algo_name() == "ChaCha") { if(provider.empty() || provider == "base") return std::unique_ptr(new ChaCha(req.arg_as_integer(0, 20))); } if(req.algo_name() == "ChaCha20") { if(provider.empty() || provider == "base") return std::unique_ptr(new ChaCha(20)); } #endif #if defined(BOTAN_HAS_SALSA20) if(req.algo_name() == "Salsa20") { if(provider.empty() || provider == "base") return std::unique_ptr(new Salsa20); } #endif #if defined(BOTAN_HAS_SHAKE_CIPHER) if(req.algo_name() == "SHAKE-128" || req.algo_name() == "SHAKE-128-XOF") { if(provider.empty() || provider == "base") return std::unique_ptr(new SHAKE_128_Cipher); } #endif #if defined(BOTAN_HAS_OFB) if(req.algo_name() == "OFB" && req.arg_count() == 1) { if(provider.empty() || provider == "base") { if(auto c = BlockCipher::create(req.arg(0))) return std::unique_ptr(new OFB(c.release())); } } #endif #if defined(BOTAN_HAS_RC4) if(req.algo_name() == "RC4" || req.algo_name() == "ARC4" || req.algo_name() == "MARK-4") { const size_t skip = (req.algo_name() == "MARK-4") ? 256 : req.arg_as_integer(0, 0); #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { return std::unique_ptr(make_openssl_rc4(skip)); } #endif if(provider.empty() || provider == "base") { return std::unique_ptr(new RC4(skip)); } } #endif BOTAN_UNUSED(req); BOTAN_UNUSED(provider); return nullptr; } //static std::unique_ptr StreamCipher::create_or_throw(const std::string& algo, const std::string& provider) { if(auto sc = StreamCipher::create(algo, provider)) { return sc; } throw Lookup_Error("Stream cipher", algo, provider); } std::vector StreamCipher::providers(const std::string& algo_spec) { return probe_providers_of(algo_spec, {"base", "openssl"}); } } /* * Streebog * (C) 2017 Ribose Inc. * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { extern const uint64_t STREEBOG_Ax[8][256]; extern const uint64_t STREEBOG_C[12][8]; std::unique_ptr Streebog::copy_state() const { return std::unique_ptr(new Streebog(*this)); } Streebog::Streebog(size_t output_bits) : m_output_bits(output_bits), m_count(0), m_position(0), m_buffer(64), m_h(8), m_S(8) { if(output_bits != 256 && output_bits != 512) throw Invalid_Argument("Streebog: Invalid output length " + std::to_string(output_bits)); clear(); } std::string Streebog::name() const { return "Streebog-" + std::to_string(m_output_bits); } /* * Clear memory of sensitive data */ void Streebog::clear() { m_count = 0; m_position = 0; zeroise(m_buffer); zeroise(m_S); const uint64_t fill = (m_output_bits == 512) ? 0 : 0x0101010101010101; std::fill(m_h.begin(), m_h.end(), fill); } /* * Update the hash */ void Streebog::add_data(const uint8_t input[], size_t length) { const size_t block_size = m_buffer.size(); if(m_position) { buffer_insert(m_buffer, m_position, input, length); if(m_position + length >= block_size) { compress(m_buffer.data()); m_count += 512; input += (block_size - m_position); length -= (block_size - m_position); m_position = 0; } } const size_t full_blocks = length / block_size; const size_t remaining = length % block_size; for(size_t i = 0; i != full_blocks; ++i) { compress(input + block_size * i); m_count += 512; } buffer_insert(m_buffer, m_position, input + full_blocks * block_size, remaining); m_position += remaining; } /* * Finalize a hash */ void Streebog::final_result(uint8_t output[]) { m_buffer[m_position++] = 0x01; if(m_position != m_buffer.size()) clear_mem(&m_buffer[m_position], m_buffer.size() - m_position); compress(m_buffer.data()); m_count += (m_position - 1) * 8; zeroise(m_buffer); store_le(m_count, m_buffer.data()); compress(m_buffer.data(), true); compress_64(m_S.data(), true); // FIXME std::memcpy(output, &m_h[8 - output_length() / 8], output_length()); clear(); } namespace { inline uint64_t force_le(uint64_t x) { #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) return x; #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) return reverse_bytes(x); #else store_le(x, reinterpret_cast(&x)); return x; #endif } inline void lps(uint64_t block[8]) { uint8_t r[64]; // FIXME std::memcpy(r, block, 64); for(int i = 0; i < 8; ++i) { block[i] = force_le(STREEBOG_Ax[0][r[i + 0*8]]) ^ force_le(STREEBOG_Ax[1][r[i + 1*8]]) ^ force_le(STREEBOG_Ax[2][r[i + 2*8]]) ^ force_le(STREEBOG_Ax[3][r[i + 3*8]]) ^ force_le(STREEBOG_Ax[4][r[i + 4*8]]) ^ force_le(STREEBOG_Ax[5][r[i + 5*8]]) ^ force_le(STREEBOG_Ax[6][r[i + 6*8]]) ^ force_le(STREEBOG_Ax[7][r[i + 7*8]]); } } } //namespace void Streebog::compress(const uint8_t input[], bool last_block) { uint64_t M[8]; std::memcpy(M, input, 64); compress_64(M, last_block); } void Streebog::compress_64(const uint64_t M[], bool last_block) { uint64_t N = force_le(last_block ? 0ULL : m_count); uint64_t hN[8]; uint64_t A[8]; copy_mem(hN, m_h.data(), 8); hN[0] ^= N; lps(hN); copy_mem(A, hN, 8); for(size_t i = 0; i != 8; ++i) { hN[i] ^= M[i]; } for(size_t i = 0; i < 12; ++i) { for(size_t j = 0; j != 8; ++j) A[j] ^= force_le(STREEBOG_C[i][j]); lps(A); lps(hN); for(size_t j = 0; j != 8; ++j) hN[j] ^= A[j]; } for(size_t i = 0; i != 8; ++i) { m_h[i] ^= hN[i] ^ M[i]; } if(!last_block) { uint64_t carry = 0; for(int i = 0; i < 8; i++) { const uint64_t m = force_le(M[i]); const uint64_t hi = force_le(m_S[i]); const uint64_t t = hi + m + carry; m_S[i] = force_le(t); if(t != m) carry = (t < m); } } } } /* * Derived from: * https://github.com/degtyarevalexey/streebog * * Copyright (c) 2013, Alexey Degtyarev . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ namespace Botan { extern const uint64_t STREEBOG_Ax[8][256] = { { 0xd01f715b5c7ef8e6ULL, 0x16fa240980778325ULL, 0xa8a42e857ee049c8ULL, 0x6ac1068fa186465bULL, 0x6e417bd7a2e9320bULL, 0x665c8167a437daabULL, 0x7666681aa89617f6ULL, 0x4b959163700bdcf5ULL, 0xf14be6b78df36248ULL, 0xc585bd689a625cffULL, 0x9557d7fca67d82cbULL, 0x89f0b969af6dd366ULL, 0xb0833d48749f6c35ULL, 0xa1998c23b1ecbc7cULL, 0x8d70c431ac02a736ULL, 0xd6dfbc2fd0a8b69eULL, 0x37aeb3e551fa198bULL, 0x0b7d128a40b5cf9cULL, 0x5a8f2008b5780cbcULL, 0xedec882284e333e5ULL, 0xd25fc177d3c7c2ceULL, 0x5e0f5d50b61778ecULL, 0x1d873683c0c24cb9ULL, 0xad040bcbb45d208cULL, 0x2f89a0285b853c76ULL, 0x5732fff6791b8d58ULL, 0x3e9311439ef6ec3fULL, 0xc9183a809fd3c00fULL, 0x83adf3f5260a01eeULL, 0xa6791941f4e8ef10ULL, 0x103ae97d0ca1cd5dULL, 0x2ce948121dee1b4aULL, 0x39738421dbf2bf53ULL, 0x093da2a6cf0cf5b4ULL, 0xcd9847d89cbcb45fULL, 0xf9561c078b2d8ae8ULL, 0x9c6a755a6971777fULL, 0xbc1ebaa0712ef0c5ULL, 0x72e61542abf963a6ULL, 0x78bb5fde229eb12eULL, 0x14ba94250fceb90dULL, 0x844d6697630e5282ULL, 0x98ea08026a1e032fULL, 0xf06bbea144217f5cULL, 0xdb6263d11ccb377aULL, 0x641c314b2b8ee083ULL, 0x320e96ab9b4770cfULL, 0x1ee7deb986a96b85ULL, 0xe96cf57a878c47b5ULL, 0xfdd6615f8842feb8ULL, 0xc83862965601dd1bULL, 0x2ea9f83e92572162ULL, 0xf876441142ff97fcULL, 0xeb2c455608357d9dULL, 0x5612a7e0b0c9904cULL, 0x6c01cbfb2d500823ULL, 0x4548a6a7fa037a2dULL, 0xabc4c6bf388b6ef4ULL, 0xbade77d4fdf8bebdULL, 0x799b07c8eb4cac3aULL, 0x0c9d87e805b19cf0ULL, 0xcb588aac106afa27ULL, 0xea0c1d40c1e76089ULL, 0x2869354a1e816f1aULL, 0xff96d17307fbc490ULL, 0x9f0a9d602f1a5043ULL, 0x96373fc6e016a5f7ULL, 0x5292dab8b3a6e41cULL, 0x9b8ae0382c752413ULL, 0x4f15ec3b7364a8a5ULL, 0x3fb349555724f12bULL, 0xc7c50d4415db66d7ULL, 0x92b7429ee379d1a7ULL, 0xd37f99611a15dfdaULL, 0x231427c05e34a086ULL, 0xa439a96d7b51d538ULL, 0xb403401077f01865ULL, 0xdda2aea5901d7902ULL, 0x0a5d4a9c8967d288ULL, 0xc265280adf660f93ULL, 0x8bb0094520d4e94eULL, 0x2a29856691385532ULL, 0x42a833c5bf072941ULL, 0x73c64d54622b7eb2ULL, 0x07e095624504536cULL, 0x8a905153e906f45aULL, 0x6f6123c16b3b2f1fULL, 0xc6e55552dc097bc3ULL, 0x4468feb133d16739ULL, 0xe211e7f0c7398829ULL, 0xa2f96419f7879b40ULL, 0x19074bdbc3ad38e9ULL, 0xf4ebc3f9474e0b0cULL, 0x43886bd376d53455ULL, 0xd8028beb5aa01046ULL, 0x51f23282f5cdc320ULL, 0xe7b1c2be0d84e16dULL, 0x081dfab006dee8a0ULL, 0x3b33340d544b857bULL, 0x7f5bcabc679ae242ULL, 0x0edd37c48a08a6d8ULL, 0x81ed43d9a9b33bc6ULL, 0xb1a3655ebd4d7121ULL, 0x69a1eeb5e7ed6167ULL, 0xf6ab73d5c8f73124ULL, 0x1a67a3e185c61fd5ULL, 0x2dc91004d43c065eULL, 0x0240b02c8fb93a28ULL, 0x90f7f2b26cc0eb8fULL, 0x3cd3a16f114fd617ULL, 0xaae49ea9f15973e0ULL, 0x06c0cd748cd64e78ULL, 0xda423bc7d5192a6eULL, 0xc345701c16b41287ULL, 0x6d2193ede4821537ULL, 0xfcf639494190e3acULL, 0x7c3b228621f1c57eULL, 0xfb16ac2b0494b0c0ULL, 0xbf7e529a3745d7f9ULL, 0x6881b6a32e3f7c73ULL, 0xca78d2bad9b8e733ULL, 0xbbfe2fc2342aa3a9ULL, 0x0dbddffecc6381e4ULL, 0x70a6a56e2440598eULL, 0xe4d12a844befc651ULL, 0x8c509c2765d0ba22ULL, 0xee8c6018c28814d9ULL, 0x17da7c1f49a59e31ULL, 0x609c4c1328e194d3ULL, 0xb3e3d57232f44b09ULL, 0x91d7aaa4a512f69bULL, 0x0ffd6fd243dabbccULL, 0x50d26a943c1fde34ULL, 0x6be15e9968545b4fULL, 0x94778fea6faf9fdfULL, 0x2b09dd7058ea4826ULL, 0x677cd9716de5c7bfULL, 0x49d5214fffb2e6ddULL, 0x0360e83a466b273cULL, 0x1fc786af4f7b7691ULL, 0xa0b9d435783ea168ULL, 0xd49f0c035f118cb6ULL, 0x01205816c9d21d14ULL, 0xac2453dd7d8f3d98ULL, 0x545217cc3f70aa64ULL, 0x26b4028e9489c9c2ULL, 0xdec2469fd6765e3eULL, 0x04807d58036f7450ULL, 0xe5f17292823ddb45ULL, 0xf30b569b024a5860ULL, 0x62dcfc3fa758aefbULL, 0xe84cad6c4e5e5aa1ULL, 0xccb81fce556ea94bULL, 0x53b282ae7a74f908ULL, 0x1b47fbf74c1402c1ULL, 0x368eebf39828049fULL, 0x7afbeff2ad278b06ULL, 0xbe5e0a8cfe97caedULL, 0xcfd8f7f413058e77ULL, 0xf78b2bc301252c30ULL, 0x4d555c17fcdd928dULL, 0x5f2f05467fc565f8ULL, 0x24f4b2a21b30f3eaULL, 0x860dd6bbecb768aaULL, 0x4c750401350f8f99ULL, 0x0000000000000000ULL, 0xecccd0344d312ef1ULL, 0xb5231806be220571ULL, 0xc105c030990d28afULL, 0x653c695de25cfd97ULL, 0x159acc33c61ca419ULL, 0xb89ec7f872418495ULL, 0xa9847693b73254dcULL, 0x58cf90243ac13694ULL, 0x59efc832f3132b80ULL, 0x5c4fed7c39ae42c4ULL, 0x828dabe3efd81cfaULL, 0xd13f294d95ace5f2ULL, 0x7d1b7a90e823d86aULL, 0xb643f03cf849224dULL, 0x3df3f979d89dcb03ULL, 0x7426d836272f2ddeULL, 0xdfe21e891fa4432aULL, 0x3a136c1b9d99986fULL, 0xfa36f43dcd46add4ULL, 0xc025982650df35bbULL, 0x856d3e81aadc4f96ULL, 0xc4a5e57e53b041ebULL, 0x4708168b75ba4005ULL, 0xaf44bbe73be41aa4ULL, 0x971767d029c4b8e3ULL, 0xb9be9feebb939981ULL, 0x215497ecd18d9aaeULL, 0x316e7e91dd2c57f3ULL, 0xcef8afe2dad79363ULL, 0x3853dc371220a247ULL, 0x35ee03c9de4323a3ULL, 0xe6919aa8c456fc79ULL, 0xe05157dc4880b201ULL, 0x7bdbb7e464f59612ULL, 0x127a59518318f775ULL, 0x332ecebd52956ddbULL, 0x8f30741d23bb9d1eULL, 0xd922d3fd93720d52ULL, 0x7746300c61440ae2ULL, 0x25d4eab4d2e2eefeULL, 0x75068020eefd30caULL, 0x135a01474acaea61ULL, 0x304e268714fe4ae7ULL, 0xa519f17bb283c82cULL, 0xdc82f6b359cf6416ULL, 0x5baf781e7caa11a8ULL, 0xb2c38d64fb26561dULL, 0x34ce5bdf17913eb7ULL, 0x5d6fb56af07c5fd0ULL, 0x182713cd0a7f25fdULL, 0x9e2ac576e6c84d57ULL, 0x9aaab82ee5a73907ULL, 0xa3d93c0f3e558654ULL, 0x7e7b92aaae48ff56ULL, 0x872d8ead256575beULL, 0x41c8dbfff96c0e7dULL, 0x99ca5014a3cc1e3bULL, 0x40e883e930be1369ULL, 0x1ca76e95091051adULL, 0x4e35b42dbab6b5b1ULL, 0x05a0254ecabd6944ULL, 0xe1710fca8152af15ULL, 0xf22b0e8dcb984574ULL, 0xb763a82a319b3f59ULL, 0x63fca4296e8ab3efULL, 0x9d4a2d4ca0a36a6bULL, 0xe331bfe60eeb953dULL, 0xd5bf541596c391a2ULL, 0xf5cb9bef8e9c1618ULL, 0x46284e9dbc685d11ULL, 0x2074cffa185f87baULL, 0xbd3ee2b6b8fcedd1ULL, 0xae64e3f1f23607b0ULL, 0xfeb68965ce29d984ULL, 0x55724fdaf6a2b770ULL, 0x29496d5cd753720eULL, 0xa75941573d3af204ULL, 0x8e102c0bea69800aULL, 0x111ab16bc573d049ULL, 0xd7ffe439197aab8aULL, 0xefac380e0b5a09cdULL, 0x48f579593660fbc9ULL, 0x22347fd697e6bd92ULL, 0x61bc1405e13389c7ULL, 0x4ab5c975b9d9c1e1ULL, 0x80cd1bcf606126d2ULL, 0x7186fd78ed92449aULL, 0x93971a882aabccb3ULL, 0x88d0e17f66bfce72ULL, 0x27945a985d5bd4d6ULL }, { 0xde553f8c05a811c8ULL, 0x1906b59631b4f565ULL, 0x436e70d6b1964ff7ULL, 0x36d343cb8b1e9d85ULL, 0x843dfacc858aab5aULL, 0xfdfc95c299bfc7f9ULL, 0x0f634bdea1d51fa2ULL, 0x6d458b3b76efb3cdULL, 0x85c3f77cf8593f80ULL, 0x3c91315fbe737cb2ULL, 0x2148b03366ace398ULL, 0x18f8b8264c6761bfULL, 0xc830c1c495c9fb0fULL, 0x981a76102086a0aaULL, 0xaa16012142f35760ULL, 0x35cc54060c763cf6ULL, 0x42907d66cc45db2dULL, 0x8203d44b965af4bcULL, 0x3d6f3cefc3a0e868ULL, 0xbc73ff69d292bda7ULL, 0x8722ed0102e20a29ULL, 0x8f8185e8cd34deb7ULL, 0x9b0561dda7ee01d9ULL, 0x5335a0193227fad6ULL, 0xc9cecc74e81a6fd5ULL, 0x54f5832e5c2431eaULL, 0x99e47ba05d553470ULL, 0xf7bee756acd226ceULL, 0x384e05a5571816fdULL, 0xd1367452a47d0e6aULL, 0xf29fde1c386ad85bULL, 0x320c77316275f7caULL, 0xd0c879e2d9ae9ab0ULL, 0xdb7406c69110ef5dULL, 0x45505e51a2461011ULL, 0xfc029872e46c5323ULL, 0xfa3cb6f5f7bc0cc5ULL, 0x031f17cd8768a173ULL, 0xbd8df2d9af41297dULL, 0x9d3b4f5ab43e5e3fULL, 0x4071671b36feee84ULL, 0x716207e7d3e3b83dULL, 0x48d20ff2f9283a1aULL, 0x27769eb4757cbc7eULL, 0x5c56ebc793f2e574ULL, 0xa48b474f9ef5dc18ULL, 0x52cbada94ff46e0cULL, 0x60c7da982d8199c6ULL, 0x0e9d466edc068b78ULL, 0x4eec2175eaf865fcULL, 0x550b8e9e21f7a530ULL, 0x6b7ba5bc653fec2bULL, 0x5eb7f1ba6949d0ddULL, 0x57ea94e3db4c9099ULL, 0xf640eae6d101b214ULL, 0xdd4a284182c0b0bbULL, 0xff1d8fbf6304f250ULL, 0xb8accb933bf9d7e8ULL, 0xe8867c478eb68c4dULL, 0x3f8e2692391bddc1ULL, 0xcb2fd60912a15a7cULL, 0xaec935dbab983d2fULL, 0xf55ffd2b56691367ULL, 0x80e2ce366ce1c115ULL, 0x179bf3f8edb27e1dULL, 0x01fe0db07dd394daULL, 0xda8a0b76ecc37b87ULL, 0x44ae53e1df9584cbULL, 0xb310b4b77347a205ULL, 0xdfab323c787b8512ULL, 0x3b511268d070b78eULL, 0x65e6e3d2b9396753ULL, 0x6864b271e2574d58ULL, 0x259784c98fc789d7ULL, 0x02e11a7dfabb35a9ULL, 0x8841a6dfa337158bULL, 0x7ade78c39b5dcdd0ULL, 0xb7cf804d9a2cc84aULL, 0x20b6bd831b7f7742ULL, 0x75bd331d3a88d272ULL, 0x418f6aab4b2d7a5eULL, 0xd9951cbb6babdaf4ULL, 0xb6318dfde7ff5c90ULL, 0x1f389b112264aa83ULL, 0x492c024284fbaec0ULL, 0xe33a0363c608f9a0ULL, 0x2688930408af28a4ULL, 0xc7538a1a341ce4adULL, 0x5da8e677ee2171aeULL, 0x8c9e92254a5c7fc4ULL, 0x63d8cd55aae938b5ULL, 0x29ebd8daa97a3706ULL, 0x959827b37be88aa1ULL, 0x1484e4356adadf6eULL, 0xa7945082199d7d6bULL, 0xbf6ce8a455fa1cd4ULL, 0x9cc542eac9edcae5ULL, 0x79c16f0e1c356ca3ULL, 0x89bfab6fdee48151ULL, 0xd4174d1830c5f0ffULL, 0x9258048415eb419dULL, 0x6139d72850520d1cULL, 0x6a85a80c18ec78f1ULL, 0xcd11f88e0171059aULL, 0xcceff53e7ca29140ULL, 0xd229639f2315af19ULL, 0x90b91ef9ef507434ULL, 0x5977d28d074a1be1ULL, 0x311360fce51d56b9ULL, 0xc093a92d5a1f2f91ULL, 0x1a19a25bb6dc5416ULL, 0xeb996b8a09de2d3eULL, 0xfee3820f1ed7668aULL, 0xd7085ad5b7ad518cULL, 0x7fff41890fe53345ULL, 0xec5948bd67dde602ULL, 0x2fd5f65dbaaa68e0ULL, 0xa5754affe32648c2ULL, 0xf8ddac880d07396cULL, 0x6fa491468c548664ULL, 0x0c7c5c1326bdbed1ULL, 0x4a33158f03930fb3ULL, 0x699abfc19f84d982ULL, 0xe4fa2054a80b329cULL, 0x6707f9af438252faULL, 0x08a368e9cfd6d49eULL, 0x47b1442c58fd25b8ULL, 0xbbb3dc5ebc91769bULL, 0x1665fe489061eac7ULL, 0x33f27a811fa66310ULL, 0x93a609346838d547ULL, 0x30ed6d4c98cec263ULL, 0x1dd9816cd8df9f2aULL, 0x94662a03063b1e7bULL, 0x83fdd9fbeb896066ULL, 0x7b207573e68e590aULL, 0x5f49fc0a149a4407ULL, 0x343259b671a5a82cULL, 0xfbc2bb458a6f981fULL, 0xc272b350a0a41a38ULL, 0x3aaf1fd8ada32354ULL, 0x6cbb868b0b3c2717ULL, 0xa2b569c88d2583feULL, 0xf180c9d1bf027928ULL, 0xaf37386bd64ba9f5ULL, 0x12bacab2790a8088ULL, 0x4c0d3b0810435055ULL, 0xb2eeb9070e9436dfULL, 0xc5b29067cea7d104ULL, 0xdcb425f1ff132461ULL, 0x4f122cc5972bf126ULL, 0xac282fa651230886ULL, 0xe7e537992f6393efULL, 0xe61b3a2952b00735ULL, 0x709c0a57ae302ce7ULL, 0xe02514ae416058d3ULL, 0xc44c9dd7b37445deULL, 0x5a68c5408022ba92ULL, 0x1c278cdca50c0bf0ULL, 0x6e5a9cf6f18712beULL, 0x86dce0b17f319ef3ULL, 0x2d34ec2040115d49ULL, 0x4bcd183f7e409b69ULL, 0x2815d56ad4a9a3dcULL, 0x24698979f2141d0dULL, 0x0000000000000000ULL, 0x1ec696a15fb73e59ULL, 0xd86b110b16784e2eULL, 0x8e7f8858b0e74a6dULL, 0x063e2e8713d05fe6ULL, 0xe2c40ed3bbdb6d7aULL, 0xb1f1aeca89fc97acULL, 0xe1db191e3cb3cc09ULL, 0x6418ee62c4eaf389ULL, 0xc6ad87aa49cf7077ULL, 0xd6f65765ca7ec556ULL, 0x9afb6c6dda3d9503ULL, 0x7ce05644888d9236ULL, 0x8d609f95378feb1eULL, 0x23a9aa4e9c17d631ULL, 0x6226c0e5d73aac6fULL, 0x56149953a69f0443ULL, 0xeeb852c09d66d3abULL, 0x2b0ac2a753c102afULL, 0x07c023376e03cb3cULL, 0x2ccae1903dc2c993ULL, 0xd3d76e2f5ec63bc3ULL, 0x9e2458973356ff4cULL, 0xa66a5d32644ee9b1ULL, 0x0a427294356de137ULL, 0x783f62be61e6f879ULL, 0x1344c70204d91452ULL, 0x5b96c8f0fdf12e48ULL, 0xa90916ecc59bf613ULL, 0xbe92e5142829880eULL, 0x727d102a548b194eULL, 0x1be7afebcb0fc0ccULL, 0x3e702b2244c8491bULL, 0xd5e940a84d166425ULL, 0x66f9f41f3e51c620ULL, 0xabe80c913f20c3baULL, 0xf07ec461c2d1edf2ULL, 0xf361d3ac45b94c81ULL, 0x0521394a94b8fe95ULL, 0xadd622162cf09c5cULL, 0xe97871f7f3651897ULL, 0xf4a1f09b2bba87bdULL, 0x095d6559b2054044ULL, 0x0bbc7f2448be75edULL, 0x2af4cf172e129675ULL, 0x157ae98517094bb4ULL, 0x9fda55274e856b96ULL, 0x914713499283e0eeULL, 0xb952c623462a4332ULL, 0x74433ead475b46a8ULL, 0x8b5eb112245fb4f8ULL, 0xa34b6478f0f61724ULL, 0x11a5dd7ffe6221fbULL, 0xc16da49d27ccbb4bULL, 0x76a224d0bde07301ULL, 0x8aa0bca2598c2022ULL, 0x4df336b86d90c48fULL, 0xea67663a740db9e4ULL, 0xef465f70e0b54771ULL, 0x39b008152acb8227ULL, 0x7d1e5bf4f55e06ecULL, 0x105bd0cf83b1b521ULL, 0x775c2960c033e7dbULL, 0x7e014c397236a79fULL, 0x811cc386113255cfULL, 0xeda7450d1a0e72d8ULL, 0x5889df3d7a998f3bULL, 0x2e2bfbedc779fc3aULL, 0xce0eef438619a4e9ULL, 0x372d4e7bf6cd095fULL, 0x04df34fae96b6a4fULL, 0xf923a13870d4adb6ULL, 0xa1aa7e050a4d228dULL, 0xa8f71b5cb84862c9ULL, 0xb52e9a306097fde3ULL, 0x0d8251a35b6e2a0bULL, 0x2257a7fee1c442ebULL, 0x73831d9a29588d94ULL, 0x51d4ba64c89ccf7fULL, 0x502ab7d4b54f5ba5ULL, 0x97793dce8153bf08ULL, 0xe5042de4d5d8a646ULL, 0x9687307efc802bd2ULL, 0xa05473b5779eb657ULL, 0xb4d097801d446939ULL, 0xcff0e2f3fbca3033ULL, 0xc38cbee0dd778ee2ULL, 0x464f499c252eb162ULL, 0xcad1dbb96f72cea6ULL, 0xba4dd1eec142e241ULL, 0xb00fa37af42f0376ULL }, { 0xcce4cd3aa968b245ULL, 0x089d5484e80b7fafULL, 0x638246c1b3548304ULL, 0xd2fe0ec8c2355492ULL, 0xa7fbdf7ff2374eeeULL, 0x4df1600c92337a16ULL, 0x84e503ea523b12fbULL, 0x0790bbfd53ab0c4aULL, 0x198a780f38f6ea9dULL, 0x2ab30c8f55ec48cbULL, 0xe0f7fed6b2c49db5ULL, 0xb6ecf3f422cadbdcULL, 0x409c9a541358df11ULL, 0xd3ce8a56dfde3fe3ULL, 0xc3e9224312c8c1a0ULL, 0x0d6dfa58816ba507ULL, 0xddf3e1b179952777ULL, 0x04c02a42748bb1d9ULL, 0x94c2abff9f2decb8ULL, 0x4f91752da8f8acf4ULL, 0x78682befb169bf7bULL, 0xe1c77a48af2ff6c4ULL, 0x0c5d7ec69c80ce76ULL, 0x4cc1e4928fd81167ULL, 0xfeed3d24d9997b62ULL, 0x518bb6dfc3a54a23ULL, 0x6dbf2d26151f9b90ULL, 0xb5bc624b05ea664fULL, 0xe86aaa525acfe21aULL, 0x4801ced0fb53a0beULL, 0xc91463e6c00868edULL, 0x1027a815cd16fe43ULL, 0xf67069a0319204cdULL, 0xb04ccc976c8abce7ULL, 0xc0b9b3fc35e87c33ULL, 0xf380c77c58f2de65ULL, 0x50bb3241de4e2152ULL, 0xdf93f490435ef195ULL, 0xf1e0d25d62390887ULL, 0xaf668bfb1a3c3141ULL, 0xbc11b251f00a7291ULL, 0x73a5eed47e427d47ULL, 0x25bee3f6ee4c3b2eULL, 0x43cc0beb34786282ULL, 0xc824e778dde3039cULL, 0xf97d86d98a327728ULL, 0xf2b043e24519b514ULL, 0xe297ebf7880f4b57ULL, 0x3a94a49a98fab688ULL, 0x868516cb68f0c419ULL, 0xeffa11af0964ee50ULL, 0xa4ab4ec0d517f37dULL, 0xa9c6b498547c567aULL, 0x8e18424f80fbbbb6ULL, 0x0bcdc53bcf2bc23cULL, 0x137739aaea3643d0ULL, 0x2c1333ec1bac2ff0ULL, 0x8d48d3f0a7db0625ULL, 0x1e1ac3f26b5de6d7ULL, 0xf520f81f16b2b95eULL, 0x9f0f6ec450062e84ULL, 0x0130849e1deb6b71ULL, 0xd45e31ab8c7533a9ULL, 0x652279a2fd14e43fULL, 0x3209f01e70f1c927ULL, 0xbe71a770cac1a473ULL, 0x0e3d6be7a64b1894ULL, 0x7ec8148cff29d840ULL, 0xcb7476c7fac3be0fULL, 0x72956a4a63a91636ULL, 0x37f95ec21991138fULL, 0x9e3fea5a4ded45f5ULL, 0x7b38ba50964902e8ULL, 0x222e580bbde73764ULL, 0x61e253e0899f55e6ULL, 0xfc8d2805e352ad80ULL, 0x35994be3235ac56dULL, 0x09add01af5e014deULL, 0x5e8659a6780539c6ULL, 0xb17c48097161d796ULL, 0x026015213acbd6e2ULL, 0xd1ae9f77e515e901ULL, 0xb7dc776a3f21b0adULL, 0xaba6a1b96eb78098ULL, 0x9bcf4486248d9f5dULL, 0x582666c536455efdULL, 0xfdbdac9bfeb9c6f1ULL, 0xc47999be4163cdeaULL, 0x765540081722a7efULL, 0x3e548ed8ec710751ULL, 0x3d041f67cb51bac2ULL, 0x7958af71ac82d40aULL, 0x36c9da5c047a78feULL, 0xed9a048e33af38b2ULL, 0x26ee7249c96c86bdULL, 0x900281bdeba65d61ULL, 0x11172c8bd0fd9532ULL, 0xea0abf73600434f8ULL, 0x42fc8f75299309f3ULL, 0x34a9cf7d3eb1ae1cULL, 0x2b838811480723baULL, 0x5ce64c8742ceef24ULL, 0x1adae9b01fd6570eULL, 0x3c349bf9d6bad1b3ULL, 0x82453c891c7b75c0ULL, 0x97923a40b80d512bULL, 0x4a61dbf1c198765cULL, 0xb48ce6d518010d3eULL, 0xcfb45c858e480fd6ULL, 0xd933cbf30d1e96aeULL, 0xd70ea014ab558e3aULL, 0xc189376228031742ULL, 0x9262949cd16d8b83ULL, 0xeb3a3bed7def5f89ULL, 0x49314a4ee6b8cbcfULL, 0xdcc3652f647e4c06ULL, 0xda635a4c2a3e2b3dULL, 0x470c21a940f3d35bULL, 0x315961a157d174b4ULL, 0x6672e81dda3459acULL, 0x5b76f77a1165e36eULL, 0x445cb01667d36ec8ULL, 0xc5491d205c88a69bULL, 0x456c34887a3805b9ULL, 0xffddb9bac4721013ULL, 0x99af51a71e4649bfULL, 0xa15be01cbc7729d5ULL, 0x52db2760e485f7b0ULL, 0x8c78576eba306d54ULL, 0xae560f6507d75a30ULL, 0x95f22f6182c687c9ULL, 0x71c5fbf54489aba5ULL, 0xca44f259e728d57eULL, 0x88b87d2ccebbdc8dULL, 0xbab18d32be4a15aaULL, 0x8be8ec93e99b611eULL, 0x17b713e89ebdf209ULL, 0xb31c5d284baa0174ULL, 0xeeca9531148f8521ULL, 0xb8d198138481c348ULL, 0x8988f9b2d350b7fcULL, 0xb9e11c8d996aa839ULL, 0x5a4673e40c8e881fULL, 0x1687977683569978ULL, 0xbf4123eed72acf02ULL, 0x4ea1f1b3b513c785ULL, 0xe767452be16f91ffULL, 0x7505d1b730021a7cULL, 0xa59bca5ec8fc980cULL, 0xad069eda20f7e7a3ULL, 0x38f4b1bba231606aULL, 0x60d2d77e94743e97ULL, 0x9affc0183966f42cULL, 0x248e6768f3a7505fULL, 0xcdd449a4b483d934ULL, 0x87b59255751baf68ULL, 0x1bea6d2e023d3c7fULL, 0x6b1f12455b5ffcabULL, 0x743555292de9710dULL, 0xd8034f6d10f5fddfULL, 0xc6198c9f7ba81b08ULL, 0xbb8109aca3a17edbULL, 0xfa2d1766ad12cabbULL, 0xc729080166437079ULL, 0x9c5fff7b77269317ULL, 0x0000000000000000ULL, 0x15d706c9a47624ebULL, 0x6fdf38072fd44d72ULL, 0x5fb6dd3865ee52b7ULL, 0xa33bf53d86bcff37ULL, 0xe657c1b5fc84fa8eULL, 0xaa962527735cebe9ULL, 0x39c43525bfda0b1bULL, 0x204e4d2a872ce186ULL, 0x7a083ece8ba26999ULL, 0x554b9c9db72efbfaULL, 0xb22cd9b656416a05ULL, 0x96a2bedea5e63a5aULL, 0x802529a826b0a322ULL, 0x8115ad363b5bc853ULL, 0x8375b81701901eb1ULL, 0x3069e53f4a3a1fc5ULL, 0xbd2136cfede119e0ULL, 0x18bafc91251d81ecULL, 0x1d4a524d4c7d5b44ULL, 0x05f0aedc6960daa8ULL, 0x29e39d3072ccf558ULL, 0x70f57f6b5962c0d4ULL, 0x989fd53903ad22ceULL, 0xf84d024797d91c59ULL, 0x547b1803aac5908bULL, 0xf0d056c37fd263f6ULL, 0xd56eb535919e58d8ULL, 0x1c7ad6d351963035ULL, 0x2e7326cd2167f912ULL, 0xac361a443d1c8cd2ULL, 0x697f076461942a49ULL, 0x4b515f6fdc731d2dULL, 0x8ad8680df4700a6fULL, 0x41ac1eca0eb3b460ULL, 0x7d988533d80965d3ULL, 0xa8f6300649973d0bULL, 0x7765c4960ac9cc9eULL, 0x7ca801adc5e20ea2ULL, 0xdea3700e5eb59ae4ULL, 0xa06b6482a19c42a4ULL, 0x6a2f96db46b497daULL, 0x27def6d7d487edccULL, 0x463ca5375d18b82aULL, 0xa6cb5be1efdc259fULL, 0x53eba3fef96e9cc1ULL, 0xce84d81b93a364a7ULL, 0xf4107c810b59d22fULL, 0x333974806d1aa256ULL, 0x0f0def79bba073e5ULL, 0x231edc95a00c5c15ULL, 0xe437d494c64f2c6cULL, 0x91320523f64d3610ULL, 0x67426c83c7df32ddULL, 0x6eefbc99323f2603ULL, 0x9d6f7be56acdf866ULL, 0x5916e25b2bae358cULL, 0x7ff89012e2c2b331ULL, 0x035091bf2720bd93ULL, 0x561b0d22900e4669ULL, 0x28d319ae6f279e29ULL, 0x2f43a2533c8c9263ULL, 0xd09e1be9f8fe8270ULL, 0xf740ed3e2c796fbcULL, 0xdb53ded237d5404cULL, 0x62b2c25faebfe875ULL, 0x0afd41a5d2c0a94dULL, 0x6412fd3ce0ff8f4eULL, 0xe3a76f6995e42026ULL, 0x6c8fa9b808f4f0e1ULL, 0xc2d9a6dd0f23aad1ULL, 0x8f28c6d19d10d0c7ULL, 0x85d587744fd0798aULL, 0xa20b71a39b579446ULL, 0x684f83fa7c7f4138ULL, 0xe507500adba4471dULL, 0x3f640a46f19a6c20ULL, 0x1247bd34f7dd28a1ULL, 0x2d23b77206474481ULL, 0x93521002cc86e0f2ULL, 0x572b89bc8de52d18ULL, 0xfb1d93f8b0f9a1caULL, 0xe95a2ecc4724896bULL, 0x3ba420048511ddf9ULL, 0xd63e248ab6bee54bULL, 0x5dd6c8195f258455ULL, 0x06a03f634e40673bULL, 0x1f2a476c76b68da6ULL, 0x217ec9b49ac78af7ULL, 0xecaa80102e4453c3ULL, 0x14e78257b99d4f9aULL }, { 0x20329b2cc87bba05ULL, 0x4f5eb6f86546a531ULL, 0xd4f44775f751b6b1ULL, 0x8266a47b850dfa8bULL, 0xbb986aa15a6ca985ULL, 0xc979eb08f9ae0f99ULL, 0x2da6f447a2375ea1ULL, 0x1e74275dcd7d8576ULL, 0xbc20180a800bc5f8ULL, 0xb4a2f701b2dc65beULL, 0xe726946f981b6d66ULL, 0x48e6c453bf21c94cULL, 0x42cad9930f0a4195ULL, 0xefa47b64aacccd20ULL, 0x71180a8960409a42ULL, 0x8bb3329bf6a44e0cULL, 0xd34c35de2d36daccULL, 0xa92f5b7cbc23dc96ULL, 0xb31a85aa68bb09c3ULL, 0x13e04836a73161d2ULL, 0xb24dfc4129c51d02ULL, 0x8ae44b70b7da5acdULL, 0xe671ed84d96579a7ULL, 0xa4bb3417d66f3832ULL, 0x4572ab38d56d2de8ULL, 0xb1b47761ea47215cULL, 0xe81c09cf70aba15dULL, 0xffbdb872ce7f90acULL, 0xa8782297fd5dc857ULL, 0x0d946f6b6a4ce4a4ULL, 0xe4df1f4f5b995138ULL, 0x9ebc71edca8c5762ULL, 0x0a2c1dc0b02b88d9ULL, 0x3b503c115d9d7b91ULL, 0xc64376a8111ec3a2ULL, 0xcec199a323c963e4ULL, 0xdc76a87ec58616f7ULL, 0x09d596e073a9b487ULL, 0x14583a9d7d560dafULL, 0xf4c6dc593f2a0cb4ULL, 0xdd21d19584f80236ULL, 0x4a4836983ddde1d3ULL, 0xe58866a41ae745f9ULL, 0xf591a5b27e541875ULL, 0x891dc05074586693ULL, 0x5b068c651810a89eULL, 0xa30346bc0c08544fULL, 0x3dbf3751c684032dULL, 0x2a1e86ec785032dcULL, 0xf73f5779fca830eaULL, 0xb60c05ca30204d21ULL, 0x0cc316802b32f065ULL, 0x8770241bdd96be69ULL, 0xb861e18199ee95dbULL, 0xf805cad91418fcd1ULL, 0x29e70dccbbd20e82ULL, 0xc7140f435060d763ULL, 0x0f3a9da0e8b0cc3bULL, 0xa2543f574d76408eULL, 0xbd7761e1c175d139ULL, 0x4b1f4f737ca3f512ULL, 0x6dc2df1f2fc137abULL, 0xf1d05c3967b14856ULL, 0xa742bf3715ed046cULL, 0x654030141d1697edULL, 0x07b872abda676c7dULL, 0x3ce84eba87fa17ecULL, 0xc1fb0403cb79afdfULL, 0x3e46bc7105063f73ULL, 0x278ae987121cd678ULL, 0xa1adb4778ef47cd0ULL, 0x26dd906c5362c2b9ULL, 0x05168060589b44e2ULL, 0xfbfc41f9d79ac08fULL, 0x0e6de44ba9ced8faULL, 0x9feb08068bf243a3ULL, 0x7b341749d06b129bULL, 0x229c69e74a87929aULL, 0xe09ee6c4427c011bULL, 0x5692e30e725c4c3aULL, 0xda99a33e5e9f6e4bULL, 0x353dd85af453a36bULL, 0x25241b4c90e0fee7ULL, 0x5de987258309d022ULL, 0xe230140fc0802984ULL, 0x93281e86a0c0b3c6ULL, 0xf229d719a4337408ULL, 0x6f6c2dd4ad3d1f34ULL, 0x8ea5b2fbae3f0aeeULL, 0x8331dd90c473ee4aULL, 0x346aa1b1b52db7aaULL, 0xdf8f235e06042aa9ULL, 0xcc6f6b68a1354b7bULL, 0x6c95a6f46ebf236aULL, 0x52d31a856bb91c19ULL, 0x1a35ded6d498d555ULL, 0xf37eaef2e54d60c9ULL, 0x72e181a9a3c2a61cULL, 0x98537aad51952fdeULL, 0x16f6c856ffaa2530ULL, 0xd960281e9d1d5215ULL, 0x3a0745fa1ce36f50ULL, 0x0b7b642bf1559c18ULL, 0x59a87eae9aec8001ULL, 0x5e100c05408bec7cULL, 0x0441f98b19e55023ULL, 0xd70dcc5534d38aefULL, 0x927f676de1bea707ULL, 0x9769e70db925e3e5ULL, 0x7a636ea29115065aULL, 0x468b201816ef11b6ULL, 0xab81a9b73edff409ULL, 0xc0ac7de88a07bb1eULL, 0x1f235eb68c0391b7ULL, 0x6056b074458dd30fULL, 0xbe8eeac102f7ed67ULL, 0xcd381283e04b5fbaULL, 0x5cbefecec277c4e3ULL, 0xd21b4c356c48ce0dULL, 0x1019c31664b35d8cULL, 0x247362a7d19eea26ULL, 0xebe582efb3299d03ULL, 0x02aef2cb82fc289fULL, 0x86275df09ce8aaa8ULL, 0x28b07427faac1a43ULL, 0x38a9b7319e1f47cfULL, 0xc82e92e3b8d01b58ULL, 0x06ef0b409b1978bcULL, 0x62f842bfc771fb90ULL, 0x9904034610eb3b1fULL, 0xded85ab5477a3e68ULL, 0x90d195a663428f98ULL, 0x5384636e2ac708d8ULL, 0xcbd719c37b522706ULL, 0xae9729d76644b0ebULL, 0x7c8c65e20a0c7ee6ULL, 0x80c856b007f1d214ULL, 0x8c0b40302cc32271ULL, 0xdbcedad51fe17a8aULL, 0x740e8ae938dbdea0ULL, 0xa615c6dc549310adULL, 0x19cc55f6171ae90bULL, 0x49b1bdb8fe5fdd8dULL, 0xed0a89af2830e5bfULL, 0x6a7aadb4f5a65bd6ULL, 0x7e22972988f05679ULL, 0xf952b3325566e810ULL, 0x39fecedadf61530eULL, 0x6101c99f04f3c7ceULL, 0x2e5f7f6761b562ffULL, 0xf08725d226cf5c97ULL, 0x63af3b54860fef51ULL, 0x8ff2cb10ef411e2fULL, 0x884ab9bb35267252ULL, 0x4df04433e7ba8daeULL, 0x9afd8866d3690741ULL, 0x66b9bb34de94abb3ULL, 0x9baaf18d92171380ULL, 0x543c11c5f0a064a5ULL, 0x17a1b1bdbed431f1ULL, 0xb5f58eeaf3a2717fULL, 0xc355f6c849858740ULL, 0xec5df044694ef17eULL, 0xd83751f5dc6346d4ULL, 0xfc4433520dfdacf2ULL, 0x0000000000000000ULL, 0x5a51f58e596ebc5fULL, 0x3285aaf12e34cf16ULL, 0x8d5c39db6dbd36b0ULL, 0x12b731dde64f7513ULL, 0x94906c2d7aa7dfbbULL, 0x302b583aacc8e789ULL, 0x9d45facd090e6b3cULL, 0x2165e2c78905aec4ULL, 0x68d45f7f775a7349ULL, 0x189b2c1d5664fdcaULL, 0xe1c99f2f030215daULL, 0x6983269436246788ULL, 0x8489af3b1e148237ULL, 0xe94b702431d5b59cULL, 0x33d2d31a6f4adbd7ULL, 0xbfd9932a4389f9a6ULL, 0xb0e30e8aab39359dULL, 0xd1e2c715afcaf253ULL, 0x150f43763c28196eULL, 0xc4ed846393e2eb3dULL, 0x03f98b20c3823c5eULL, 0xfd134ab94c83b833ULL, 0x556b682eb1de7064ULL, 0x36c4537a37d19f35ULL, 0x7559f30279a5ca61ULL, 0x799ae58252973a04ULL, 0x9c12832648707ffdULL, 0x78cd9c6913e92ec5ULL, 0x1d8dac7d0effb928ULL, 0x439da0784e745554ULL, 0x413352b3cc887dcbULL, 0xbacf134a1b12bd44ULL, 0x114ebafd25cd494dULL, 0x2f08068c20cb763eULL, 0x76a07822ba27f63fULL, 0xeab2fb04f25789c2ULL, 0xe3676de481fe3d45ULL, 0x1b62a73d95e6c194ULL, 0x641749ff5c68832cULL, 0xa5ec4dfc97112cf3ULL, 0xf6682e92bdd6242bULL, 0x3f11c59a44782bb2ULL, 0x317c21d1edb6f348ULL, 0xd65ab5be75ad9e2eULL, 0x6b2dd45fb4d84f17ULL, 0xfaab381296e4d44eULL, 0xd0b5befeeeb4e692ULL, 0x0882ef0b32d7a046ULL, 0x512a91a5a83b2047ULL, 0x963e9ee6f85bf724ULL, 0x4e09cf132438b1f0ULL, 0x77f701c9fb59e2feULL, 0x7ddb1c094b726a27ULL, 0x5f4775ee01f5f8bdULL, 0x9186ec4d223c9b59ULL, 0xfeeac1998f01846dULL, 0xac39db1ce4b89874ULL, 0xb75b7c21715e59e0ULL, 0xafc0503c273aa42aULL, 0x6e3b543fec430bf5ULL, 0x704f7362213e8e83ULL, 0x58ff0745db9294c0ULL, 0x67eec2df9feabf72ULL, 0xa0facd9ccf8a6811ULL, 0xb936986ad890811aULL, 0x95c715c63bd9cb7aULL, 0xca8060283a2c33c7ULL, 0x507de84ee9453486ULL, 0x85ded6d05f6a96f6ULL, 0x1cdad5964f81ade9ULL, 0xd5a33e9eb62fa270ULL, 0x40642b588df6690aULL, 0x7f75eec2c98e42b8ULL, 0x2cf18dace3494a60ULL, 0x23cb100c0bf9865bULL, 0xeef3028febb2d9e1ULL, 0x4425d2d394133929ULL, 0xaad6d05c7fa1e0c8ULL, 0xad6ea2f7a5c68cb5ULL, 0xc2028f2308fb9381ULL, 0x819f2f5b468fc6d5ULL, 0xc5bafd88d29cfffcULL, 0x47dc59f357910577ULL, 0x2b49ff07392e261dULL, 0x57c59ae5332258fbULL, 0x73b6f842e2bcb2ddULL, 0xcf96e04862b77725ULL, 0x4ca73dd8a6c4996fULL, 0x015779eb417e14c1ULL, 0x37932a9176af8bf4ULL }, { 0x190a2c9b249df23eULL, 0x2f62f8b62263e1e9ULL, 0x7a7f754740993655ULL, 0x330b7ba4d5564d9fULL, 0x4c17a16a46672582ULL, 0xb22f08eb7d05f5b8ULL, 0x535f47f40bc148ccULL, 0x3aec5d27d4883037ULL, 0x10ed0a1825438f96ULL, 0x516101f72c233d17ULL, 0x13cc6f949fd04eaeULL, 0x739853c441474bfdULL, 0x653793d90d3f5b1bULL, 0x5240647b96b0fc2fULL, 0x0c84890ad27623e0ULL, 0xd7189b32703aaea3ULL, 0x2685de3523bd9c41ULL, 0x99317c5b11bffefaULL, 0x0d9baa854f079703ULL, 0x70b93648fbd48ac5ULL, 0xa80441fce30bc6beULL, 0x7287704bdc36ff1eULL, 0xb65384ed33dc1f13ULL, 0xd36417343ee34408ULL, 0x39cd38ab6e1bf10fULL, 0x5ab861770a1f3564ULL, 0x0ebacf09f594563bULL, 0xd04572b884708530ULL, 0x3cae9722bdb3af47ULL, 0x4a556b6f2f5cbaf2ULL, 0xe1704f1f76c4bd74ULL, 0x5ec4ed7144c6dfcfULL, 0x16afc01d4c7810e6ULL, 0x283f113cd629ca7aULL, 0xaf59a8761741ed2dULL, 0xeed5a3991e215facULL, 0x3bf37ea849f984d4ULL, 0xe413e096a56ce33cULL, 0x2c439d3a98f020d1ULL, 0x637559dc6404c46bULL, 0x9e6c95d1e5f5d569ULL, 0x24bb9836045fe99aULL, 0x44efa466dac8ecc9ULL, 0xc6eab2a5c80895d6ULL, 0x803b50c035220cc4ULL, 0x0321658cba93c138ULL, 0x8f9ebc465dc7ee1cULL, 0xd15a5137190131d3ULL, 0x0fa5ec8668e5e2d8ULL, 0x91c979578d1037b1ULL, 0x0642ca05693b9f70ULL, 0xefca80168350eb4fULL, 0x38d21b24f36a45ecULL, 0xbeab81e1af73d658ULL, 0x8cbfd9cae7542f24ULL, 0xfd19cc0d81f11102ULL, 0x0ac6430fbb4dbc90ULL, 0x1d76a09d6a441895ULL, 0x2a01573ff1cbbfa1ULL, 0xb572e161894fde2bULL, 0x8124734fa853b827ULL, 0x614b1fdf43e6b1b0ULL, 0x68ac395c4238cc18ULL, 0x21d837bfd7f7b7d2ULL, 0x20c714304a860331ULL, 0x5cfaab726324aa14ULL, 0x74c5ba4eb50d606eULL, 0xf3a3030474654739ULL, 0x23e671bcf015c209ULL, 0x45f087e947b9582aULL, 0xd8bd77b418df4c7bULL, 0xe06f6c90ebb50997ULL, 0x0bd96080263c0873ULL, 0x7e03f9410e40dcfeULL, 0xb8e94be4c6484928ULL, 0xfb5b0608e8ca8e72ULL, 0x1a2b49179e0e3306ULL, 0x4e29e76961855059ULL, 0x4f36c4e6fcf4e4baULL, 0x49740ee395cf7bcaULL, 0xc2963ea386d17f7dULL, 0x90d65ad810618352ULL, 0x12d34c1b02a1fa4dULL, 0xfa44258775bb3a91ULL, 0x18150f14b9ec46ddULL, 0x1491861e6b9a653dULL, 0x9a1019d7ab2c3fc2ULL, 0x3668d42d06fe13d7ULL, 0xdcc1fbb25606a6d0ULL, 0x969490dd795a1c22ULL, 0x3549b1a1bc6dd2efULL, 0xc94f5e23a0ed770eULL, 0xb9f6686b5b39fdcbULL, 0xc4d4f4a6efeae00dULL, 0xe732851a1fff2204ULL, 0x94aad6de5eb869f9ULL, 0x3f8ff2ae07206e7fULL, 0xfe38a9813b62d03aULL, 0xa7a1ad7a8bee2466ULL, 0x7b6056c8dde882b6ULL, 0x302a1e286fc58ca7ULL, 0x8da0fa457a259bc7ULL, 0xb3302b64e074415bULL, 0x5402ae7eff8b635fULL, 0x08f8050c9cafc94bULL, 0xae468bf98a3059ceULL, 0x88c355cca98dc58fULL, 0xb10e6d67c7963480ULL, 0xbad70de7e1aa3cf3ULL, 0xbfb4a26e320262bbULL, 0xcb711820870f02d5ULL, 0xce12b7a954a75c9dULL, 0x563ce87dd8691684ULL, 0x9f73b65e7884618aULL, 0x2b1e74b06cba0b42ULL, 0x47cec1ea605b2df1ULL, 0x1c698312f735ac76ULL, 0x5fdbcefed9b76b2cULL, 0x831a354c8fb1cdfcULL, 0x820516c312c0791fULL, 0xb74ca762aeadabf0ULL, 0xfc06ef821c80a5e1ULL, 0x5723cbf24518a267ULL, 0x9d4df05d5f661451ULL, 0x588627742dfd40bfULL, 0xda8331b73f3d39a0ULL, 0x17b0e392d109a405ULL, 0xf965400bcf28fba9ULL, 0x7c3dbf4229a2a925ULL, 0x023e460327e275dbULL, 0x6cd0b55a0ce126b3ULL, 0xe62da695828e96e7ULL, 0x42ad6e63b3f373b9ULL, 0xe50cc319381d57dfULL, 0xc5cbd729729b54eeULL, 0x46d1e265fd2a9912ULL, 0x6428b056904eeff8ULL, 0x8be23040131e04b7ULL, 0x6709d5da2add2ec0ULL, 0x075de98af44a2b93ULL, 0x8447dcc67bfbe66fULL, 0x6616f655b7ac9a23ULL, 0xd607b8bded4b1a40ULL, 0x0563af89d3a85e48ULL, 0x3db1b4ad20c21ba4ULL, 0x11f22997b8323b75ULL, 0x292032b34b587e99ULL, 0x7f1cdace9331681dULL, 0x8e819fc9c0b65affULL, 0xa1e3677fe2d5bb16ULL, 0xcd33d225ee349da5ULL, 0xd9a2543b85aef898ULL, 0x795e10cbfa0af76dULL, 0x25a4bbb9992e5d79ULL, 0x78413344677b438eULL, 0xf0826688cef68601ULL, 0xd27b34bba392f0ebULL, 0x551d8df162fad7bcULL, 0x1e57c511d0d7d9adULL, 0xdeffbdb171e4d30bULL, 0xf4feea8e802f6caaULL, 0xa480c8f6317de55eULL, 0xa0fc44f07fa40ff5ULL, 0x95b5f551c3c9dd1aULL, 0x22f952336d6476eaULL, 0x0000000000000000ULL, 0xa6be8ef5169f9085ULL, 0xcc2cf1aa73452946ULL, 0x2e7ddb39bf12550aULL, 0xd526dd3157d8db78ULL, 0x486b2d6c08becf29ULL, 0x9b0f3a58365d8b21ULL, 0xac78cdfaadd22c15ULL, 0xbc95c7e28891a383ULL, 0x6a927f5f65dab9c3ULL, 0xc3891d2c1ba0cb9eULL, 0xeaa92f9f50f8b507ULL, 0xcf0d9426c9d6e87eULL, 0xca6e3baf1a7eb636ULL, 0xab25247059980786ULL, 0x69b31ad3df4978fbULL, 0xe2512a93cc577c4cULL, 0xff278a0ea61364d9ULL, 0x71a615c766a53e26ULL, 0x89dc764334fc716cULL, 0xf87a638452594f4aULL, 0xf2bc208be914f3daULL, 0x8766b94ac1682757ULL, 0xbbc82e687cdb8810ULL, 0x626a7a53f9757088ULL, 0xa2c202f358467a2eULL, 0x4d0882e5db169161ULL, 0x09e7268301de7da8ULL, 0xe897699c771ac0dcULL, 0xc8507dac3d9cc3edULL, 0xc0a878a0a1330aa6ULL, 0x978bb352e42ba8c1ULL, 0xe9884a13ea6b743fULL, 0x279afdbabecc28a2ULL, 0x047c8c064ed9eaabULL, 0x507e2278b15289f4ULL, 0x599904fbb08cf45cULL, 0xbd8ae46d15e01760ULL, 0x31353da7f2b43844ULL, 0x8558ff49e68a528cULL, 0x76fbfc4d92ef15b5ULL, 0x3456922e211c660cULL, 0x86799ac55c1993b4ULL, 0x3e90d1219a51da9cULL, 0x2d5cbeb505819432ULL, 0x982e5fd48cce4a19ULL, 0xdb9c1238a24c8d43ULL, 0xd439febecaa96f9bULL, 0x418c0bef0960b281ULL, 0x158ea591f6ebd1deULL, 0x1f48e69e4da66d4eULL, 0x8afd13cf8e6fb054ULL, 0xf5e1c9011d5ed849ULL, 0xe34e091c5126c8afULL, 0xad67ee7530a398f6ULL, 0x43b24dec2e82c75aULL, 0x75da99c1287cd48dULL, 0x92e81cdb3783f689ULL, 0xa3dd217cc537cecdULL, 0x60543c50de970553ULL, 0x93f73f54aaf2426aULL, 0xa91b62737e7a725dULL, 0xf19d4507538732e2ULL, 0x77e4dfc20f9ea156ULL, 0x7d229ccdb4d31dc6ULL, 0x1b346a98037f87e5ULL, 0xedf4c615a4b29e94ULL, 0x4093286094110662ULL, 0xb0114ee85ae78063ULL, 0x6ff1d0d6b672e78bULL, 0x6dcf96d591909250ULL, 0xdfe09e3eec9567e8ULL, 0x3214582b4827f97cULL, 0xb46dc2ee143e6ac8ULL, 0xf6c0ac8da7cd1971ULL, 0xebb60c10cd8901e4ULL, 0xf7df8f023abcad92ULL, 0x9c52d3d2c217a0b2ULL, 0x6b8d5cd0f8ab0d20ULL, 0x3777f7a29b8fa734ULL, 0x011f238f9d71b4e3ULL, 0xc1b75b2f3c42be45ULL, 0x5de588fdfe551ef7ULL, 0x6eeef3592b035368ULL, 0xaa3a07ffc4e9b365ULL, 0xecebe59a39c32a77ULL, 0x5ba742f8976e8187ULL, 0x4b4a48e0b22d0e11ULL, 0xddded83dcb771233ULL, 0xa59feb79ac0c51bdULL, 0xc7f5912a55792135ULL }, { 0x6d6ae04668a9b08aULL, 0x3ab3f04b0be8c743ULL, 0xe51e166b54b3c908ULL, 0xbe90a9eb35c2f139ULL, 0xb2c7066637f2bec1ULL, 0xaa6945613392202cULL, 0x9a28c36f3b5201ebULL, 0xddce5a93ab536994ULL, 0x0e34133ef6382827ULL, 0x52a02ba1ec55048bULL, 0xa2f88f97c4b2a177ULL, 0x8640e513ca2251a5ULL, 0xcdf1d36258137622ULL, 0xfe6cb708dedf8ddbULL, 0x8a174a9ec8121e5dULL, 0x679896036b81560eULL, 0x59ed033395795feeULL, 0x1dd778ab8b74edafULL, 0xee533ef92d9f926dULL, 0x2a8c79baf8a8d8f5ULL, 0x6bcf398e69b119f6ULL, 0xe20491742fafdd95ULL, 0x276488e0809c2aecULL, 0xea955b82d88f5cceULL, 0x7102c63a99d9e0c4ULL, 0xf9763017a5c39946ULL, 0x429fa2501f151b3dULL, 0x4659c72bea05d59eULL, 0x984b7fdccf5a6634ULL, 0xf742232953fbb161ULL, 0x3041860e08c021c7ULL, 0x747bfd9616cd9386ULL, 0x4bb1367192312787ULL, 0x1b72a1638a6c44d3ULL, 0x4a0e68a6e8359a66ULL, 0x169a5039f258b6caULL, 0xb98a2ef44edee5a4ULL, 0xd9083fe85e43a737ULL, 0x967f6ce239624e13ULL, 0x8874f62d3c1a7982ULL, 0x3c1629830af06e3fULL, 0x9165ebfd427e5a8eULL, 0xb5dd81794ceeaa5cULL, 0x0de8f15a7834f219ULL, 0x70bd98ede3dd5d25ULL, 0xaccc9ca9328a8950ULL, 0x56664eda1945ca28ULL, 0x221db34c0f8859aeULL, 0x26dbd637fa98970dULL, 0x1acdffb4f068f932ULL, 0x4585254f64090fa0ULL, 0x72de245e17d53afaULL, 0x1546b25d7c546cf4ULL, 0x207e0ffffb803e71ULL, 0xfaaad2732bcf4378ULL, 0xb462dfae36ea17bdULL, 0xcf926fd1ac1b11fdULL, 0xe0672dc7dba7ba4aULL, 0xd3fa49ad5d6b41b3ULL, 0x8ba81449b216a3bcULL, 0x14f9ec8a0650d115ULL, 0x40fc1ee3eb1d7ce2ULL, 0x23a2ed9b758ce44fULL, 0x782c521b14fddc7eULL, 0x1c68267cf170504eULL, 0xbcf31558c1ca96e6ULL, 0xa781b43b4ba6d235ULL, 0xf6fd7dfe29ff0c80ULL, 0xb0a4bad5c3fad91eULL, 0xd199f51ea963266cULL, 0x414340349119c103ULL, 0x5405f269ed4dadf7ULL, 0xabd61bb649969dcdULL, 0x6813dbeae7bdc3c8ULL, 0x65fb2ab09f8931d1ULL, 0xf1e7fae152e3181dULL, 0xc1a67cef5a2339daULL, 0x7a4feea8e0f5bba1ULL, 0x1e0b9acf05783791ULL, 0x5b8ebf8061713831ULL, 0x80e53cdbcb3af8d9ULL, 0x7e898bd315e57502ULL, 0xc6bcfbf0213f2d47ULL, 0x95a38e86b76e942dULL, 0x092e94218d243cbaULL, 0x8339debf453622e7ULL, 0xb11be402b9fe64ffULL, 0x57d9100d634177c9ULL, 0xcc4e8db52217cbc3ULL, 0x3b0cae9c71ec7aa2ULL, 0xfb158ca451cbfe99ULL, 0x2b33276d82ac6514ULL, 0x01bf5ed77a04bde1ULL, 0xc5601994af33f779ULL, 0x75c4a3416cc92e67ULL, 0xf3844652a6eb7fc2ULL, 0x3487e375fdd0ef64ULL, 0x18ae430704609eedULL, 0x4d14efb993298efbULL, 0x815a620cb13e4538ULL, 0x125c354207487869ULL, 0x9eeea614ce42cf48ULL, 0xce2d3106d61fac1cULL, 0xbbe99247bad6827bULL, 0x071a871f7b1c149dULL, 0x2e4a1cc10db81656ULL, 0x77a71ff298c149b8ULL, 0x06a5d9c80118a97cULL, 0xad73c27e488e34b1ULL, 0x443a7b981e0db241ULL, 0xe3bbcfa355ab6074ULL, 0x0af276450328e684ULL, 0x73617a896dd1871bULL, 0x58525de4ef7de20fULL, 0xb7be3dcab8e6cd83ULL, 0x19111dd07e64230cULL, 0x842359a03e2a367aULL, 0x103f89f1f3401fb6ULL, 0xdc710444d157d475ULL, 0xb835702334da5845ULL, 0x4320fc876511a6dcULL, 0xd026abc9d3679b8dULL, 0x17250eee885c0b2bULL, 0x90dab52a387ae76fULL, 0x31fed8d972c49c26ULL, 0x89cba8fa461ec463ULL, 0x2ff5421677bcabb7ULL, 0x396f122f85e41d7dULL, 0xa09b332430bac6a8ULL, 0xc888e8ced7070560ULL, 0xaeaf201ac682ee8fULL, 0x1180d7268944a257ULL, 0xf058a43628e7a5fcULL, 0xbd4c4b8fbbce2b07ULL, 0xa1246df34abe7b49ULL, 0x7d5569b79be9af3cULL, 0xa9b5a705bd9efa12ULL, 0xdb6b835baa4bc0e8ULL, 0x05793bac8f147342ULL, 0x21c1512881848390ULL, 0xfdb0556c50d357e5ULL, 0x613d4fcb6a99ff72ULL, 0x03dce2648e0cda3eULL, 0xe949b9e6568386f0ULL, 0xfc0f0bbb2ad7ea04ULL, 0x6a70675913b5a417ULL, 0x7f36d5046fe1c8e3ULL, 0x0c57af8d02304ff8ULL, 0x32223abdfcc84618ULL, 0x0891caf6f720815bULL, 0xa63eeaec31a26fd4ULL, 0x2507345374944d33ULL, 0x49d28ac266394058ULL, 0xf5219f9aa7f3d6beULL, 0x2d96fea583b4cc68ULL, 0x5a31e1571b7585d0ULL, 0x8ed12fe53d02d0feULL, 0xdfade6205f5b0e4bULL, 0x4cabb16ee92d331aULL, 0x04c6657bf510cea3ULL, 0xd73c2cd6a87b8f10ULL, 0xe1d87310a1a307abULL, 0x6cd5be9112ad0d6bULL, 0x97c032354366f3f2ULL, 0xd4e0ceb22677552eULL, 0x0000000000000000ULL, 0x29509bde76a402cbULL, 0xc27a9e8bd42fe3e4ULL, 0x5ef7842cee654b73ULL, 0xaf107ecdbc86536eULL, 0x3fcacbe784fcb401ULL, 0xd55f90655c73e8cfULL, 0xe6c2f40fdabf1336ULL, 0xe8f6e7312c873b11ULL, 0xeb2a0555a28be12fULL, 0xe4a148bc2eb774e9ULL, 0x9b979db84156bc0aULL, 0x6eb60222e6a56ab4ULL, 0x87ffbbc4b026ec44ULL, 0xc703a5275b3b90a6ULL, 0x47e699fc9001687fULL, 0x9c8d1aa73a4aa897ULL, 0x7cea3760e1ed12ddULL, 0x4ec80ddd1d2554c5ULL, 0x13e36b957d4cc588ULL, 0x5d2b66486069914dULL, 0x92b90999cc7280b0ULL, 0x517cc9c56259deb5ULL, 0xc937b619ad03b881ULL, 0xec30824ad997f5b2ULL, 0xa45d565fc5aa080bULL, 0xd6837201d27f32f1ULL, 0x635ef3789e9198adULL, 0x531f75769651b96aULL, 0x4f77530a6721e924ULL, 0x486dd4151c3dfdb9ULL, 0x5f48dafb9461f692ULL, 0x375b011173dc355aULL, 0x3da9775470f4d3deULL, 0x8d0dcd81b30e0ac0ULL, 0x36e45fc609d888bbULL, 0x55baacbe97491016ULL, 0x8cb29356c90ab721ULL, 0x76184125e2c5f459ULL, 0x99f4210bb55edbd5ULL, 0x6f095cf59ca1d755ULL, 0x9f51f8c3b44672a9ULL, 0x3538bda287d45285ULL, 0x50c39712185d6354ULL, 0xf23b1885dcefc223ULL, 0x79930ccc6ef9619fULL, 0xed8fdc9da3934853ULL, 0xcb540aaa590bdf5eULL, 0x5c94389f1a6d2cacULL, 0xe77daad8a0bbaed7ULL, 0x28efc5090ca0bf2aULL, 0xbf2ff73c4fc64cd8ULL, 0xb37858b14df60320ULL, 0xf8c96ec0dfc724a7ULL, 0x828680683f329f06ULL, 0x941cd051cd6a29ccULL, 0xc3c5c05cae2b5e05ULL, 0xb601631dc2e27062ULL, 0xc01922382027843bULL, 0x24b86a840e90f0d2ULL, 0xd245177a276ffc52ULL, 0x0f8b4de98c3c95c6ULL, 0x3e759530fef809e0ULL, 0x0b4d2892792c5b65ULL, 0xc4df4743d5374a98ULL, 0xa5e20888bfaeb5eaULL, 0xba56cc90c0d23f9aULL, 0x38d04cf8ffe0a09cULL, 0x62e1adafe495254cULL, 0x0263bcb3f40867dfULL, 0xcaeb547d230f62bfULL, 0x6082111c109d4293ULL, 0xdad4dd8cd04f7d09ULL, 0xefec602e579b2f8cULL, 0x1fb4c4187f7c8a70ULL, 0xffd3e9dfa4db303aULL, 0x7bf0b07f9af10640ULL, 0xf49ec14dddf76b5fULL, 0x8f6e713247066d1fULL, 0x339d646a86ccfbf9ULL, 0x64447467e58d8c30ULL, 0x2c29a072f9b07189ULL, 0xd8b7613f24471ad6ULL, 0x6627c8d41185ebefULL, 0xa347d140beb61c96ULL, 0xde12b8f7255fb3aaULL, 0x9d324470404e1576ULL, 0x9306574eb6763d51ULL, 0xa80af9d2c79a47f3ULL, 0x859c0777442e8b9bULL, 0x69ac853d9db97e29ULL }, { 0xc3407dfc2de6377eULL, 0x5b9e93eea4256f77ULL, 0xadb58fdd50c845e0ULL, 0x5219ff11a75bed86ULL, 0x356b61cfd90b1de9ULL, 0xfb8f406e25abe037ULL, 0x7a5a0231c0f60796ULL, 0x9d3cd216e1f5020bULL, 0x0c6550fb6b48d8f3ULL, 0xf57508c427ff1c62ULL, 0x4ad35ffa71cb407dULL, 0x6290a2da1666aa6dULL, 0xe284ec2349355f9fULL, 0xb3c307c53d7c84ecULL, 0x05e23c0468365a02ULL, 0x190bac4d6c9ebfa8ULL, 0x94bbbee9e28b80faULL, 0xa34fc777529cb9b5ULL, 0xcc7b39f095bcd978ULL, 0x2426addb0ce532e3ULL, 0x7e79329312ce4fc7ULL, 0xab09a72eebec2917ULL, 0xf8d15499f6b9d6c2ULL, 0x1a55b8babf8c895dULL, 0xdb8add17fb769a85ULL, 0xb57f2f368658e81bULL, 0x8acd36f18f3f41f6ULL, 0x5ce3b7bba50f11d3ULL, 0x114dcc14d5ee2f0aULL, 0xb91a7fcded1030e8ULL, 0x81d5425fe55de7a1ULL, 0xb6213bc1554adeeeULL, 0x80144ef95f53f5f2ULL, 0x1e7688186db4c10cULL, 0x3b912965db5fe1bcULL, 0xc281715a97e8252dULL, 0x54a5d7e21c7f8171ULL, 0x4b12535ccbc5522eULL, 0x1d289cefbea6f7f9ULL, 0x6ef5f2217d2e729eULL, 0xe6a7dc819b0d17ceULL, 0x1b94b41c05829b0eULL, 0x33d7493c622f711eULL, 0xdcf7f942fa5ce421ULL, 0x600fba8b7f7a8ecbULL, 0x46b60f011a83988eULL, 0x235b898e0dcf4c47ULL, 0x957ab24f588592a9ULL, 0x4354330572b5c28cULL, 0xa5f3ef84e9b8d542ULL, 0x8c711e02341b2d01ULL, 0x0b1874ae6a62a657ULL, 0x1213d8e306fc19ffULL, 0xfe6d7c6a4d9dba35ULL, 0x65ed868f174cd4c9ULL, 0x88522ea0e6236550ULL, 0x899322065c2d7703ULL, 0xc01e690bfef4018bULL, 0x915982ed8abddaf8ULL, 0xbe675b98ec3a4e4cULL, 0xa996bf7f82f00db1ULL, 0xe1daf8d49a27696aULL, 0x2effd5d3dc8986e7ULL, 0xd153a51f2b1a2e81ULL, 0x18caa0ebd690adfbULL, 0x390e3134b243c51aULL, 0x2778b92cdff70416ULL, 0x029f1851691c24a6ULL, 0x5e7cafeacc133575ULL, 0xfa4e4cc89fa5f264ULL, 0x5a5f9f481e2b7d24ULL, 0x484c47ab18d764dbULL, 0x400a27f2a1a7f479ULL, 0xaeeb9b2a83da7315ULL, 0x721c626879869734ULL, 0x042330a2d2384851ULL, 0x85f672fd3765aff0ULL, 0xba446b3a3e02061dULL, 0x73dd6ecec3888567ULL, 0xffac70ccf793a866ULL, 0xdfa9edb5294ed2d4ULL, 0x6c6aea7014325638ULL, 0x834a5a0e8c41c307ULL, 0xcdba35562fb2cb2bULL, 0x0ad97808d06cb404ULL, 0x0f3b440cb85aee06ULL, 0xe5f9c876481f213bULL, 0x98deee1289c35809ULL, 0x59018bbfcd394bd1ULL, 0xe01bf47220297b39ULL, 0xde68e1139340c087ULL, 0x9fa3ca4788e926adULL, 0xbb85679c840c144eULL, 0x53d8f3b71d55ffd5ULL, 0x0da45c5dd146caa0ULL, 0x6f34fe87c72060cdULL, 0x57fbc315cf6db784ULL, 0xcee421a1fca0fddeULL, 0x3d2d0196607b8d4bULL, 0x642c8a29ad42c69aULL, 0x14aff010bdd87508ULL, 0xac74837beac657b3ULL, 0x3216459ad821634dULL, 0x3fb219c70967a9edULL, 0x06bc28f3bb246cf7ULL, 0xf2082c9126d562c6ULL, 0x66b39278c45ee23cULL, 0xbd394f6f3f2878b9ULL, 0xfd33689d9e8f8cc0ULL, 0x37f4799eb017394fULL, 0x108cc0b26fe03d59ULL, 0xda4bd1b1417888d6ULL, 0xb09d1332ee6eb219ULL, 0x2f3ed975668794b4ULL, 0x58c0871977375982ULL, 0x7561463d78ace990ULL, 0x09876cff037e82f1ULL, 0x7fb83e35a8c05d94ULL, 0x26b9b58a65f91645ULL, 0xef20b07e9873953fULL, 0x3148516d0b3355b8ULL, 0x41cb2b541ba9e62aULL, 0x790416c613e43163ULL, 0xa011d380818e8f40ULL, 0x3a5025c36151f3efULL, 0xd57095bdf92266d0ULL, 0x498d4b0da2d97688ULL, 0x8b0c3a57353153a5ULL, 0x21c491df64d368e1ULL, 0x8f2f0af5e7091bf4ULL, 0x2da1c1240f9bb012ULL, 0xc43d59a92ccc49daULL, 0xbfa6573e56345c1fULL, 0x828b56a8364fd154ULL, 0x9a41f643e0df7cafULL, 0xbcf843c985266aeaULL, 0x2b1de9d7b4bfdce5ULL, 0x20059d79dedd7ab2ULL, 0x6dabe6d6ae3c446bULL, 0x45e81bf6c991ae7bULL, 0x6351ae7cac68b83eULL, 0xa432e32253b6c711ULL, 0xd092a9b991143cd2ULL, 0xcac711032e98b58fULL, 0xd8d4c9e02864ac70ULL, 0xc5fc550f96c25b89ULL, 0xd7ef8dec903e4276ULL, 0x67729ede7e50f06fULL, 0xeac28c7af045cf3dULL, 0xb15c1f945460a04aULL, 0x9cfddeb05bfb1058ULL, 0x93c69abce3a1fe5eULL, 0xeb0380dc4a4bdd6eULL, 0xd20db1e8f8081874ULL, 0x229a8528b7c15e14ULL, 0x44291750739fbc28ULL, 0xd3ccbd4e42060a27ULL, 0xf62b1c33f4ed2a97ULL, 0x86a8660ae4779905ULL, 0xd62e814a2a305025ULL, 0x477703a7a08d8addULL, 0x7b9b0e977af815c5ULL, 0x78c51a60a9ea2330ULL, 0xa6adfb733aaae3b7ULL, 0x97e5aa1e3199b60fULL, 0x0000000000000000ULL, 0xf4b404629df10e31ULL, 0x5564db44a6719322ULL, 0x9207961a59afec0dULL, 0x9624a6b88b97a45cULL, 0x363575380a192b1cULL, 0x2c60cd82b595a241ULL, 0x7d272664c1dc7932ULL, 0x7142769faa94a1c1ULL, 0xa1d0df263b809d13ULL, 0x1630e841d4c451aeULL, 0xc1df65ad44fa13d8ULL, 0x13d2d445bcf20bacULL, 0xd915c546926abe23ULL, 0x38cf3d92084dd749ULL, 0xe766d0272103059dULL, 0xc7634d5effde7f2fULL, 0x077d2455012a7ea4ULL, 0xedbfa82ff16fb199ULL, 0xaf2a978c39d46146ULL, 0x42953fa3c8bbd0dfULL, 0xcb061da59496a7dcULL, 0x25e7a17db6eb20b0ULL, 0x34aa6d6963050fbaULL, 0xa76cf7d580a4f1e4ULL, 0xf7ea10954ee338c4ULL, 0xfcf2643b24819e93ULL, 0xcf252d0746aeef8dULL, 0x4ef06f58a3f3082cULL, 0x563acfb37563a5d7ULL, 0x5086e740ce47c920ULL, 0x2982f186dda3f843ULL, 0x87696aac5e798b56ULL, 0x5d22bb1d1f010380ULL, 0x035e14f7d31236f5ULL, 0x3cec0d30da759f18ULL, 0xf3c920379cdb7095ULL, 0xb8db736b571e22bbULL, 0xdd36f5e44052f672ULL, 0xaac8ab8851e23b44ULL, 0xa857b3d938fe1fe2ULL, 0x17f1e4e76eca43fdULL, 0xec7ea4894b61a3caULL, 0x9e62c6e132e734feULL, 0xd4b1991b432c7483ULL, 0x6ad6c283af163acfULL, 0x1ce9904904a8e5aaULL, 0x5fbda34c761d2726ULL, 0xf910583f4cb7c491ULL, 0xc6a241f845d06d7cULL, 0x4f3163fe19fd1a7fULL, 0xe99c988d2357f9c8ULL, 0x8eee06535d0709a7ULL, 0x0efa48aa0254fc55ULL, 0xb4be23903c56fa48ULL, 0x763f52caabbedf65ULL, 0xeee1bcd8227d876cULL, 0xe345e085f33b4dccULL, 0x3e731561b369bbbeULL, 0x2843fd2067adea10ULL, 0x2adce5710eb1ceb6ULL, 0xb7e03767ef44ccbdULL, 0x8db012a48e153f52ULL, 0x61ceb62dc5749c98ULL, 0xe85d942b9959eb9bULL, 0x4c6f7709caef2c8aULL, 0x84377e5b8d6bbda3ULL, 0x30895dcbb13d47ebULL, 0x74a04a9bc2a2fbc3ULL, 0x6b17ce251518289cULL, 0xe438c4d0f2113368ULL, 0x1fb784bed7bad35fULL, 0x9b80fae55ad16efcULL, 0x77fe5e6c11b0cd36ULL, 0xc858095247849129ULL, 0x08466059b97090a2ULL, 0x01c10ca6ba0e1253ULL, 0x6988d6747c040c3aULL, 0x6849dad2c60a1e69ULL, 0x5147ebe67449db73ULL, 0xc99905f4fd8a837aULL, 0x991fe2b433cd4a5aULL, 0xf09734c04fc94660ULL, 0xa28ecbd1e892abe6ULL, 0xf1563866f5c75433ULL, 0x4dae7baf70e13ed9ULL, 0x7ce62ac27bd26b61ULL, 0x70837a39109ab392ULL, 0x90988e4b30b3c8abULL, 0xb2020b63877296bfULL, 0x156efcb607d6675bULL }, { 0xe63f55ce97c331d0ULL, 0x25b506b0015bba16ULL, 0xc8706e29e6ad9ba8ULL, 0x5b43d3775d521f6aULL, 0x0bfa3d577035106eULL, 0xab95fc172afb0e66ULL, 0xf64b63979e7a3276ULL, 0xf58b4562649dad4bULL, 0x48f7c3dbae0c83f1ULL, 0xff31916642f5c8c5ULL, 0xcbb048dc1c4a0495ULL, 0x66b8f83cdf622989ULL, 0x35c130e908e2b9b0ULL, 0x7c761a61f0b34fa1ULL, 0x3601161cf205268dULL, 0x9e54ccfe2219b7d6ULL, 0x8b7d90a538940837ULL, 0x9cd403588ea35d0bULL, 0xbc3c6fea9ccc5b5aULL, 0xe5ff733b6d24aeedULL, 0xceed22de0f7eb8d2ULL, 0xec8581cab1ab545eULL, 0xb96105e88ff8e71dULL, 0x8ca03501871a5eadULL, 0x76ccce65d6db2a2fULL, 0x5883f582a7b58057ULL, 0x3f7be4ed2e8adc3eULL, 0x0fe7be06355cd9c9ULL, 0xee054e6c1d11be83ULL, 0x1074365909b903a6ULL, 0x5dde9f80b4813c10ULL, 0x4a770c7d02b6692cULL, 0x5379c8d5d7809039ULL, 0xb4067448161ed409ULL, 0x5f5e5026183bd6cdULL, 0xe898029bf4c29df9ULL, 0x7fb63c940a54d09cULL, 0xc5171f897f4ba8bcULL, 0xa6f28db7b31d3d72ULL, 0x2e4f3be7716eaa78ULL, 0x0d6771a099e63314ULL, 0x82076254e41bf284ULL, 0x2f0fd2b42733df98ULL, 0x5c9e76d3e2dc49f0ULL, 0x7aeb569619606cdbULL, 0x83478b07b2468764ULL, 0xcfadcb8d5923cd32ULL, 0x85dac7f05b95a41eULL, 0xb5469d1b4043a1e9ULL, 0xb821ecbbd9a592fdULL, 0x1b8e0b0e798c13c8ULL, 0x62a57b6d9a0be02eULL, 0xfcf1b793b81257f8ULL, 0x9d94ea0bd8fe28ebULL, 0x4cea408aeb654a56ULL, 0x23284a47e888996cULL, 0x2d8f1d128b893545ULL, 0xf4cbac3132c0d8abULL, 0xbd7c86b9ca912ebaULL, 0x3a268eef3dbe6079ULL, 0xf0d62f6077a9110cULL, 0x2735c916ade150cbULL, 0x89fd5f03942ee2eaULL, 0x1acee25d2fd16628ULL, 0x90f39bab41181bffULL, 0x430dfe8cde39939fULL, 0xf70b8ac4c8274796ULL, 0x1c53aeaac6024552ULL, 0x13b410acf35e9c9bULL, 0xa532ab4249faa24fULL, 0x2b1251e5625a163fULL, 0xd7e3e676da4841c7ULL, 0xa7b264e4e5404892ULL, 0xda8497d643ae72d3ULL, 0x861ae105a1723b23ULL, 0x38a6414991048aa4ULL, 0x6578dec92585b6b4ULL, 0x0280cfa6acbaeaddULL, 0x88bdb650c273970aULL, 0x9333bd5ebbff84c2ULL, 0x4e6a8f2c47dfa08bULL, 0x321c954db76cef2aULL, 0x418d312a72837942ULL, 0xb29b38bfffcdf773ULL, 0x6c022c38f90a4c07ULL, 0x5a033a240b0f6a8aULL, 0x1f93885f3ce5da6fULL, 0xc38a537e96988bc6ULL, 0x39e6a81ac759ff44ULL, 0x29929e43cee0fce2ULL, 0x40cdd87924de0ca2ULL, 0xe9d8ebc8a29fe819ULL, 0x0c2798f3cfbb46f4ULL, 0x55e484223e53b343ULL, 0x4650948ecd0d2fd8ULL, 0x20e86cb2126f0651ULL, 0x6d42c56baf5739e7ULL, 0xa06fc1405ace1e08ULL, 0x7babbfc54f3d193bULL, 0x424d17df8864e67fULL, 0xd8045870ef14980eULL, 0xc6d7397c85ac3781ULL, 0x21a885e1443273b1ULL, 0x67f8116f893f5c69ULL, 0x24f5efe35706cff6ULL, 0xd56329d076f2ab1aULL, 0x5e1eb9754e66a32dULL, 0x28d2771098bd8902ULL, 0x8f6013f47dfdc190ULL, 0x17a993fdb637553cULL, 0xe0a219397e1012aaULL, 0x786b9930b5da8606ULL, 0x6e82e39e55b0a6daULL, 0x875a0856f72f4ec3ULL, 0x3741ff4fa458536dULL, 0xac4859b3957558fcULL, 0x7ef6d5c75c09a57cULL, 0xc04a758b6c7f14fbULL, 0xf9acdd91ab26ebbfULL, 0x7391a467c5ef9668ULL, 0x335c7c1ee1319acaULL, 0xa91533b18641e4bbULL, 0xe4bf9a683b79db0dULL, 0x8e20faa72ba0b470ULL, 0x51f907737b3a7ae4ULL, 0x2268a314bed5ec8cULL, 0xd944b123b949edeeULL, 0x31dcb3b84d8b7017ULL, 0xd3fe65279f218860ULL, 0x097af2f1dc8ffab3ULL, 0x9b09a6fc312d0b91ULL, 0xcc6ded78a3c4520fULL, 0x3481d9ba5ebfcc50ULL, 0x4f2a667f1182d56bULL, 0xdfd9fdd4509ace94ULL, 0x26752045fbbc252bULL, 0xbffc491f662bc467ULL, 0xdd593272fc202449ULL, 0x3cbbc218d46d4303ULL, 0x91b372f817456e1fULL, 0x681faf69bc6385a0ULL, 0xb686bbeebaa43ed4ULL, 0x1469b5084cd0ca01ULL, 0x98c98009cbca94acULL, 0x6438379a73d8c354ULL, 0xc2caba2dc0c5fe26ULL, 0x3e3b0dbe78d7a9deULL, 0x50b9ee202d670f04ULL, 0x4590b27b37eab0e5ULL, 0x6025b4cb36b10af3ULL, 0xfb2c1237079c0162ULL, 0xa12f28130c936be8ULL, 0x4b37e52e54eb1cccULL, 0x083a1ba28ad28f53ULL, 0xc10a9cd83a22611bULL, 0x9f1425ad7444c236ULL, 0x069d4cf7e9d3237aULL, 0xedc56899e7f621beULL, 0x778c273680865fcfULL, 0x309c5aeb1bd605f7ULL, 0x8de0dc52d1472b4dULL, 0xf8ec34c2fd7b9e5fULL, 0xea18cd3d58787724ULL, 0xaad515447ca67b86ULL, 0x9989695a9d97e14cULL, 0x0000000000000000ULL, 0xf196c63321f464ecULL, 0x71116bc169557cb5ULL, 0xaf887f466f92c7c1ULL, 0x972e3e0ffe964d65ULL, 0x190ec4a8d536f915ULL, 0x95aef1a9522ca7b8ULL, 0xdc19db21aa7d51a9ULL, 0x94ee18fa0471d258ULL, 0x8087adf248a11859ULL, 0xc457f6da2916dd5cULL, 0xfa6cfb6451c17482ULL, 0xf256e0c6db13fbd1ULL, 0x6a9f60cf10d96f7dULL, 0x4daaa9d9bd383fb6ULL, 0x03c026f5fae79f3dULL, 0xde99148706c7bb74ULL, 0x2a52b8b6340763dfULL, 0x6fc20acd03edd33aULL, 0xd423c08320afdefaULL, 0xbbe1ca4e23420dc0ULL, 0x966ed75ca8cb3885ULL, 0xeb58246e0e2502c4ULL, 0x055d6a021334bc47ULL, 0xa47242111fa7d7afULL, 0xe3623fcc84f78d97ULL, 0x81c744a11efc6db9ULL, 0xaec8961539cfb221ULL, 0xf31609958d4e8e31ULL, 0x63e5923ecc5695ceULL, 0x47107ddd9b505a38ULL, 0xa3afe7b5a0298135ULL, 0x792b7063e387f3e6ULL, 0x0140e953565d75e0ULL, 0x12f4f9ffa503e97bULL, 0x750ce8902c3cb512ULL, 0xdbc47e8515f30733ULL, 0x1ed3610c6ab8af8fULL, 0x5239218681dde5d9ULL, 0xe222d69fd2aaf877ULL, 0xfe71783514a8bd25ULL, 0xcaf0a18f4a177175ULL, 0x61655d9860ec7f13ULL, 0xe77fbc9dc19e4430ULL, 0x2ccff441ddd440a5ULL, 0x16e97aaee06a20dcULL, 0xa855dae2d01c915bULL, 0x1d1347f9905f30b2ULL, 0xb7c652bdecf94b34ULL, 0xd03e43d265c6175dULL, 0xfdb15ec0ee4f2218ULL, 0x57644b8492e9599eULL, 0x07dda5a4bf8e569aULL, 0x54a46d71680ec6a3ULL, 0x5624a2d7c4b42c7eULL, 0xbebca04c3076b187ULL, 0x7d36f332a6ee3a41ULL, 0x3b6667bc6be31599ULL, 0x695f463aea3ef040ULL, 0xad08b0e0c3282d1cULL, 0xb15b1e4a052a684eULL, 0x44d05b2861b7c505ULL, 0x15295c5b1a8dbfe1ULL, 0x744c01c37a61c0f2ULL, 0x59c31cd1f1e8f5b7ULL, 0xef45a73f4b4ccb63ULL, 0x6bdf899c46841a9dULL, 0x3dfb2b4b823036e3ULL, 0xa2ef0ee6f674f4d5ULL, 0x184e2dfb836b8cf5ULL, 0x1134df0a5fe47646ULL, 0xbaa1231d751f7820ULL, 0xd17eaa81339b62bdULL, 0xb01bf71953771daeULL, 0x849a2ea30dc8d1feULL, 0x705182923f080955ULL, 0x0ea757556301ac29ULL, 0x041d83514569c9a7ULL, 0x0abad4042668658eULL, 0x49b72a88f851f611ULL, 0x8a3d79f66ec97dd7ULL, 0xcd2d042bf59927efULL, 0xc930877ab0f0ee48ULL, 0x9273540deda2f122ULL, 0xc797d02fd3f14261ULL, 0xe1e2f06a284d674aULL, 0xd2be8c74c97cfd80ULL, 0x9a494faf67707e71ULL, 0xb3dbd1eca9908293ULL, 0x72d14d3493b2e388ULL, 0xd6a30f258c153427ULL } }; extern const uint64_t STREEBOG_C[12][8] = { { 0xdd806559f2a64507ULL, 0x05767436cc744d23ULL, 0xa2422a08a460d315ULL, 0x4b7ce09192676901ULL, 0x714eb88d7585c4fcULL, 0x2f6a76432e45d016ULL, 0xebcb2f81c0657c1fULL, 0xb1085bda1ecadae9ULL }, { 0xe679047021b19bb7ULL, 0x55dda21bd7cbcd56ULL, 0x5cb561c2db0aa7caULL, 0x9ab5176b12d69958ULL, 0x61d55e0f16b50131ULL, 0xf3feea720a232b98ULL, 0x4fe39d460f70b5d7ULL, 0x6fa3b58aa99d2f1aULL }, { 0x991e96f50aba0ab2ULL, 0xc2b6f443867adb31ULL, 0xc1c93a376062db09ULL, 0xd3e20fe490359eb1ULL, 0xf2ea7514b1297b7bULL, 0x06f15e5f529c1f8bULL, 0x0a39fc286a3d8435ULL, 0xf574dcac2bce2fc7ULL }, { 0x220cbebc84e3d12eULL, 0x3453eaa193e837f1ULL, 0xd8b71333935203beULL, 0xa9d72c82ed03d675ULL, 0x9d721cad685e353fULL, 0x488e857e335c3c7dULL, 0xf948e1a05d71e4ddULL, 0xef1fdfb3e81566d2ULL }, { 0x601758fd7c6cfe57ULL, 0x7a56a27ea9ea63f5ULL, 0xdfff00b723271a16ULL, 0xbfcd1747253af5a3ULL, 0x359e35d7800fffbdULL, 0x7f151c1f1686104aULL, 0x9a3f410c6ca92363ULL, 0x4bea6bacad474799ULL }, { 0xfa68407a46647d6eULL, 0xbf71c57236904f35ULL, 0x0af21f66c2bec6b6ULL, 0xcffaa6b71c9ab7b4ULL, 0x187f9ab49af08ec6ULL, 0x2d66c4f95142a46cULL, 0x6fa4c33b7a3039c0ULL, 0xae4faeae1d3ad3d9ULL }, { 0x8886564d3a14d493ULL, 0x3517454ca23c4af3ULL, 0x06476983284a0504ULL, 0x0992abc52d822c37ULL, 0xd3473e33197a93c9ULL, 0x399ec6c7e6bf87c9ULL, 0x51ac86febf240954ULL, 0xf4c70e16eeaac5ecULL }, { 0xa47f0dd4bf02e71eULL, 0x36acc2355951a8d9ULL, 0x69d18d2bd1a5c42fULL, 0xf4892bcb929b0690ULL, 0x89b4443b4ddbc49aULL, 0x4eb7f8719c36de1eULL, 0x03e7aa020c6e4141ULL, 0x9b1f5b424d93c9a7ULL }, { 0x7261445183235adbULL, 0x0e38dc92cb1f2a60ULL, 0x7b2b8a9aa6079c54ULL, 0x800a440bdbb2ceb1ULL, 0x3cd955b7e00d0984ULL, 0x3a7d3a1b25894224ULL, 0x944c9ad8ec165fdeULL, 0x378f5a541631229bULL }, { 0x74b4c7fb98459cedULL, 0x3698fad1153bb6c3ULL, 0x7a1e6c303b7652f4ULL, 0x9fe76702af69334bULL, 0x1fffe18a1b336103ULL, 0x8941e71cff8a78dbULL, 0x382ae548b2e4f3f3ULL, 0xabbedea680056f52ULL }, { 0x6bcaa4cd81f32d1bULL, 0xdea2594ac06fd85dULL, 0xefbacd1d7d476e98ULL, 0x8a1d71efea48b9caULL, 0x2001802114846679ULL, 0xd8fa6bbbebab0761ULL, 0x3002c6cd635afe94ULL, 0x7bcd9ed0efc889fbULL }, { 0x48bc924af11bd720ULL, 0xfaf417d5d9b21b99ULL, 0xe71da4aa88e12852ULL, 0x5d80ef9d1891cc86ULL, 0xf82012d430219f9bULL, 0xcda43c32bcdf1d77ULL, 0xd21380b00449b17aULL, 0x378ee767f11631baULL } }; } /* * System RNG * (C) 2014,2015,2017,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM) #define NOMINMAX 1 #define _WINSOCKAPI_ // stop windows.h including winsock.h #elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG) #include #elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM) #include #elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM) #include #include #elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM) #include #include #include #include #include #endif namespace Botan { namespace { #if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM) class System_RNG_Impl final : public RandomNumberGenerator { public: System_RNG_Impl() : m_advapi("advapi32.dll") { // This throws if the function is not found m_rtlgenrandom = m_advapi.resolve("SystemFunction036"); } void randomize(uint8_t buf[], size_t len) override { bool success = m_rtlgenrandom(buf, ULONG(len)) == TRUE; if(!success) throw System_Error("RtlGenRandom failed"); } void add_entropy(const uint8_t[], size_t) override { /* ignored */ } bool is_seeded() const override { return true; } bool accepts_input() const override { return false; } void clear() override { /* not possible */ } std::string name() const override { return "RtlGenRandom"; } private: // Use type BYTE instead of BOOLEAN because of a naming conflict // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx using RtlGenRandom_fptr = BYTE (NTAPI *)(PVOID, ULONG); Dynamically_Loaded_Library m_advapi; RtlGenRandom_fptr m_rtlgenrandom; }; #elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG) class System_RNG_Impl final : public RandomNumberGenerator { public: System_RNG_Impl() { NTSTATUS ret = ::BCryptOpenAlgorithmProvider(&m_prov, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); if(ret != STATUS_SUCCESS) throw System_Error("System_RNG failed to acquire crypto provider", ret); } ~System_RNG_Impl() { ::BCryptCloseAlgorithmProvider(m_prov, 0); } void randomize(uint8_t buf[], size_t len) override { NTSTATUS ret = ::BCryptGenRandom(m_prov, static_cast(buf), static_cast(len), 0); if(ret != STATUS_SUCCESS) throw System_Error("System_RNG call to BCryptGenRandom failed", ret); } void add_entropy(const uint8_t in[], size_t length) override { /* There is a flag BCRYPT_RNG_USE_ENTROPY_IN_BUFFER to provide entropy inputs, but it is ignored in Windows 8 and later. */ } bool is_seeded() const override { return true; } bool accepts_input() const override { return false; } void clear() override { /* not possible */ } std::string name() const override { return "crypto_ng"; } private: BCRYPT_ALG_HANDLE m_prov; }; #elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM) class System_RNG_Impl final : public RandomNumberGenerator { public: // No constructor or destructor needed as no userland state maintained void randomize(uint8_t buf[], size_t len) override { // macOS 10.15 arc4random crashes if called with buf == nullptr && len == 0 if(len > 0) { ::arc4random_buf(buf, len); } } bool accepts_input() const override { return false; } void add_entropy(const uint8_t[], size_t) override { /* ignored */ } bool is_seeded() const override { return true; } void clear() override { /* not possible */ } std::string name() const override { return "arc4random"; } }; #elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM) class System_RNG_Impl final : public RandomNumberGenerator { public: // No constructor or destructor needed as no userland state maintained void randomize(uint8_t buf[], size_t len) override { const unsigned int flags = 0; while(len > 0) { const ssize_t got = ::getrandom(buf, len, flags); if(got < 0) { if(errno == EINTR) continue; throw System_Error("System_RNG getrandom failed", errno); } buf += got; len -= got; } } bool accepts_input() const override { return false; } void add_entropy(const uint8_t[], size_t) override { /* ignored */ } bool is_seeded() const override { return true; } void clear() override { /* not possible */ } std::string name() const override { return "getrandom"; } }; #elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM) // Read a random device class System_RNG_Impl final : public RandomNumberGenerator { public: System_RNG_Impl() { #ifndef O_NOCTTY #define O_NOCTTY 0 #endif m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY); if(m_fd >= 0) { m_writable = true; } else { /* Cannot open in read-write mode. Fall back to read-only, calls to add_entropy will fail, but randomize will work */ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY); m_writable = false; } if(m_fd < 0) throw System_Error("System_RNG failed to open RNG device", errno); } ~System_RNG_Impl() { ::close(m_fd); m_fd = -1; } void randomize(uint8_t buf[], size_t len) override; void add_entropy(const uint8_t in[], size_t length) override; bool is_seeded() const override { return true; } bool accepts_input() const override { return m_writable; } void clear() override { /* not possible */ } std::string name() const override { return BOTAN_SYSTEM_RNG_DEVICE; } private: int m_fd; bool m_writable; }; void System_RNG_Impl::randomize(uint8_t buf[], size_t len) { while(len) { ssize_t got = ::read(m_fd, buf, len); if(got < 0) { if(errno == EINTR) continue; throw System_Error("System_RNG read failed", errno); } if(got == 0) throw System_Error("System_RNG EOF on device"); // ?!? buf += got; len -= got; } } void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len) { if(!m_writable) return; while(len) { ssize_t got = ::write(m_fd, input, len); if(got < 0) { if(errno == EINTR) continue; /* * This is seen on OS X CI, despite the fact that the man page * for macOS urandom explicitly states that writing to it is * supported, and write(2) does not document EPERM at all. * But in any case EPERM seems indicative of a policy decision * by the OS or sysadmin that additional entropy is not wanted * in the system pool, so we accept that and return here, * since there is no corrective action possible. * * In Linux EBADF or EPERM is returned if m_fd is not opened for * writing. */ if(errno == EPERM || errno == EBADF) return; // maybe just ignore any failure here and return? throw System_Error("System_RNG write failed", errno); } input += got; len -= got; } } #endif } RandomNumberGenerator& system_rng() { static System_RNG_Impl g_system_rng; return g_system_rng; } } /* * Barrier * (C) 2016 Joel Low * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Barrier::wait(size_t delta) { std::lock_guard lock(m_mutex); m_value += delta; } void Barrier::sync() { std::unique_lock lock(m_mutex); if(m_value > 1) { --m_value; const size_t current_syncs = m_syncs; m_cond.wait(lock, [this, ¤t_syncs] { return m_syncs != current_syncs; }); } else { m_value = 0; ++m_syncs; m_cond.notify_all(); } } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { RWLock::RWLock() : m_state(0) {} void RWLock::lock() { std::unique_lock lock(m_mutex); while(m_state & is_writing) m_gate1.wait(lock); m_state |= is_writing; while(m_state & readers_mask) m_gate2.wait(lock); } void RWLock::unlock() { std::unique_lock lock(m_mutex); m_state = 0; m_gate1.notify_all(); } void RWLock::lock_shared() { std::unique_lock lock(m_mutex); while((m_state & is_writing) || (m_state & readers_mask) == readers_mask) m_gate1.wait(lock); const uint32_t num_readers = (m_state & readers_mask) + 1; m_state &= ~readers_mask; m_state |= num_readers; } void RWLock::unlock_shared() { std::unique_lock lock(m_mutex); const uint32_t num_readers = (m_state & readers_mask) - 1; m_state &= ~readers_mask; m_state |= num_readers; if(m_state & is_writing) { if(num_readers == 0) m_gate2.notify_one(); } else { if(num_readers == readers_mask - 1) m_gate1.notify_one(); } } } /* * Semaphore * (C) 2013 Joel Low * * Botan is released under the Simplified BSD License (see license.txt) */ // Based on code by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html) namespace Botan { void Semaphore::release(size_t n) { for(size_t i = 0; i != n; ++i) { std::lock_guard lock(m_mutex); if(m_value++ < 0) { ++m_wakeups; m_cond.notify_one(); } } } void Semaphore::acquire() { std::unique_lock lock(m_mutex); if(m_value-- <= 0) { m_cond.wait(lock, [this] { return m_wakeups > 0; }); --m_wakeups; } } } /* * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include namespace Botan { //static Thread_Pool& Thread_Pool::global_instance() { static Thread_Pool g_thread_pool(OS::read_env_variable_sz("BOTAN_THREAD_POOL_SIZE")); return g_thread_pool; } Thread_Pool::Thread_Pool(size_t pool_size) { if(pool_size == 0) { pool_size = OS::get_cpu_available(); /* * For large machines don't create too many threads, unless * explicitly asked to by the caller. */ if(pool_size > 16) pool_size = 16; } if(pool_size <= 1) pool_size = 2; m_shutdown = false; for(size_t i = 0; i != pool_size; ++i) { m_workers.push_back(std::thread(&Thread_Pool::worker_thread, this)); } } void Thread_Pool::shutdown() { { std::unique_lock lock(m_mutex); if(m_shutdown == true) return; m_shutdown = true; m_more_tasks.notify_all(); } for(auto&& thread : m_workers) { thread.join(); } m_workers.clear(); } void Thread_Pool::queue_thunk(std::function fn) { std::unique_lock lock(m_mutex); if(m_shutdown) throw Invalid_State("Cannot add work after thread pool has shut down"); m_tasks.push_back(fn); m_more_tasks.notify_one(); } void Thread_Pool::worker_thread() { for(;;) { std::function task; { std::unique_lock lock(m_mutex); m_more_tasks.wait(lock, [this]{ return m_shutdown || !m_tasks.empty(); }); if(m_tasks.empty()) { if(m_shutdown) return; else continue; } task = m_tasks.front(); m_tasks.pop_front(); } task(); } } } /* * Threefish-512 * (C) 2013,2014,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { #define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ do { \ X0 += X4; \ X1 += X5; \ X2 += X6; \ X3 += X7; \ X4 = rotl(X4); \ X5 = rotl(X5); \ X6 = rotl(X6); \ X7 = rotl(X7); \ X4 ^= X0; \ X5 ^= X1; \ X6 ^= X2; \ X7 ^= X3; \ } while(0) #define THREEFISH_INJECT_KEY(r) \ do { \ X0 += m_K[(r ) % 9]; \ X1 += m_K[(r+1) % 9]; \ X2 += m_K[(r+2) % 9]; \ X3 += m_K[(r+3) % 9]; \ X4 += m_K[(r+4) % 9]; \ X5 += m_K[(r+5) % 9] + m_T[(r ) % 3]; \ X6 += m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ X7 += m_K[(r+7) % 9] + (r); \ } while(0) #define THREEFISH_ENC_8_ROUNDS(R1,R2) \ do { \ THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \ THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \ THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \ THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \ THREEFISH_INJECT_KEY(R1); \ \ THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \ THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \ THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \ THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22); \ THREEFISH_INJECT_KEY(R2); \ } while(0) void Threefish_512::skein_feedfwd(const secure_vector& M, const secure_vector& T) { BOTAN_ASSERT(m_K.size() == 9, "Key was set"); BOTAN_ASSERT(M.size() == 8, "Single block"); m_T[0] = T[0]; m_T[1] = T[1]; m_T[2] = T[0] ^ T[1]; uint64_t X0 = M[0]; uint64_t X1 = M[1]; uint64_t X2 = M[2]; uint64_t X3 = M[3]; uint64_t X4 = M[4]; uint64_t X5 = M[5]; uint64_t X6 = M[6]; uint64_t X7 = M[7]; THREEFISH_INJECT_KEY(0); THREEFISH_ENC_8_ROUNDS(1,2); THREEFISH_ENC_8_ROUNDS(3,4); THREEFISH_ENC_8_ROUNDS(5,6); THREEFISH_ENC_8_ROUNDS(7,8); THREEFISH_ENC_8_ROUNDS(9,10); THREEFISH_ENC_8_ROUNDS(11,12); THREEFISH_ENC_8_ROUNDS(13,14); THREEFISH_ENC_8_ROUNDS(15,16); THREEFISH_ENC_8_ROUNDS(17,18); m_K[0] = M[0] ^ X0; m_K[1] = M[1] ^ X1; m_K[2] = M[2] ^ X2; m_K[3] = M[3] ^ X3; m_K[4] = M[4] ^ X4; m_K[5] = M[5] ^ X5; m_K[6] = M[6] ^ X6; m_K[7] = M[7] ^ X7; m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; } size_t Threefish_512::parallelism() const { #if defined(BOTAN_HAS_THREEFISH_512_AVX2) if(CPUID::has_avx2()) { return 2; } #endif return 1; } std::string Threefish_512::provider() const { #if defined(BOTAN_HAS_THREEFISH_512_AVX2) if(CPUID::has_avx2()) { return "avx2"; } #endif return "base"; } void Threefish_512::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_K.empty() == false); #if defined(BOTAN_HAS_THREEFISH_512_AVX2) if(CPUID::has_avx2()) { return avx2_encrypt_n(in, out, blocks); } #endif BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) { uint64_t X0, X1, X2, X3, X4, X5, X6, X7; load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); THREEFISH_INJECT_KEY(0); THREEFISH_ENC_8_ROUNDS(1,2); THREEFISH_ENC_8_ROUNDS(3,4); THREEFISH_ENC_8_ROUNDS(5,6); THREEFISH_ENC_8_ROUNDS(7,8); THREEFISH_ENC_8_ROUNDS(9,10); THREEFISH_ENC_8_ROUNDS(11,12); THREEFISH_ENC_8_ROUNDS(13,14); THREEFISH_ENC_8_ROUNDS(15,16); THREEFISH_ENC_8_ROUNDS(17,18); store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); } } #undef THREEFISH_ENC_8_ROUNDS #undef THREEFISH_INJECT_KEY #undef THREEFISH_ROUND void Threefish_512::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_K.empty() == false); #if defined(BOTAN_HAS_THREEFISH_512_AVX2) if(CPUID::has_avx2()) { return avx2_decrypt_n(in, out, blocks); } #endif #define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ do { \ X4 ^= X0; \ X5 ^= X1; \ X6 ^= X2; \ X7 ^= X3; \ X4 = rotr(X4); \ X5 = rotr(X5); \ X6 = rotr(X6); \ X7 = rotr(X7); \ X0 -= X4; \ X1 -= X5; \ X2 -= X6; \ X3 -= X7; \ } while(0) #define THREEFISH_INJECT_KEY(r) \ do { \ X0 -= m_K[(r ) % 9]; \ X1 -= m_K[(r+1) % 9]; \ X2 -= m_K[(r+2) % 9]; \ X3 -= m_K[(r+3) % 9]; \ X4 -= m_K[(r+4) % 9]; \ X5 -= m_K[(r+5) % 9] + m_T[(r ) % 3]; \ X6 -= m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ X7 -= m_K[(r+7) % 9] + (r); \ } while(0) #define THREEFISH_DEC_8_ROUNDS(R1,R2) \ do { \ THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22); \ THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \ THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \ THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \ THREEFISH_INJECT_KEY(R1); \ \ THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \ THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \ THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \ THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \ THREEFISH_INJECT_KEY(R2); \ } while(0) BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) { uint64_t X0, X1, X2, X3, X4, X5, X6, X7; load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); THREEFISH_INJECT_KEY(18); THREEFISH_DEC_8_ROUNDS(17,16); THREEFISH_DEC_8_ROUNDS(15,14); THREEFISH_DEC_8_ROUNDS(13,12); THREEFISH_DEC_8_ROUNDS(11,10); THREEFISH_DEC_8_ROUNDS(9,8); THREEFISH_DEC_8_ROUNDS(7,6); THREEFISH_DEC_8_ROUNDS(5,4); THREEFISH_DEC_8_ROUNDS(3,2); THREEFISH_DEC_8_ROUNDS(1,0); store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); } #undef THREEFISH_DEC_8_ROUNDS #undef THREEFISH_INJECT_KEY #undef THREEFISH_ROUND } void Threefish_512::set_tweak(const uint8_t tweak[], size_t len) { BOTAN_ARG_CHECK(len == 16, "Threefish-512 requires 128 bit tweak"); m_T.resize(3); m_T[0] = load_le(tweak, 0); m_T[1] = load_le(tweak, 1); m_T[2] = m_T[0] ^ m_T[1]; } void Threefish_512::key_schedule(const uint8_t key[], size_t) { // todo: define key schedule for smaller keys m_K.resize(9); for(size_t i = 0; i != 8; ++i) m_K[i] = load_le(key, i); m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; // Reset tweak to all zeros on key reset m_T.resize(3); zeroise(m_T); } void Threefish_512::clear() { zap(m_K); zap(m_T); } } /* * S-Box Tables for Tiger * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { const uint64_t Tiger::SBOX1[256] = { 0x02AAB17CF7E90C5E, 0xAC424B03E243A8EC, 0x72CD5BE30DD5FCD3, 0x6D019B93F6F97F3A, 0xCD9978FFD21F9193, 0x7573A1C9708029E2, 0xB164326B922A83C3, 0x46883EEE04915870, 0xEAACE3057103ECE6, 0xC54169B808A3535C, 0x4CE754918DDEC47C, 0x0AA2F4DFDC0DF40C, 0x10B76F18A74DBEFA, 0xC6CCB6235AD1AB6A, 0x13726121572FE2FF, 0x1A488C6F199D921E, 0x4BC9F9F4DA0007CA, 0x26F5E6F6E85241C7, 0x859079DBEA5947B6, 0x4F1885C5C99E8C92, 0xD78E761EA96F864B, 0x8E36428C52B5C17D, 0x69CF6827373063C1, 0xB607C93D9BB4C56E, 0x7D820E760E76B5EA, 0x645C9CC6F07FDC42, 0xBF38A078243342E0, 0x5F6B343C9D2E7D04, 0xF2C28AEB600B0EC6, 0x6C0ED85F7254BCAC, 0x71592281A4DB4FE5, 0x1967FA69CE0FED9F, 0xFD5293F8B96545DB, 0xC879E9D7F2A7600B, 0x860248920193194E, 0xA4F9533B2D9CC0B3, 0x9053836C15957613, 0xDB6DCF8AFC357BF1, 0x18BEEA7A7A370F57, 0x037117CA50B99066, 0x6AB30A9774424A35, 0xF4E92F02E325249B, 0x7739DB07061CCAE1, 0xD8F3B49CECA42A05, 0xBD56BE3F51382F73, 0x45FAED5843B0BB28, 0x1C813D5C11BF1F83, 0x8AF0E4B6D75FA169, 0x33EE18A487AD9999, 0x3C26E8EAB1C94410, 0xB510102BC0A822F9, 0x141EEF310CE6123B, 0xFC65B90059DDB154, 0xE0158640C5E0E607, 0x884E079826C3A3CF, 0x930D0D9523C535FD, 0x35638D754E9A2B00, 0x4085FCCF40469DD5, 0xC4B17AD28BE23A4C, 0xCAB2F0FC6A3E6A2E, 0x2860971A6B943FCD, 0x3DDE6EE212E30446, 0x6222F32AE01765AE, 0x5D550BB5478308FE, 0xA9EFA98DA0EDA22A, 0xC351A71686C40DA7, 0x1105586D9C867C84, 0xDCFFEE85FDA22853, 0xCCFBD0262C5EEF76, 0xBAF294CB8990D201, 0xE69464F52AFAD975, 0x94B013AFDF133E14, 0x06A7D1A32823C958, 0x6F95FE5130F61119, 0xD92AB34E462C06C0, 0xED7BDE33887C71D2, 0x79746D6E6518393E, 0x5BA419385D713329, 0x7C1BA6B948A97564, 0x31987C197BFDAC67, 0xDE6C23C44B053D02, 0x581C49FED002D64D, 0xDD474D6338261571, 0xAA4546C3E473D062, 0x928FCE349455F860, 0x48161BBACAAB94D9, 0x63912430770E6F68, 0x6EC8A5E602C6641C, 0x87282515337DDD2B, 0x2CDA6B42034B701B, 0xB03D37C181CB096D, 0xE108438266C71C6F, 0x2B3180C7EB51B255, 0xDF92B82F96C08BBC, 0x5C68C8C0A632F3BA, 0x5504CC861C3D0556, 0xABBFA4E55FB26B8F, 0x41848B0AB3BACEB4, 0xB334A273AA445D32, 0xBCA696F0A85AD881, 0x24F6EC65B528D56C, 0x0CE1512E90F4524A, 0x4E9DD79D5506D35A, 0x258905FAC6CE9779, 0x2019295B3E109B33, 0xF8A9478B73A054CC, 0x2924F2F934417EB0, 0x3993357D536D1BC4, 0x38A81AC21DB6FF8B, 0x47C4FBF17D6016BF, 0x1E0FAADD7667E3F5, 0x7ABCFF62938BEB96, 0xA78DAD948FC179C9, 0x8F1F98B72911E50D, 0x61E48EAE27121A91, 0x4D62F7AD31859808, 0xECEBA345EF5CEAEB, 0xF5CEB25EBC9684CE, 0xF633E20CB7F76221, 0xA32CDF06AB8293E4, 0x985A202CA5EE2CA4, 0xCF0B8447CC8A8FB1, 0x9F765244979859A3, 0xA8D516B1A1240017, 0x0BD7BA3EBB5DC726, 0xE54BCA55B86ADB39, 0x1D7A3AFD6C478063, 0x519EC608E7669EDD, 0x0E5715A2D149AA23, 0x177D4571848FF194, 0xEEB55F3241014C22, 0x0F5E5CA13A6E2EC2, 0x8029927B75F5C361, 0xAD139FABC3D6E436, 0x0D5DF1A94CCF402F, 0x3E8BD948BEA5DFC8, 0xA5A0D357BD3FF77E, 0xA2D12E251F74F645, 0x66FD9E525E81A082, 0x2E0C90CE7F687A49, 0xC2E8BCBEBA973BC5, 0x000001BCE509745F, 0x423777BBE6DAB3D6, 0xD1661C7EAEF06EB5, 0xA1781F354DAACFD8, 0x2D11284A2B16AFFC, 0xF1FC4F67FA891D1F, 0x73ECC25DCB920ADA, 0xAE610C22C2A12651, 0x96E0A810D356B78A, 0x5A9A381F2FE7870F, 0xD5AD62EDE94E5530, 0xD225E5E8368D1427, 0x65977B70C7AF4631, 0x99F889B2DE39D74F, 0x233F30BF54E1D143, 0x9A9675D3D9A63C97, 0x5470554FF334F9A8, 0x166ACB744A4F5688, 0x70C74CAAB2E4AEAD, 0xF0D091646F294D12, 0x57B82A89684031D1, 0xEFD95A5A61BE0B6B, 0x2FBD12E969F2F29A, 0x9BD37013FEFF9FE8, 0x3F9B0404D6085A06, 0x4940C1F3166CFE15, 0x09542C4DCDF3DEFB, 0xB4C5218385CD5CE3, 0xC935B7DC4462A641, 0x3417F8A68ED3B63F, 0xB80959295B215B40, 0xF99CDAEF3B8C8572, 0x018C0614F8FCB95D, 0x1B14ACCD1A3ACDF3, 0x84D471F200BB732D, 0xC1A3110E95E8DA16, 0x430A7220BF1A82B8, 0xB77E090D39DF210E, 0x5EF4BD9F3CD05E9D, 0x9D4FF6DA7E57A444, 0xDA1D60E183D4A5F8, 0xB287C38417998E47, 0xFE3EDC121BB31886, 0xC7FE3CCC980CCBEF, 0xE46FB590189BFD03, 0x3732FD469A4C57DC, 0x7EF700A07CF1AD65, 0x59C64468A31D8859, 0x762FB0B4D45B61F6, 0x155BAED099047718, 0x68755E4C3D50BAA6, 0xE9214E7F22D8B4DF, 0x2ADDBF532EAC95F4, 0x32AE3909B4BD0109, 0x834DF537B08E3450, 0xFA209DA84220728D, 0x9E691D9B9EFE23F7, 0x0446D288C4AE8D7F, 0x7B4CC524E169785B, 0x21D87F0135CA1385, 0xCEBB400F137B8AA5, 0x272E2B66580796BE, 0x3612264125C2B0DE, 0x057702BDAD1EFBB2, 0xD4BABB8EACF84BE9, 0x91583139641BC67B, 0x8BDC2DE08036E024, 0x603C8156F49F68ED, 0xF7D236F7DBEF5111, 0x9727C4598AD21E80, 0xA08A0896670A5FD7, 0xCB4A8F4309EBA9CB, 0x81AF564B0F7036A1, 0xC0B99AA778199ABD, 0x959F1EC83FC8E952, 0x8C505077794A81B9, 0x3ACAAF8F056338F0, 0x07B43F50627A6778, 0x4A44AB49F5ECCC77, 0x3BC3D6E4B679EE98, 0x9CC0D4D1CF14108C, 0x4406C00B206BC8A0, 0x82A18854C8D72D89, 0x67E366B35C3C432C, 0xB923DD61102B37F2, 0x56AB2779D884271D, 0xBE83E1B0FF1525AF, 0xFB7C65D4217E49A9, 0x6BDBE0E76D48E7D4, 0x08DF828745D9179E, 0x22EA6A9ADD53BD34, 0xE36E141C5622200A, 0x7F805D1B8CB750EE, 0xAFE5C7A59F58E837, 0xE27F996A4FB1C23C, 0xD3867DFB0775F0D0, 0xD0E673DE6E88891A, 0x123AEB9EAFB86C25, 0x30F1D5D5C145B895, 0xBB434A2DEE7269E7, 0x78CB67ECF931FA38, 0xF33B0372323BBF9C, 0x52D66336FB279C74, 0x505F33AC0AFB4EAA, 0xE8A5CD99A2CCE187, 0x534974801E2D30BB, 0x8D2D5711D5876D90, 0x1F1A412891BC038E, 0xD6E2E71D82E56648, 0x74036C3A497732B7, 0x89B67ED96361F5AB, 0xFFED95D8F1EA02A2, 0xE72B3BD61464D43D, 0xA6300F170BDC4820, 0xEBC18760ED78A77A }; const uint64_t Tiger::SBOX2[256] = { 0xE6A6BE5A05A12138, 0xB5A122A5B4F87C98, 0x563C6089140B6990, 0x4C46CB2E391F5DD5, 0xD932ADDBC9B79434, 0x08EA70E42015AFF5, 0xD765A6673E478CF1, 0xC4FB757EAB278D99, 0xDF11C6862D6E0692, 0xDDEB84F10D7F3B16, 0x6F2EF604A665EA04, 0x4A8E0F0FF0E0DFB3, 0xA5EDEEF83DBCBA51, 0xFC4F0A2A0EA4371E, 0xE83E1DA85CB38429, 0xDC8FF882BA1B1CE2, 0xCD45505E8353E80D, 0x18D19A00D4DB0717, 0x34A0CFEDA5F38101, 0x0BE77E518887CAF2, 0x1E341438B3C45136, 0xE05797F49089CCF9, 0xFFD23F9DF2591D14, 0x543DDA228595C5CD, 0x661F81FD99052A33, 0x8736E641DB0F7B76, 0x15227725418E5307, 0xE25F7F46162EB2FA, 0x48A8B2126C13D9FE, 0xAFDC541792E76EEA, 0x03D912BFC6D1898F, 0x31B1AAFA1B83F51B, 0xF1AC2796E42AB7D9, 0x40A3A7D7FCD2EBAC, 0x1056136D0AFBBCC5, 0x7889E1DD9A6D0C85, 0xD33525782A7974AA, 0xA7E25D09078AC09B, 0xBD4138B3EAC6EDD0, 0x920ABFBE71EB9E70, 0xA2A5D0F54FC2625C, 0xC054E36B0B1290A3, 0xF6DD59FF62FE932B, 0x3537354511A8AC7D, 0xCA845E9172FADCD4, 0x84F82B60329D20DC, 0x79C62CE1CD672F18, 0x8B09A2ADD124642C, 0xD0C1E96A19D9E726, 0x5A786A9B4BA9500C, 0x0E020336634C43F3, 0xC17B474AEB66D822, 0x6A731AE3EC9BAAC2, 0x8226667AE0840258, 0x67D4567691CAECA5, 0x1D94155C4875ADB5, 0x6D00FD985B813FDF, 0x51286EFCB774CD06, 0x5E8834471FA744AF, 0xF72CA0AEE761AE2E, 0xBE40E4CDAEE8E09A, 0xE9970BBB5118F665, 0x726E4BEB33DF1964, 0x703B000729199762, 0x4631D816F5EF30A7, 0xB880B5B51504A6BE, 0x641793C37ED84B6C, 0x7B21ED77F6E97D96, 0x776306312EF96B73, 0xAE528948E86FF3F4, 0x53DBD7F286A3F8F8, 0x16CADCE74CFC1063, 0x005C19BDFA52C6DD, 0x68868F5D64D46AD3, 0x3A9D512CCF1E186A, 0x367E62C2385660AE, 0xE359E7EA77DCB1D7, 0x526C0773749ABE6E, 0x735AE5F9D09F734B, 0x493FC7CC8A558BA8, 0xB0B9C1533041AB45, 0x321958BA470A59BD, 0x852DB00B5F46C393, 0x91209B2BD336B0E5, 0x6E604F7D659EF19F, 0xB99A8AE2782CCB24, 0xCCF52AB6C814C4C7, 0x4727D9AFBE11727B, 0x7E950D0C0121B34D, 0x756F435670AD471F, 0xF5ADD442615A6849, 0x4E87E09980B9957A, 0x2ACFA1DF50AEE355, 0xD898263AFD2FD556, 0xC8F4924DD80C8FD6, 0xCF99CA3D754A173A, 0xFE477BACAF91BF3C, 0xED5371F6D690C12D, 0x831A5C285E687094, 0xC5D3C90A3708A0A4, 0x0F7F903717D06580, 0x19F9BB13B8FDF27F, 0xB1BD6F1B4D502843, 0x1C761BA38FFF4012, 0x0D1530C4E2E21F3B, 0x8943CE69A7372C8A, 0xE5184E11FEB5CE66, 0x618BDB80BD736621, 0x7D29BAD68B574D0B, 0x81BB613E25E6FE5B, 0x071C9C10BC07913F, 0xC7BEEB7909AC2D97, 0xC3E58D353BC5D757, 0xEB017892F38F61E8, 0xD4EFFB9C9B1CC21A, 0x99727D26F494F7AB, 0xA3E063A2956B3E03, 0x9D4A8B9A4AA09C30, 0x3F6AB7D500090FB4, 0x9CC0F2A057268AC0, 0x3DEE9D2DEDBF42D1, 0x330F49C87960A972, 0xC6B2720287421B41, 0x0AC59EC07C00369C, 0xEF4EAC49CB353425, 0xF450244EEF0129D8, 0x8ACC46E5CAF4DEB6, 0x2FFEAB63989263F7, 0x8F7CB9FE5D7A4578, 0x5BD8F7644E634635, 0x427A7315BF2DC900, 0x17D0C4AA2125261C, 0x3992486C93518E50, 0xB4CBFEE0A2D7D4C3, 0x7C75D6202C5DDD8D, 0xDBC295D8E35B6C61, 0x60B369D302032B19, 0xCE42685FDCE44132, 0x06F3DDB9DDF65610, 0x8EA4D21DB5E148F0, 0x20B0FCE62FCD496F, 0x2C1B912358B0EE31, 0xB28317B818F5A308, 0xA89C1E189CA6D2CF, 0x0C6B18576AAADBC8, 0xB65DEAA91299FAE3, 0xFB2B794B7F1027E7, 0x04E4317F443B5BEB, 0x4B852D325939D0A6, 0xD5AE6BEEFB207FFC, 0x309682B281C7D374, 0xBAE309A194C3B475, 0x8CC3F97B13B49F05, 0x98A9422FF8293967, 0x244B16B01076FF7C, 0xF8BF571C663D67EE, 0x1F0D6758EEE30DA1, 0xC9B611D97ADEB9B7, 0xB7AFD5887B6C57A2, 0x6290AE846B984FE1, 0x94DF4CDEACC1A5FD, 0x058A5BD1C5483AFF, 0x63166CC142BA3C37, 0x8DB8526EB2F76F40, 0xE10880036F0D6D4E, 0x9E0523C9971D311D, 0x45EC2824CC7CD691, 0x575B8359E62382C9, 0xFA9E400DC4889995, 0xD1823ECB45721568, 0xDAFD983B8206082F, 0xAA7D29082386A8CB, 0x269FCD4403B87588, 0x1B91F5F728BDD1E0, 0xE4669F39040201F6, 0x7A1D7C218CF04ADE, 0x65623C29D79CE5CE, 0x2368449096C00BB1, 0xAB9BF1879DA503BA, 0xBC23ECB1A458058E, 0x9A58DF01BB401ECC, 0xA070E868A85F143D, 0x4FF188307DF2239E, 0x14D565B41A641183, 0xEE13337452701602, 0x950E3DCF3F285E09, 0x59930254B9C80953, 0x3BF299408930DA6D, 0xA955943F53691387, 0xA15EDECAA9CB8784, 0x29142127352BE9A0, 0x76F0371FFF4E7AFB, 0x0239F450274F2228, 0xBB073AF01D5E868B, 0xBFC80571C10E96C1, 0xD267088568222E23, 0x9671A3D48E80B5B0, 0x55B5D38AE193BB81, 0x693AE2D0A18B04B8, 0x5C48B4ECADD5335F, 0xFD743B194916A1CA, 0x2577018134BE98C4, 0xE77987E83C54A4AD, 0x28E11014DA33E1B9, 0x270CC59E226AA213, 0x71495F756D1A5F60, 0x9BE853FB60AFEF77, 0xADC786A7F7443DBF, 0x0904456173B29A82, 0x58BC7A66C232BD5E, 0xF306558C673AC8B2, 0x41F639C6B6C9772A, 0x216DEFE99FDA35DA, 0x11640CC71C7BE615, 0x93C43694565C5527, 0xEA038E6246777839, 0xF9ABF3CE5A3E2469, 0x741E768D0FD312D2, 0x0144B883CED652C6, 0xC20B5A5BA33F8552, 0x1AE69633C3435A9D, 0x97A28CA4088CFDEC, 0x8824A43C1E96F420, 0x37612FA66EEEA746, 0x6B4CB165F9CF0E5A, 0x43AA1C06A0ABFB4A, 0x7F4DC26FF162796B, 0x6CBACC8E54ED9B0F, 0xA6B7FFEFD2BB253E, 0x2E25BC95B0A29D4F, 0x86D6A58BDEF1388C, 0xDED74AC576B6F054, 0x8030BDBC2B45805D, 0x3C81AF70E94D9289, 0x3EFF6DDA9E3100DB, 0xB38DC39FDFCC8847, 0x123885528D17B87E, 0xF2DA0ED240B1B642, 0x44CEFADCD54BF9A9, 0x1312200E433C7EE6, 0x9FFCC84F3A78C748, 0xF0CD1F72248576BB, 0xEC6974053638CFE4, 0x2BA7B67C0CEC4E4C, 0xAC2F4DF3E5CE32ED, 0xCB33D14326EA4C11, 0xA4E9044CC77E58BC, 0x5F513293D934FCEF, 0x5DC9645506E55444, 0x50DE418F317DE40A, 0x388CB31A69DDE259, 0x2DB4A83455820A86, 0x9010A91E84711AE9, 0x4DF7F0B7B1498371, 0xD62A2EABC0977179, 0x22FAC097AA8D5C0E }; const uint64_t Tiger::SBOX3[256] = { 0xF49FCC2FF1DAF39B, 0x487FD5C66FF29281, 0xE8A30667FCDCA83F, 0x2C9B4BE3D2FCCE63, 0xDA3FF74B93FBBBC2, 0x2FA165D2FE70BA66, 0xA103E279970E93D4, 0xBECDEC77B0E45E71, 0xCFB41E723985E497, 0xB70AAA025EF75017, 0xD42309F03840B8E0, 0x8EFC1AD035898579, 0x96C6920BE2B2ABC5, 0x66AF4163375A9172, 0x2174ABDCCA7127FB, 0xB33CCEA64A72FF41, 0xF04A4933083066A5, 0x8D970ACDD7289AF5, 0x8F96E8E031C8C25E, 0xF3FEC02276875D47, 0xEC7BF310056190DD, 0xF5ADB0AEBB0F1491, 0x9B50F8850FD58892, 0x4975488358B74DE8, 0xA3354FF691531C61, 0x0702BBE481D2C6EE, 0x89FB24057DEDED98, 0xAC3075138596E902, 0x1D2D3580172772ED, 0xEB738FC28E6BC30D, 0x5854EF8F63044326, 0x9E5C52325ADD3BBE, 0x90AA53CF325C4623, 0xC1D24D51349DD067, 0x2051CFEEA69EA624, 0x13220F0A862E7E4F, 0xCE39399404E04864, 0xD9C42CA47086FCB7, 0x685AD2238A03E7CC, 0x066484B2AB2FF1DB, 0xFE9D5D70EFBF79EC, 0x5B13B9DD9C481854, 0x15F0D475ED1509AD, 0x0BEBCD060EC79851, 0xD58C6791183AB7F8, 0xD1187C5052F3EEE4, 0xC95D1192E54E82FF, 0x86EEA14CB9AC6CA2, 0x3485BEB153677D5D, 0xDD191D781F8C492A, 0xF60866BAA784EBF9, 0x518F643BA2D08C74, 0x8852E956E1087C22, 0xA768CB8DC410AE8D, 0x38047726BFEC8E1A, 0xA67738B4CD3B45AA, 0xAD16691CEC0DDE19, 0xC6D4319380462E07, 0xC5A5876D0BA61938, 0x16B9FA1FA58FD840, 0x188AB1173CA74F18, 0xABDA2F98C99C021F, 0x3E0580AB134AE816, 0x5F3B05B773645ABB, 0x2501A2BE5575F2F6, 0x1B2F74004E7E8BA9, 0x1CD7580371E8D953, 0x7F6ED89562764E30, 0xB15926FF596F003D, 0x9F65293DA8C5D6B9, 0x6ECEF04DD690F84C, 0x4782275FFF33AF88, 0xE41433083F820801, 0xFD0DFE409A1AF9B5, 0x4325A3342CDB396B, 0x8AE77E62B301B252, 0xC36F9E9F6655615A, 0x85455A2D92D32C09, 0xF2C7DEA949477485, 0x63CFB4C133A39EBA, 0x83B040CC6EBC5462, 0x3B9454C8FDB326B0, 0x56F56A9E87FFD78C, 0x2DC2940D99F42BC6, 0x98F7DF096B096E2D, 0x19A6E01E3AD852BF, 0x42A99CCBDBD4B40B, 0xA59998AF45E9C559, 0x366295E807D93186, 0x6B48181BFAA1F773, 0x1FEC57E2157A0A1D, 0x4667446AF6201AD5, 0xE615EBCACFB0F075, 0xB8F31F4F68290778, 0x22713ED6CE22D11E, 0x3057C1A72EC3C93B, 0xCB46ACC37C3F1F2F, 0xDBB893FD02AAF50E, 0x331FD92E600B9FCF, 0xA498F96148EA3AD6, 0xA8D8426E8B6A83EA, 0xA089B274B7735CDC, 0x87F6B3731E524A11, 0x118808E5CBC96749, 0x9906E4C7B19BD394, 0xAFED7F7E9B24A20C, 0x6509EADEEB3644A7, 0x6C1EF1D3E8EF0EDE, 0xB9C97D43E9798FB4, 0xA2F2D784740C28A3, 0x7B8496476197566F, 0x7A5BE3E6B65F069D, 0xF96330ED78BE6F10, 0xEEE60DE77A076A15, 0x2B4BEE4AA08B9BD0, 0x6A56A63EC7B8894E, 0x02121359BA34FEF4, 0x4CBF99F8283703FC, 0x398071350CAF30C8, 0xD0A77A89F017687A, 0xF1C1A9EB9E423569, 0x8C7976282DEE8199, 0x5D1737A5DD1F7ABD, 0x4F53433C09A9FA80, 0xFA8B0C53DF7CA1D9, 0x3FD9DCBC886CCB77, 0xC040917CA91B4720, 0x7DD00142F9D1DCDF, 0x8476FC1D4F387B58, 0x23F8E7C5F3316503, 0x032A2244E7E37339, 0x5C87A5D750F5A74B, 0x082B4CC43698992E, 0xDF917BECB858F63C, 0x3270B8FC5BF86DDA, 0x10AE72BB29B5DD76, 0x576AC94E7700362B, 0x1AD112DAC61EFB8F, 0x691BC30EC5FAA427, 0xFF246311CC327143, 0x3142368E30E53206, 0x71380E31E02CA396, 0x958D5C960AAD76F1, 0xF8D6F430C16DA536, 0xC8FFD13F1BE7E1D2, 0x7578AE66004DDBE1, 0x05833F01067BE646, 0xBB34B5AD3BFE586D, 0x095F34C9A12B97F0, 0x247AB64525D60CA8, 0xDCDBC6F3017477D1, 0x4A2E14D4DECAD24D, 0xBDB5E6D9BE0A1EEB, 0x2A7E70F7794301AB, 0xDEF42D8A270540FD, 0x01078EC0A34C22C1, 0xE5DE511AF4C16387, 0x7EBB3A52BD9A330A, 0x77697857AA7D6435, 0x004E831603AE4C32, 0xE7A21020AD78E312, 0x9D41A70C6AB420F2, 0x28E06C18EA1141E6, 0xD2B28CBD984F6B28, 0x26B75F6C446E9D83, 0xBA47568C4D418D7F, 0xD80BADBFE6183D8E, 0x0E206D7F5F166044, 0xE258A43911CBCA3E, 0x723A1746B21DC0BC, 0xC7CAA854F5D7CDD3, 0x7CAC32883D261D9C, 0x7690C26423BA942C, 0x17E55524478042B8, 0xE0BE477656A2389F, 0x4D289B5E67AB2DA0, 0x44862B9C8FBBFD31, 0xB47CC8049D141365, 0x822C1B362B91C793, 0x4EB14655FB13DFD8, 0x1ECBBA0714E2A97B, 0x6143459D5CDE5F14, 0x53A8FBF1D5F0AC89, 0x97EA04D81C5E5B00, 0x622181A8D4FDB3F3, 0xE9BCD341572A1208, 0x1411258643CCE58A, 0x9144C5FEA4C6E0A4, 0x0D33D06565CF620F, 0x54A48D489F219CA1, 0xC43E5EAC6D63C821, 0xA9728B3A72770DAF, 0xD7934E7B20DF87EF, 0xE35503B61A3E86E5, 0xCAE321FBC819D504, 0x129A50B3AC60BFA6, 0xCD5E68EA7E9FB6C3, 0xB01C90199483B1C7, 0x3DE93CD5C295376C, 0xAED52EDF2AB9AD13, 0x2E60F512C0A07884, 0xBC3D86A3E36210C9, 0x35269D9B163951CE, 0x0C7D6E2AD0CDB5FA, 0x59E86297D87F5733, 0x298EF221898DB0E7, 0x55000029D1A5AA7E, 0x8BC08AE1B5061B45, 0xC2C31C2B6C92703A, 0x94CC596BAF25EF42, 0x0A1D73DB22540456, 0x04B6A0F9D9C4179A, 0xEFFDAFA2AE3D3C60, 0xF7C8075BB49496C4, 0x9CC5C7141D1CD4E3, 0x78BD1638218E5534, 0xB2F11568F850246A, 0xEDFABCFA9502BC29, 0x796CE5F2DA23051B, 0xAAE128B0DC93537C, 0x3A493DA0EE4B29AE, 0xB5DF6B2C416895D7, 0xFCABBD25122D7F37, 0x70810B58105DC4B1, 0xE10FDD37F7882A90, 0x524DCAB5518A3F5C, 0x3C9E85878451255B, 0x4029828119BD34E2, 0x74A05B6F5D3CECCB, 0xB610021542E13ECA, 0x0FF979D12F59E2AC, 0x6037DA27E4F9CC50, 0x5E92975A0DF1847D, 0xD66DE190D3E623FE, 0x5032D6B87B568048, 0x9A36B7CE8235216E, 0x80272A7A24F64B4A, 0x93EFED8B8C6916F7, 0x37DDBFF44CCE1555, 0x4B95DB5D4B99BD25, 0x92D3FDA169812FC0, 0xFB1A4A9A90660BB6, 0x730C196946A4B9B2, 0x81E289AA7F49DA68, 0x64669A0F83B1A05F, 0x27B3FF7D9644F48B, 0xCC6B615C8DB675B3, 0x674F20B9BCEBBE95, 0x6F31238275655982, 0x5AE488713E45CF05, 0xBF619F9954C21157, 0xEABAC46040A8EAE9, 0x454C6FE9F2C0C1CD, 0x419CF6496412691C, 0xD3DC3BEF265B0F70, 0x6D0E60F5C3578A9E }; const uint64_t Tiger::SBOX4[256] = { 0x5B0E608526323C55, 0x1A46C1A9FA1B59F5, 0xA9E245A17C4C8FFA, 0x65CA5159DB2955D7, 0x05DB0A76CE35AFC2, 0x81EAC77EA9113D45, 0x528EF88AB6AC0A0D, 0xA09EA253597BE3FF, 0x430DDFB3AC48CD56, 0xC4B3A67AF45CE46F, 0x4ECECFD8FBE2D05E, 0x3EF56F10B39935F0, 0x0B22D6829CD619C6, 0x17FD460A74DF2069, 0x6CF8CC8E8510ED40, 0xD6C824BF3A6ECAA7, 0x61243D581A817049, 0x048BACB6BBC163A2, 0xD9A38AC27D44CC32, 0x7FDDFF5BAAF410AB, 0xAD6D495AA804824B, 0xE1A6A74F2D8C9F94, 0xD4F7851235DEE8E3, 0xFD4B7F886540D893, 0x247C20042AA4BFDA, 0x096EA1C517D1327C, 0xD56966B4361A6685, 0x277DA5C31221057D, 0x94D59893A43ACFF7, 0x64F0C51CCDC02281, 0x3D33BCC4FF6189DB, 0xE005CB184CE66AF1, 0xFF5CCD1D1DB99BEA, 0xB0B854A7FE42980F, 0x7BD46A6A718D4B9F, 0xD10FA8CC22A5FD8C, 0xD31484952BE4BD31, 0xC7FA975FCB243847, 0x4886ED1E5846C407, 0x28CDDB791EB70B04, 0xC2B00BE2F573417F, 0x5C9590452180F877, 0x7A6BDDFFF370EB00, 0xCE509E38D6D9D6A4, 0xEBEB0F00647FA702, 0x1DCC06CF76606F06, 0xE4D9F28BA286FF0A, 0xD85A305DC918C262, 0x475B1D8732225F54, 0x2D4FB51668CCB5FE, 0xA679B9D9D72BBA20, 0x53841C0D912D43A5, 0x3B7EAA48BF12A4E8, 0x781E0E47F22F1DDF, 0xEFF20CE60AB50973, 0x20D261D19DFFB742, 0x16A12B03062A2E39, 0x1960EB2239650495, 0x251C16FED50EB8B8, 0x9AC0C330F826016E, 0xED152665953E7671, 0x02D63194A6369570, 0x5074F08394B1C987, 0x70BA598C90B25CE1, 0x794A15810B9742F6, 0x0D5925E9FCAF8C6C, 0x3067716CD868744E, 0x910AB077E8D7731B, 0x6A61BBDB5AC42F61, 0x93513EFBF0851567, 0xF494724B9E83E9D5, 0xE887E1985C09648D, 0x34B1D3C675370CFD, 0xDC35E433BC0D255D, 0xD0AAB84234131BE0, 0x08042A50B48B7EAF, 0x9997C4EE44A3AB35, 0x829A7B49201799D0, 0x263B8307B7C54441, 0x752F95F4FD6A6CA6, 0x927217402C08C6E5, 0x2A8AB754A795D9EE, 0xA442F7552F72943D, 0x2C31334E19781208, 0x4FA98D7CEAEE6291, 0x55C3862F665DB309, 0xBD0610175D53B1F3, 0x46FE6CB840413F27, 0x3FE03792DF0CFA59, 0xCFE700372EB85E8F, 0xA7BE29E7ADBCE118, 0xE544EE5CDE8431DD, 0x8A781B1B41F1873E, 0xA5C94C78A0D2F0E7, 0x39412E2877B60728, 0xA1265EF3AFC9A62C, 0xBCC2770C6A2506C5, 0x3AB66DD5DCE1CE12, 0xE65499D04A675B37, 0x7D8F523481BFD216, 0x0F6F64FCEC15F389, 0x74EFBE618B5B13C8, 0xACDC82B714273E1D, 0xDD40BFE003199D17, 0x37E99257E7E061F8, 0xFA52626904775AAA, 0x8BBBF63A463D56F9, 0xF0013F1543A26E64, 0xA8307E9F879EC898, 0xCC4C27A4150177CC, 0x1B432F2CCA1D3348, 0xDE1D1F8F9F6FA013, 0x606602A047A7DDD6, 0xD237AB64CC1CB2C7, 0x9B938E7225FCD1D3, 0xEC4E03708E0FF476, 0xFEB2FBDA3D03C12D, 0xAE0BCED2EE43889A, 0x22CB8923EBFB4F43, 0x69360D013CF7396D, 0x855E3602D2D4E022, 0x073805BAD01F784C, 0x33E17A133852F546, 0xDF4874058AC7B638, 0xBA92B29C678AA14A, 0x0CE89FC76CFAADCD, 0x5F9D4E0908339E34, 0xF1AFE9291F5923B9, 0x6E3480F60F4A265F, 0xEEBF3A2AB29B841C, 0xE21938A88F91B4AD, 0x57DFEFF845C6D3C3, 0x2F006B0BF62CAAF2, 0x62F479EF6F75EE78, 0x11A55AD41C8916A9, 0xF229D29084FED453, 0x42F1C27B16B000E6, 0x2B1F76749823C074, 0x4B76ECA3C2745360, 0x8C98F463B91691BD, 0x14BCC93CF1ADE66A, 0x8885213E6D458397, 0x8E177DF0274D4711, 0xB49B73B5503F2951, 0x10168168C3F96B6B, 0x0E3D963B63CAB0AE, 0x8DFC4B5655A1DB14, 0xF789F1356E14DE5C, 0x683E68AF4E51DAC1, 0xC9A84F9D8D4B0FD9, 0x3691E03F52A0F9D1, 0x5ED86E46E1878E80, 0x3C711A0E99D07150, 0x5A0865B20C4E9310, 0x56FBFC1FE4F0682E, 0xEA8D5DE3105EDF9B, 0x71ABFDB12379187A, 0x2EB99DE1BEE77B9C, 0x21ECC0EA33CF4523, 0x59A4D7521805C7A1, 0x3896F5EB56AE7C72, 0xAA638F3DB18F75DC, 0x9F39358DABE9808E, 0xB7DEFA91C00B72AC, 0x6B5541FD62492D92, 0x6DC6DEE8F92E4D5B, 0x353F57ABC4BEEA7E, 0x735769D6DA5690CE, 0x0A234AA642391484, 0xF6F9508028F80D9D, 0xB8E319A27AB3F215, 0x31AD9C1151341A4D, 0x773C22A57BEF5805, 0x45C7561A07968633, 0xF913DA9E249DBE36, 0xDA652D9B78A64C68, 0x4C27A97F3BC334EF, 0x76621220E66B17F4, 0x967743899ACD7D0B, 0xF3EE5BCAE0ED6782, 0x409F753600C879FC, 0x06D09A39B5926DB6, 0x6F83AEB0317AC588, 0x01E6CA4A86381F21, 0x66FF3462D19F3025, 0x72207C24DDFD3BFB, 0x4AF6B6D3E2ECE2EB, 0x9C994DBEC7EA08DE, 0x49ACE597B09A8BC4, 0xB38C4766CF0797BA, 0x131B9373C57C2A75, 0xB1822CCE61931E58, 0x9D7555B909BA1C0C, 0x127FAFDD937D11D2, 0x29DA3BADC66D92E4, 0xA2C1D57154C2ECBC, 0x58C5134D82F6FE24, 0x1C3AE3515B62274F, 0xE907C82E01CB8126, 0xF8ED091913E37FCB, 0x3249D8F9C80046C9, 0x80CF9BEDE388FB63, 0x1881539A116CF19E, 0x5103F3F76BD52457, 0x15B7E6F5AE47F7A8, 0xDBD7C6DED47E9CCF, 0x44E55C410228BB1A, 0xB647D4255EDB4E99, 0x5D11882BB8AAFC30, 0xF5098BBB29D3212A, 0x8FB5EA14E90296B3, 0x677B942157DD025A, 0xFB58E7C0A390ACB5, 0x89D3674C83BD4A01, 0x9E2DA4DF4BF3B93B, 0xFCC41E328CAB4829, 0x03F38C96BA582C52, 0xCAD1BDBD7FD85DB2, 0xBBB442C16082AE83, 0xB95FE86BA5DA9AB0, 0xB22E04673771A93F, 0x845358C9493152D8, 0xBE2A488697B4541E, 0x95A2DC2DD38E6966, 0xC02C11AC923C852B, 0x2388B1990DF2A87B, 0x7C8008FA1B4F37BE, 0x1F70D0C84D54E503, 0x5490ADEC7ECE57D4, 0x002B3C27D9063A3A, 0x7EAEA3848030A2BF, 0xC602326DED2003C0, 0x83A7287D69A94086, 0xC57A5FCB30F57A8A, 0xB56844E479EBE779, 0xA373B40F05DCBCE9, 0xD71A786E88570EE2, 0x879CBACDBDE8F6A0, 0x976AD1BCC164A32F, 0xAB21E25E9666D78B, 0x901063AAE5E5C33C, 0x9818B34448698D90, 0xE36487AE3E1E8ABB, 0xAFBDF931893BDCB4, 0x6345A0DC5FBBD519, 0x8628FE269B9465CA, 0x1E5D01603F9C51EC, 0x4DE44006A15049B7, 0xBF6C70E5F776CBB1, 0x411218F2EF552BED, 0xCB0C0708705A36A3, 0xE74D14754F986044, 0xCD56D9430EA8280E, 0xC12591D7535F5065, 0xC83223F1720AEF96, 0xC3A0396F7363A51F }; } /* * Tiger * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr Tiger::copy_state() const { return std::unique_ptr(new Tiger(*this)); } namespace { /* * Tiger Mixing Function */ inline void mix(secure_vector& X) { X[0] -= X[7] ^ 0xA5A5A5A5A5A5A5A5; X[1] ^= X[0]; X[2] += X[1]; X[3] -= X[2] ^ ((~X[1]) << 19); X[4] ^= X[3]; X[5] += X[4]; X[6] -= X[5] ^ ((~X[4]) >> 23); X[7] ^= X[6]; X[0] += X[7]; X[1] -= X[0] ^ ((~X[7]) << 19); X[2] ^= X[1]; X[3] += X[2]; X[4] -= X[3] ^ ((~X[2]) >> 23); X[5] ^= X[4]; X[6] += X[5]; X[7] -= X[6] ^ 0x0123456789ABCDEF; } } /* * Tiger Compression Function */ void Tiger::compress_n(const uint8_t input[], size_t blocks) { uint64_t A = m_digest[0], B = m_digest[1], C = m_digest[2]; for(size_t i = 0; i != blocks; ++i) { load_le(m_X.data(), input, m_X.size()); pass(A, B, C, m_X, 5); mix(m_X); pass(C, A, B, m_X, 7); mix(m_X); pass(B, C, A, m_X, 9); for(size_t j = 3; j != m_passes; ++j) { mix(m_X); pass(A, B, C, m_X, 9); uint64_t T = A; A = C; C = B; B = T; } A = (m_digest[0] ^= A); B = m_digest[1] = B - m_digest[1]; C = (m_digest[2] += C); input += hash_block_size(); } } /* * Copy out the digest */ void Tiger::copy_out(uint8_t output[]) { copy_out_vec_le(output, output_length(), m_digest); } /* * Tiger Pass */ void Tiger::pass(uint64_t& A, uint64_t& B, uint64_t& C, const secure_vector& X, uint8_t mul) { C ^= X[0]; A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; B *= mul; A ^= X[1]; B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; C *= mul; B ^= X[2]; C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; A *= mul; C ^= X[3]; A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; B *= mul; A ^= X[4]; B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; C *= mul; B ^= X[5]; C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; A *= mul; C ^= X[6]; A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; B *= mul; A ^= X[7]; B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; C *= mul; } /* * Clear memory of sensitive data */ void Tiger::clear() { MDx_HashFunction::clear(); zeroise(m_X); m_digest[0] = 0x0123456789ABCDEF; m_digest[1] = 0xFEDCBA9876543210; m_digest[2] = 0xF096A5B4C3B2E187; } /* * Return the name of this type */ std::string Tiger::name() const { return "Tiger(" + std::to_string(output_length()) + "," + std::to_string(m_passes) + ")"; } /* * Tiger Constructor */ Tiger::Tiger(size_t hash_len, size_t passes) : MDx_HashFunction(64, false, false), m_X(8), m_digest(3), m_hash_len(hash_len), m_passes(passes) { if(output_length() != 16 && output_length() != 20 && output_length() != 24) throw Invalid_Argument("Tiger: Illegal hash output size: " + std::to_string(output_length())); if(passes < 3) throw Invalid_Argument("Tiger: Invalid number of passes: " + std::to_string(passes)); clear(); } } /* * Credentials Manager * (C) 2011,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string Credentials_Manager::psk_identity_hint(const std::string&, const std::string&) { return ""; } std::string Credentials_Manager::psk_identity(const std::string&, const std::string&, const std::string&) { return ""; } SymmetricKey Credentials_Manager::psk(const std::string&, const std::string&, const std::string& identity) { throw Internal_Error("No PSK set for identity " + identity); } bool Credentials_Manager::attempt_srp(const std::string&, const std::string&) { return false; } std::string Credentials_Manager::srp_identifier(const std::string&, const std::string&) { return ""; } std::string Credentials_Manager::srp_password(const std::string&, const std::string&, const std::string&) { return ""; } bool Credentials_Manager::srp_verifier(const std::string&, const std::string&, const std::string&, std::string&, BigInt&, std::vector&, bool) { return false; } std::vector Credentials_Manager::find_cert_chain( const std::vector& key_types, const std::vector&, const std::string& type, const std::string& context) { return cert_chain(key_types, type, context); } std::vector Credentials_Manager::cert_chain( const std::vector&, const std::string&, const std::string&) { return std::vector(); } std::vector Credentials_Manager::cert_chain_single_type( const std::string& cert_key_type, const std::string& type, const std::string& context) { std::vector cert_types; cert_types.push_back(cert_key_type); return find_cert_chain(cert_types, std::vector(), type, context); } Private_Key* Credentials_Manager::private_key_for(const X509_Certificate&, const std::string&, const std::string&) { return nullptr; } std::vector Credentials_Manager::trusted_certificate_authorities( const std::string&, const std::string&) { return std::vector(); } } /* * Certificate Request Message * (C) 2004-2006,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { namespace { std::string cert_type_code_to_name(uint8_t code) { switch(code) { case 1: return "RSA"; case 2: return "DSA"; case 64: return "ECDSA"; default: return ""; // DH or something else } } uint8_t cert_type_name_to_code(const std::string& name) { if(name == "RSA") return 1; if(name == "DSA") return 2; if(name == "ECDSA") return 64; throw Invalid_Argument("Unknown cert type " + name); } } /** * Create a new Certificate Request message */ Certificate_Req::Certificate_Req(Handshake_IO& io, Handshake_Hash& hash, const Policy& policy, const std::vector& ca_certs, Protocol_Version version) : m_names(ca_certs), m_cert_key_types({ "RSA", "ECDSA", "DSA" }) { if(version.supports_negotiable_signature_algorithms()) { m_schemes = policy.allowed_signature_schemes(); } hash.update(io.send(*this)); } /** * Deserialize a Certificate Request message */ Certificate_Req::Certificate_Req(const std::vector& buf, Protocol_Version version) { if(buf.size() < 4) throw Decoding_Error("Certificate_Req: Bad certificate request"); TLS_Data_Reader reader("CertificateRequest", buf); std::vector cert_type_codes = reader.get_range_vector(1, 1, 255); for(size_t i = 0; i != cert_type_codes.size(); ++i) { const std::string cert_type_name = cert_type_code_to_name(cert_type_codes[i]); if(cert_type_name.empty()) // something we don't know continue; m_cert_key_types.emplace_back(cert_type_name); } if(version.supports_negotiable_signature_algorithms()) { const std::vector algs = reader.get_range_vector(2, 2, 65534); if(algs.size() % 2 != 0) throw Decoding_Error("Bad length for signature IDs in certificate request"); for(size_t i = 0; i != algs.size(); i += 2) { m_schemes.push_back(static_cast(make_uint16(algs[i], algs[i+1]))); } } const uint16_t purported_size = reader.get_uint16_t(); if(reader.remaining_bytes() != purported_size) throw Decoding_Error("Inconsistent length in certificate request"); while(reader.has_remaining()) { std::vector name_bits = reader.get_range_vector(2, 0, 65535); BER_Decoder decoder(name_bits.data(), name_bits.size()); X509_DN name; decoder.decode(name); m_names.emplace_back(name); } } /** * Serialize a Certificate Request message */ std::vector Certificate_Req::serialize() const { std::vector buf; std::vector cert_types; for(size_t i = 0; i != m_cert_key_types.size(); ++i) cert_types.push_back(cert_type_name_to_code(m_cert_key_types[i])); append_tls_length_value(buf, cert_types, 1); if(m_schemes.size() > 0) buf += Signature_Algorithms(m_schemes).serialize(Connection_Side::SERVER); std::vector encoded_names; for(size_t i = 0; i != m_names.size(); ++i) { DER_Encoder encoder; encoder.encode(m_names[i]); append_tls_length_value(encoded_names, encoder.get_contents(), 2); } append_tls_length_value(buf, encoded_names, 2); return buf; } } } /* * Certificate Status * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { Certificate_Status::Certificate_Status(const std::vector& buf) { if(buf.size() < 5) throw Decoding_Error("Invalid Certificate_Status message: too small"); if(buf[0] != 1) // not OCSP throw Decoding_Error("Unexpected Certificate_Status message: unexpected response type"); size_t len = make_uint32(0, buf[1], buf[2], buf[3]); // Verify the redundant length field... if(buf.size() != len + 4) throw Decoding_Error("Invalid Certificate_Status: invalid length field"); m_response.assign(buf.begin() + 4, buf.end()); } Certificate_Status::Certificate_Status(Handshake_IO& io, Handshake_Hash& hash, std::shared_ptr ocsp) : m_response(ocsp->raw_bits()) { hash.update(io.send(*this)); } Certificate_Status::Certificate_Status(Handshake_IO& io, Handshake_Hash& hash, const std::vector& raw_response_bytes) : m_response(raw_response_bytes) { hash.update(io.send(*this)); } std::vector Certificate_Status::serialize() const { if(m_response.size() > 0xFFFFFF) // unlikely throw Encoding_Error("OCSP response too long to encode in TLS"); const uint32_t response_len = static_cast(m_response.size()); std::vector buf; buf.push_back(1); // type OCSP for(size_t i = 1; i < 4; ++i) buf.push_back(get_byte(i, response_len)); buf += m_response; return buf; } } } /* * Certificate Verify Message * (C) 2004,2006,2011,2012 Jack Lloyd * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { /* * Create a new Certificate Verify message */ Certificate_Verify::Certificate_Verify(Handshake_IO& io, Handshake_State& state, const Policy& policy, RandomNumberGenerator& rng, const Private_Key* priv_key) { BOTAN_ASSERT_NONNULL(priv_key); std::pair format = state.choose_sig_format(*priv_key, m_scheme, true, policy); m_signature = state.callbacks().tls_sign_message(*priv_key, rng, format.first, format.second, state.hash().get_contents()); state.hash().update(io.send(*this)); } /* * Deserialize a Certificate Verify message */ Certificate_Verify::Certificate_Verify(const std::vector& buf, Protocol_Version version) { TLS_Data_Reader reader("CertificateVerify", buf); if(version.supports_negotiable_signature_algorithms()) { m_scheme = static_cast(reader.get_uint16_t()); } m_signature = reader.get_range(2, 0, 65535); reader.assert_done(); } /* * Serialize a Certificate Verify message */ std::vector Certificate_Verify::serialize() const { std::vector buf; if(m_scheme != Signature_Scheme::NONE) { const uint16_t scheme_code = static_cast(m_scheme); buf.push_back(get_byte(0, scheme_code)); buf.push_back(get_byte(1, scheme_code)); } if(m_signature.size() > 0xFFFF) throw Encoding_Error("Certificate_Verify signature too long to encode"); const uint16_t sig_len = static_cast(m_signature.size()); buf.push_back(get_byte(0, sig_len)); buf.push_back(get_byte(1, sig_len)); buf += m_signature; return buf; } /* * Verify a Certificate Verify message */ bool Certificate_Verify::verify(const X509_Certificate& cert, const Handshake_State& state, const Policy& policy) const { std::unique_ptr key(cert.subject_public_key()); policy.check_peer_key_acceptable(*key); std::pair format = state.parse_sig_format(*key.get(), m_scheme, true, policy); const bool signature_valid = state.callbacks().tls_verify_message(*key, format.first, format.second, state.hash().get_contents(), m_signature); #if defined(BOTAN_UNSAFE_FUZZER_MODE) BOTAN_UNUSED(signature_valid); return true; #else return signature_valid; #endif } } } /* * Certificate Message * (C) 2004-2006,2012,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { /** * Create a new Certificate message */ Certificate::Certificate(Handshake_IO& io, Handshake_Hash& hash, const std::vector& cert_list) : m_certs(cert_list) { hash.update(io.send(*this)); } /** * Deserialize a Certificate message */ Certificate::Certificate(const std::vector& buf, const Policy& policy) { if(buf.size() < 3) throw Decoding_Error("Certificate: Message malformed"); const size_t total_size = make_uint32(0, buf[0], buf[1], buf[2]); if(total_size != buf.size() - 3) throw Decoding_Error("Certificate: Message malformed"); const size_t max_size = policy.maximum_certificate_chain_size(); if(max_size > 0 && total_size > max_size) throw Decoding_Error("Certificate chain exceeds policy specified maximum size"); const uint8_t* certs = buf.data() + 3; while(size_t remaining_bytes = buf.data() + buf.size() - certs) { if(remaining_bytes < 3) throw Decoding_Error("Certificate: Message malformed"); const size_t cert_size = make_uint32(0, certs[0], certs[1], certs[2]); if(remaining_bytes < (3 + cert_size)) throw Decoding_Error("Certificate: Message malformed"); DataSource_Memory cert_buf(&certs[3], cert_size); m_certs.push_back(X509_Certificate(cert_buf)); certs += cert_size + 3; } /* * TLS 1.0 through 1.2 all seem to require that the certificate be * precisely a v3 certificate. In fact the strict wording would seem * to require that every certificate in the chain be v3. But often * the intermediates are outside of the control of the server. * But, require that the leaf certificate be v3 */ if(m_certs.size() > 0 && m_certs[0].x509_version() != 3) { throw TLS_Exception(Alert::BAD_CERTIFICATE, "The leaf certificate must be v3"); } } /** * Serialize a Certificate message */ std::vector Certificate::serialize() const { std::vector buf(3); for(size_t i = 0; i != m_certs.size(); ++i) { std::vector raw_cert = m_certs[i].BER_encode(); const size_t cert_size = raw_cert.size(); for(size_t j = 0; j != 3; ++j) { buf.push_back(get_byte(j+1, static_cast(cert_size))); } buf += raw_cert; } const size_t buf_size = buf.size() - 3; for(size_t i = 0; i != 3; ++i) buf[i] = get_byte(i+1, static_cast(buf_size)); return buf; } } } /* * TLS Hello Request and Client Hello Messages * (C) 2004-2011,2015,2016 Jack Lloyd * 2016 Matthias Gierlings * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { enum { TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, TLS_FALLBACK_SCSV = 0x5600 }; std::vector make_hello_random(RandomNumberGenerator& rng, const Policy& policy) { std::vector buf(32); rng.randomize(buf.data(), buf.size()); std::unique_ptr sha256 = HashFunction::create_or_throw("SHA-256"); sha256->update(buf); sha256->final(buf); if(policy.include_time_in_hello_random()) { const uint32_t time32 = static_cast( std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); store_be(time32, buf.data()); } return buf; } /* * Create a new Hello Request message */ Hello_Request::Hello_Request(Handshake_IO& io) { io.send(*this); } /* * Deserialize a Hello Request message */ Hello_Request::Hello_Request(const std::vector& buf) { if(buf.size()) throw Decoding_Error("Bad Hello_Request, has non-zero size"); } /* * Serialize a Hello Request message */ std::vector Hello_Request::serialize() const { return std::vector(); } /* * Create a new Client Hello message */ Client_Hello::Client_Hello(Handshake_IO& io, Handshake_Hash& hash, const Policy& policy, Callbacks& cb, RandomNumberGenerator& rng, const std::vector& reneg_info, const Client_Hello::Settings& client_settings, const std::vector& next_protocols) : m_version(client_settings.protocol_version()), m_random(make_hello_random(rng, policy)), m_suites(policy.ciphersuite_list(m_version, !client_settings.srp_identifier().empty())), m_comp_methods(1) { if(!policy.acceptable_protocol_version(m_version)) throw Internal_Error("Offering " + m_version.to_string() + " but our own policy does not accept it"); /* * Place all empty extensions in front to avoid a bug in some systems * which reject hellos when the last extension in the list is empty. */ m_extensions.add(new Extended_Master_Secret); m_extensions.add(new Session_Ticket()); if(policy.negotiate_encrypt_then_mac()) m_extensions.add(new Encrypt_then_MAC); m_extensions.add(new Renegotiation_Extension(reneg_info)); m_extensions.add(new Supported_Versions(m_version, policy)); if(client_settings.hostname() != "") m_extensions.add(new Server_Name_Indicator(client_settings.hostname())); if(policy.support_cert_status_message()) m_extensions.add(new Certificate_Status_Request({}, {})); if(reneg_info.empty() && !next_protocols.empty()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); if(m_version.supports_negotiable_signature_algorithms()) m_extensions.add(new Signature_Algorithms(policy.allowed_signature_schemes())); if(m_version.is_datagram_protocol()) m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles())); #if defined(BOTAN_HAS_SRP6) m_extensions.add(new SRP_Identifier(client_settings.srp_identifier())); #else if(!client_settings.srp_identifier().empty()) { throw Invalid_State("Attempting to initiate SRP session but TLS-SRP support disabled"); } #endif std::unique_ptr supported_groups(new Supported_Groups(policy.key_exchange_groups())); if(supported_groups->ec_groups().size() > 0) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } m_extensions.add(supported_groups.release()); cb.tls_modify_extensions(m_extensions, CLIENT); if(policy.send_fallback_scsv(client_settings.protocol_version())) m_suites.push_back(TLS_FALLBACK_SCSV); hash.update(io.send(*this)); } /* * Create a new Client Hello message (session resumption case) */ Client_Hello::Client_Hello(Handshake_IO& io, Handshake_Hash& hash, const Policy& policy, Callbacks& cb, RandomNumberGenerator& rng, const std::vector& reneg_info, const Session& session, const std::vector& next_protocols) : m_version(session.version()), m_session_id(session.session_id()), m_random(make_hello_random(rng, policy)), m_suites(policy.ciphersuite_list(m_version, (session.srp_identifier() != ""))), m_comp_methods(1) { if(!policy.acceptable_protocol_version(m_version)) throw Internal_Error("Offering " + m_version.to_string() + " but our own policy does not accept it"); if(!value_exists(m_suites, session.ciphersuite_code())) m_suites.push_back(session.ciphersuite_code()); /* We always add the EMS extension, even if not used in the original session. If the server understands it and follows the RFC it should reject our resume attempt and upgrade us to a new session with the EMS protection. */ m_extensions.add(new Extended_Master_Secret); m_extensions.add(new Renegotiation_Extension(reneg_info)); m_extensions.add(new Server_Name_Indicator(session.server_info().hostname())); m_extensions.add(new Session_Ticket(session.session_ticket())); if(policy.support_cert_status_message()) m_extensions.add(new Certificate_Status_Request({}, {})); std::unique_ptr supported_groups(new Supported_Groups(policy.key_exchange_groups())); if(supported_groups->ec_groups().size() > 0) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } m_extensions.add(supported_groups.release()); if(session.supports_encrypt_then_mac()) m_extensions.add(new Encrypt_then_MAC); #if defined(BOTAN_HAS_SRP6) m_extensions.add(new SRP_Identifier(session.srp_identifier())); #else if(!session.srp_identifier().empty()) { throw Invalid_State("Attempting to resume SRP session but TLS-SRP support disabled"); } #endif if(m_version.supports_negotiable_signature_algorithms()) m_extensions.add(new Signature_Algorithms(policy.allowed_signature_schemes())); if(reneg_info.empty() && !next_protocols.empty()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); cb.tls_modify_extensions(m_extensions, CLIENT); hash.update(io.send(*this)); } void Client_Hello::update_hello_cookie(const Hello_Verify_Request& hello_verify) { if(!m_version.is_datagram_protocol()) throw Invalid_State("Cannot use hello cookie with stream protocol"); m_hello_cookie = hello_verify.cookie(); } /* * Serialize a Client Hello message */ std::vector Client_Hello::serialize() const { std::vector buf; buf.push_back(m_version.major_version()); buf.push_back(m_version.minor_version()); buf += m_random; append_tls_length_value(buf, m_session_id, 1); if(m_version.is_datagram_protocol()) append_tls_length_value(buf, m_hello_cookie, 1); append_tls_length_value(buf, m_suites, 2); append_tls_length_value(buf, m_comp_methods, 1); /* * May not want to send extensions at all in some cases. If so, * should include SCSV value (if reneg info is empty, if not we are * renegotiating with a modern server) */ buf += m_extensions.serialize(Connection_Side::CLIENT); return buf; } std::vector Client_Hello::cookie_input_data() const { std::vector buf; buf.push_back(m_version.major_version()); buf.push_back(m_version.minor_version()); buf += m_random; append_tls_length_value(buf, m_session_id, 1); append_tls_length_value(buf, m_suites, 2); append_tls_length_value(buf, m_comp_methods, 1); // Here we don't serialize the extensions since the client extensions // may contain values we don't know how to serialize back. return buf; } /* * Read a counterparty client hello */ Client_Hello::Client_Hello(const std::vector& buf) { if(buf.size() < 41) throw Decoding_Error("Client_Hello: Packet corrupted"); TLS_Data_Reader reader("ClientHello", buf); const uint8_t major_version = reader.get_byte(); const uint8_t minor_version = reader.get_byte(); m_version = Protocol_Version(major_version, minor_version); m_random = reader.get_fixed(32); m_session_id = reader.get_range(1, 0, 32); if(m_version.is_datagram_protocol()) m_hello_cookie = reader.get_range(1, 0, 255); m_suites = reader.get_range_vector(2, 1, 32767); m_comp_methods = reader.get_range_vector(1, 1, 255); m_extensions.deserialize(reader, Connection_Side::CLIENT); if(offered_suite(static_cast(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) { if(Renegotiation_Extension* reneg = m_extensions.get()) { if(!reneg->renegotiation_info().empty()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client sent renegotiation SCSV and non-empty extension"); } else { // add fake extension m_extensions.add(new Renegotiation_Extension()); } } } bool Client_Hello::sent_fallback_scsv() const { return offered_suite(static_cast(TLS_FALLBACK_SCSV)); } /* * Check if we offered this ciphersuite */ bool Client_Hello::offered_suite(uint16_t ciphersuite) const { for(size_t i = 0; i != m_suites.size(); ++i) if(m_suites[i] == ciphersuite) return true; return false; } std::vector Client_Hello::signature_schemes() const { std::vector schemes; if(Signature_Algorithms* sigs = m_extensions.get()) { schemes = sigs->supported_schemes(); } return schemes; } std::vector Client_Hello::supported_ecc_curves() const { if(Supported_Groups* groups = m_extensions.get()) return groups->ec_groups(); return std::vector(); } std::vector Client_Hello::supported_dh_groups() const { if(Supported_Groups* groups = m_extensions.get()) return groups->dh_groups(); return std::vector(); } bool Client_Hello::prefers_compressed_ec_points() const { if(Supported_Point_Formats* ecc_formats = m_extensions.get()) { return ecc_formats->prefers_compressed(); } return false; } std::string Client_Hello::sni_hostname() const { if(Server_Name_Indicator* sni = m_extensions.get()) return sni->host_name(); return ""; } #if defined(BOTAN_HAS_SRP6) std::string Client_Hello::srp_identifier() const { if(SRP_Identifier* srp = m_extensions.get()) return srp->identifier(); return ""; } #endif bool Client_Hello::secure_renegotiation() const { return m_extensions.has(); } std::vector Client_Hello::renegotiation_info() const { if(Renegotiation_Extension* reneg = m_extensions.get()) return reneg->renegotiation_info(); return std::vector(); } std::vector Client_Hello::supported_versions() const { if(Supported_Versions* versions = m_extensions.get()) return versions->versions(); return {}; } bool Client_Hello::supports_session_ticket() const { return m_extensions.has(); } std::vector Client_Hello::session_ticket() const { if(Session_Ticket* ticket = m_extensions.get()) return ticket->contents(); return std::vector(); } bool Client_Hello::supports_alpn() const { return m_extensions.has(); } bool Client_Hello::supports_extended_master_secret() const { return m_extensions.has(); } bool Client_Hello::supports_cert_status_message() const { return m_extensions.has(); } bool Client_Hello::supports_encrypt_then_mac() const { return m_extensions.has(); } bool Client_Hello::sent_signature_algorithms() const { return m_extensions.has(); } std::vector Client_Hello::next_protocols() const { if(auto alpn = m_extensions.get()) return alpn->protocols(); return std::vector(); } std::vector Client_Hello::srtp_profiles() const { if(SRTP_Protection_Profiles* srtp = m_extensions.get()) return srtp->profiles(); return std::vector(); } } } /* * Client Key Exchange Message * (C) 2004-2010,2016 Jack Lloyd * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_CECPQ1) #endif #if defined(BOTAN_HAS_SRP6) #endif namespace Botan { namespace TLS { /* * Create a new Client Key Exchange message */ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, Handshake_State& state, const Policy& policy, Credentials_Manager& creds, const Public_Key* server_public_key, const std::string& hostname, RandomNumberGenerator& rng) { const Kex_Algo kex_algo = state.ciphersuite().kex_method(); if(kex_algo == Kex_Algo::PSK) { std::string identity_hint = ""; if(state.server_kex()) { TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); identity_hint = reader.get_string(2, 0, 65535); } const std::string psk_identity = creds.psk_identity("tls-client", hostname, identity_hint); append_tls_length_value(m_key_material, psk_identity, 2); SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity); std::vector zeros(psk.length()); append_tls_length_value(m_pre_master, zeros, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } else if(state.server_kex()) { TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); SymmetricKey psk; if(kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) { std::string identity_hint = reader.get_string(2, 0, 65535); const std::string psk_identity = creds.psk_identity("tls-client", hostname, identity_hint); append_tls_length_value(m_key_material, psk_identity, 2); psk = creds.psk("tls-client", hostname, psk_identity); } if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) { const std::vector modulus = reader.get_range(2, 1, 65535); const std::vector generator = reader.get_range(2, 1, 65535); const std::vector peer_public_value = reader.get_range(2, 1, 65535); if(reader.remaining_bytes()) throw Decoding_Error("Bad params size for DH key exchange"); const std::pair, std::vector> dh_result = state.callbacks().tls_dh_agree(modulus, generator, peer_public_value, policy, rng); if(kex_algo == Kex_Algo::DH) m_pre_master = dh_result.first; else { append_tls_length_value(m_pre_master, dh_result.first, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } append_tls_length_value(m_key_material, dh_result.second, 2); } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) { const uint8_t curve_type = reader.get_byte(); if(curve_type != 3) throw Decoding_Error("Server sent non-named ECC curve"); const Group_Params curve_id = static_cast(reader.get_uint16_t()); const std::vector peer_public_value = reader.get_range(1, 1, 255); if(policy.choose_key_exchange_group({curve_id}) != curve_id) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server sent ECC curve prohibited by policy"); } const std::string curve_name = state.callbacks().tls_decode_group_param(curve_id); if(curve_name == "") throw Decoding_Error("Server sent unknown named curve " + std::to_string(static_cast(curve_id))); const std::pair, std::vector> ecdh_result = state.callbacks().tls_ecdh_agree(curve_name, peer_public_value, policy, rng, state.server_hello()->prefers_compressed_ec_points()); if(kex_algo == Kex_Algo::ECDH) { m_pre_master = ecdh_result.first; } else { append_tls_length_value(m_pre_master, ecdh_result.first, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } append_tls_length_value(m_key_material, ecdh_result.second, 1); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == Kex_Algo::SRP_SHA) { const BigInt N = BigInt::decode(reader.get_range(2, 1, 65535)); const BigInt g = BigInt::decode(reader.get_range(2, 1, 65535)); std::vector salt = reader.get_range(1, 1, 255); const BigInt B = BigInt::decode(reader.get_range(2, 1, 65535)); const std::string srp_group = srp6_group_identifier(N, g); const std::string srp_identifier = creds.srp_identifier("tls-client", hostname); const std::string srp_password = creds.srp_password("tls-client", hostname, srp_identifier); std::pair srp_vals = srp6_client_agree(srp_identifier, srp_password, srp_group, "SHA-1", salt, B, rng); append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2); m_pre_master = srp_vals.second.bits_of(); } #endif #if defined(BOTAN_HAS_CECPQ1) else if(kex_algo == Kex_Algo::CECPQ1) { const std::vector cecpq1_offer = reader.get_range(2, 1, 65535); if(cecpq1_offer.size() != CECPQ1_OFFER_BYTES) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid CECPQ1 key size"); std::vector newhope_accept(CECPQ1_ACCEPT_BYTES); secure_vector shared_secret(CECPQ1_SHARED_KEY_BYTES); CECPQ1_accept(shared_secret.data(), newhope_accept.data(), cecpq1_offer.data(), rng); append_tls_length_value(m_key_material, newhope_accept, 2); m_pre_master = shared_secret; } #endif else { throw Internal_Error("Client_Key_Exchange: Unknown key exchange method was negotiated"); } reader.assert_done(); } else { // No server key exchange msg better mean RSA kex + RSA key in cert if(kex_algo != Kex_Algo::STATIC_RSA) throw Unexpected_Message("No server kex message, but negotiated a key exchange that required it"); if(!server_public_key) throw Internal_Error("No server public key for RSA exchange"); if(auto rsa_pub = dynamic_cast(server_public_key)) { const Protocol_Version offered_version = state.client_hello()->version(); rng.random_vec(m_pre_master, 48); m_pre_master[0] = offered_version.major_version(); m_pre_master[1] = offered_version.minor_version(); PK_Encryptor_EME encryptor(*rsa_pub, rng, "PKCS1v15"); const std::vector encrypted_key = encryptor.encrypt(m_pre_master, rng); append_tls_length_value(m_key_material, encrypted_key, 2); } else throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Expected a RSA key in server cert but got " + server_public_key->algo_name()); } state.hash().update(io.send(*this)); } /* * Read a Client Key Exchange message */ Client_Key_Exchange::Client_Key_Exchange(const std::vector& contents, const Handshake_State& state, const Private_Key* server_rsa_kex_key, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng) { const Kex_Algo kex_algo = state.ciphersuite().kex_method(); if(kex_algo == Kex_Algo::STATIC_RSA) { BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(), "RSA key exchange negotiated so server sent a certificate"); if(!server_rsa_kex_key) throw Internal_Error("Expected RSA kex but no server kex key set"); if(!dynamic_cast(server_rsa_kex_key)) throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name()); TLS_Data_Reader reader("ClientKeyExchange", contents); const std::vector encrypted_pre_master = reader.get_range(2, 0, 65535); reader.assert_done(); PK_Decryptor_EME decryptor(*server_rsa_kex_key, rng, "PKCS1v15"); const uint8_t client_major = state.client_hello()->version().major_version(); const uint8_t client_minor = state.client_hello()->version().minor_version(); /* * PK_Decryptor::decrypt_or_random will return a random value if * either the length does not match the expected value or if the * version number embedded in the PMS does not match the one sent * in the client hello. */ const size_t expected_plaintext_size = 48; const size_t expected_content_size = 2; const uint8_t expected_content_bytes[expected_content_size] = { client_major, client_minor }; const uint8_t expected_content_pos[expected_content_size] = { 0, 1 }; m_pre_master = decryptor.decrypt_or_random(encrypted_pre_master.data(), encrypted_pre_master.size(), expected_plaintext_size, rng, expected_content_bytes, expected_content_pos, expected_content_size); } else { TLS_Data_Reader reader("ClientKeyExchange", contents); SymmetricKey psk; if(key_exchange_is_psk(kex_algo)) { const std::string psk_identity = reader.get_string(2, 0, 65535); psk = creds.psk("tls-server", state.client_hello()->sni_hostname(), psk_identity); if(psk.length() == 0) { if(policy.hide_unknown_users()) psk = SymmetricKey(rng, 16); else throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, "No PSK for identifier " + psk_identity); } } if(kex_algo == Kex_Algo::PSK) { std::vector zeros(psk.length()); append_tls_length_value(m_pre_master, zeros, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == Kex_Algo::SRP_SHA) { SRP6_Server_Session& srp = state.server_kex()->server_srp_params(); m_pre_master = srp.step2(BigInt::decode(reader.get_range(2, 0, 65535))).bits_of(); } #endif #if defined(BOTAN_HAS_CECPQ1) else if(kex_algo == Kex_Algo::CECPQ1) { const CECPQ1_key& cecpq1_offer = state.server_kex()->cecpq1_key(); const std::vector cecpq1_accept = reader.get_range(2, 0, 65535); if(cecpq1_accept.size() != CECPQ1_ACCEPT_BYTES) throw Decoding_Error("Invalid size for CECPQ1 accept message"); m_pre_master.resize(CECPQ1_SHARED_KEY_BYTES); CECPQ1_finish(m_pre_master.data(), cecpq1_offer, cecpq1_accept.data()); } #endif else if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) { const Private_Key& private_key = state.server_kex()->server_kex_key(); const PK_Key_Agreement_Key* ka_key = dynamic_cast(&private_key); if(!ka_key) throw Internal_Error("Expected key agreement key type but got " + private_key.algo_name()); std::vector client_pubkey; if(ka_key->algo_name() == "DH") { client_pubkey = reader.get_range(2, 0, 65535); } else { client_pubkey = reader.get_range(1, 1, 255); } try { PK_Key_Agreement ka(*ka_key, rng, "Raw"); secure_vector shared_secret = ka.derive_key(0, client_pubkey).bits_of(); if(ka_key->algo_name() == "DH") shared_secret = CT::strip_leading_zeros(shared_secret); if(kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) { append_tls_length_value(m_pre_master, shared_secret, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } else m_pre_master = shared_secret; } catch(Invalid_Argument& e) { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, e.what()); } catch(std::exception&) { /* * Something failed in the DH/ECDH computation. To avoid possible * attacks which are based on triggering and detecting some edge * failure condition, randomize the pre-master output and carry on, * allowing the protocol to fail later in the finished checks. */ rng.random_vec(m_pre_master, ka_key->public_value().size()); } reader.assert_done(); } else throw Internal_Error("Client_Key_Exchange: Unknown key exchange negotiated"); } } } } /* * Finished Message * (C) 2004-2006,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { namespace { /* * Compute the verify_data */ std::vector finished_compute_verify(const Handshake_State& state, Connection_Side side) { const uint8_t TLS_CLIENT_LABEL[] = { 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64 }; const uint8_t TLS_SERVER_LABEL[] = { 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64 }; std::unique_ptr prf(state.protocol_specific_prf()); std::vector input; std::vector label; if(side == CLIENT) label += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL)); else label += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL)); input += state.hash().final(state.version(), state.ciphersuite().prf_algo()); return unlock(prf->derive_key(12, state.session_keys().master_secret(), input, label)); } } /* * Create a new Finished message */ Finished::Finished(Handshake_IO& io, Handshake_State& state, Connection_Side side) : m_verification_data(finished_compute_verify( state, side )) { state.hash().update(io.send(*this)); } /* * Serialize a Finished message */ std::vector Finished::serialize() const { return m_verification_data; } /* * Deserialize a Finished message */ Finished::Finished(const std::vector& buf) : m_verification_data(buf) {} /* * Verify a Finished message */ bool Finished::verify(const Handshake_State& state, Connection_Side side) const { std::vector computed_verify = finished_compute_verify(state, side); #if defined(BOTAN_UNSAFE_FUZZER_MODE) return true; #else return (m_verification_data.size() == computed_verify.size()) && constant_time_compare(m_verification_data.data(), computed_verify.data(), computed_verify.size()); #endif } } } /* * DTLS Hello Verify Request * (C) 2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { Hello_Verify_Request::Hello_Verify_Request(const std::vector& buf) { if(buf.size() < 3) throw Decoding_Error("Hello verify request too small"); Protocol_Version version(buf[0], buf[1]); if(version != Protocol_Version::DTLS_V10 && version != Protocol_Version::DTLS_V12) { throw Decoding_Error("Unknown version from server in hello verify request"); } if(static_cast(buf[2]) + 3 != buf.size()) throw Decoding_Error("Bad length in hello verify request"); m_cookie.assign(buf.begin() + 3, buf.end()); } Hello_Verify_Request::Hello_Verify_Request(const std::vector& client_hello_bits, const std::string& client_identity, const SymmetricKey& secret_key) { std::unique_ptr hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); hmac->set_key(secret_key); hmac->update_be(static_cast(client_hello_bits.size())); hmac->update(client_hello_bits); hmac->update_be(static_cast(client_identity.size())); hmac->update(client_identity); m_cookie.resize(hmac->output_length()); hmac->final(m_cookie.data()); } std::vector Hello_Verify_Request::serialize() const { /* DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of the version of TLS that is expected to be negotiated (RFC 6347, section 4.2.1) */ Protocol_Version format_version(Protocol_Version::DTLS_V10); std::vector bits; bits.push_back(format_version.major_version()); bits.push_back(format_version.minor_version()); bits.push_back(static_cast(m_cookie.size())); bits += m_cookie; return bits; } } } /* * TLS Server Hello and Server Hello Done * (C) 2004-2011,2015,2016,2019 Jack Lloyd * 2016 Matthias Gierlings * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { namespace { const uint64_t DOWNGRADE_TLS11 = 0x444F574E47524400; //const uint64_t DOWNGRADE_TLS12 = 0x444F574E47524401; std::vector make_server_hello_random(RandomNumberGenerator& rng, Protocol_Version offered_version, const Policy& policy) { auto random = make_hello_random(rng, policy); if((offered_version == Protocol_Version::TLS_V10 || offered_version == Protocol_Version::TLS_V11) && policy.allow_tls12()) { store_be(DOWNGRADE_TLS11, &random[24]); } if(offered_version == Protocol_Version::DTLS_V10 && policy.allow_dtls12()) { store_be(DOWNGRADE_TLS11, &random[24]); } return random; } } // New session case Server_Hello::Server_Hello(Handshake_IO& io, Handshake_Hash& hash, const Policy& policy, Callbacks& cb, RandomNumberGenerator& rng, const std::vector& reneg_info, const Client_Hello& client_hello, const Server_Hello::Settings& server_settings, const std::string next_protocol) : m_version(server_settings.protocol_version()), m_session_id(server_settings.session_id()), m_random(make_server_hello_random(rng, m_version, policy)), m_ciphersuite(server_settings.ciphersuite()), m_comp_method(0) { if(client_hello.supports_extended_master_secret()) m_extensions.add(new Extended_Master_Secret); // Sending the extension back does not commit us to sending a stapled response if(client_hello.supports_cert_status_message() && policy.support_cert_status_message()) m_extensions.add(new Certificate_Status_Request); Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); if(c.cbc_ciphersuite() && client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) { m_extensions.add(new Encrypt_then_MAC); } if(c.ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } if(client_hello.secure_renegotiation()) m_extensions.add(new Renegotiation_Extension(reneg_info)); if(client_hello.supports_session_ticket() && server_settings.offer_session_ticket()) m_extensions.add(new Session_Ticket()); if(!next_protocol.empty() && client_hello.supports_alpn()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocol)); if(m_version.is_datagram_protocol()) { const std::vector server_srtp = policy.srtp_profiles(); const std::vector client_srtp = client_hello.srtp_profiles(); if(!server_srtp.empty() && !client_srtp.empty()) { uint16_t shared = 0; // always using server preferences for now for(auto s_srtp : server_srtp) for(auto c_srtp : client_srtp) { if(shared == 0 && s_srtp == c_srtp) shared = s_srtp; } if(shared) m_extensions.add(new SRTP_Protection_Profiles(shared)); } } cb.tls_modify_extensions(m_extensions, SERVER); hash.update(io.send(*this)); } // Resuming Server_Hello::Server_Hello(Handshake_IO& io, Handshake_Hash& hash, const Policy& policy, Callbacks& cb, RandomNumberGenerator& rng, const std::vector& reneg_info, const Client_Hello& client_hello, Session& resumed_session, bool offer_session_ticket, const std::string& next_protocol) : m_version(resumed_session.version()), m_session_id(client_hello.session_id()), m_random(make_hello_random(rng, policy)), m_ciphersuite(resumed_session.ciphersuite_code()), m_comp_method(0) { if(client_hello.supports_extended_master_secret()) m_extensions.add(new Extended_Master_Secret); if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) { Ciphersuite c = resumed_session.ciphersuite(); if(c.cbc_ciphersuite()) m_extensions.add(new Encrypt_then_MAC); } if(resumed_session.ciphersuite().ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } if(client_hello.secure_renegotiation()) m_extensions.add(new Renegotiation_Extension(reneg_info)); if(client_hello.supports_session_ticket() && offer_session_ticket) m_extensions.add(new Session_Ticket()); if(!next_protocol.empty() && client_hello.supports_alpn()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocol)); cb.tls_modify_extensions(m_extensions, SERVER); hash.update(io.send(*this)); } /* * Deserialize a Server Hello message */ Server_Hello::Server_Hello(const std::vector& buf) { if(buf.size() < 38) throw Decoding_Error("Server_Hello: Packet corrupted"); TLS_Data_Reader reader("ServerHello", buf); const uint8_t major_version = reader.get_byte(); const uint8_t minor_version = reader.get_byte(); m_version = Protocol_Version(major_version, minor_version); m_random = reader.get_fixed(32); m_session_id = reader.get_range(1, 0, 32); m_ciphersuite = reader.get_uint16_t(); m_comp_method = reader.get_byte(); m_extensions.deserialize(reader, Connection_Side::SERVER); } /* * Serialize a Server Hello message */ std::vector Server_Hello::serialize() const { std::vector buf; buf.push_back(m_version.major_version()); buf.push_back(m_version.minor_version()); buf += m_random; append_tls_length_value(buf, m_session_id, 1); buf.push_back(get_byte(0, m_ciphersuite)); buf.push_back(get_byte(1, m_ciphersuite)); buf.push_back(m_comp_method); buf += m_extensions.serialize(Connection_Side::SERVER); return buf; } bool Server_Hello::random_signals_downgrade() const { const uint64_t last8 = load_be(m_random.data(), 3); return (last8 == DOWNGRADE_TLS11); } /* * Create a new Server Hello Done message */ Server_Hello_Done::Server_Hello_Done(Handshake_IO& io, Handshake_Hash& hash) { hash.update(io.send(*this)); } /* * Deserialize a Server Hello Done message */ Server_Hello_Done::Server_Hello_Done(const std::vector& buf) { if(buf.size()) throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); } /* * Serialize a Server Hello Done message */ std::vector Server_Hello_Done::serialize() const { return std::vector(); } } } /* * Server Key Exchange Message * (C) 2004-2010,2012,2015,2016 Jack Lloyd * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_CURVE_25519) #endif #if defined(BOTAN_HAS_CECPQ1) #endif #if defined(BOTAN_HAS_SRP6) #endif namespace Botan { namespace TLS { /** * Create a new Server Key Exchange message */ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, Handshake_State& state, const Policy& policy, Credentials_Manager& creds, RandomNumberGenerator& rng, const Private_Key* signing_key) { const std::string hostname = state.client_hello()->sni_hostname(); const Kex_Algo kex_algo = state.ciphersuite().kex_method(); if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) { std::string identity_hint = creds.psk_identity_hint("tls-server", hostname); append_tls_length_value(m_params, identity_hint, 2); } if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) { const std::vector dh_groups = state.client_hello()->supported_dh_groups(); Group_Params shared_group = Group_Params::NONE; /* If the client does not send any DH groups in the supported groups extension, but does offer DH ciphersuites, we select a group arbitrarily */ if(dh_groups.empty()) { shared_group = policy.default_dh_group(); } else { shared_group = policy.choose_key_exchange_group(dh_groups); } if(shared_group == Group_Params::NONE) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Could not agree on a DH group with the client"); BOTAN_ASSERT(group_param_is_dh(shared_group), "DH groups for the DH ciphersuites god"); const std::string group_name = state.callbacks().tls_decode_group_param(shared_group); std::unique_ptr dh(new DH_PrivateKey(rng, DL_Group(group_name))); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); append_tls_length_value(m_params, dh->public_value(), 2); m_kex_key.reset(dh.release()); } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) { const std::vector ec_groups = state.client_hello()->supported_ecc_curves(); if(ec_groups.empty()) throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); Group_Params shared_group = policy.choose_key_exchange_group(ec_groups); if(shared_group == Group_Params::NONE) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "No shared ECC group with client"); std::vector ecdh_public_val; if(shared_group == Group_Params::X25519) { #if defined(BOTAN_HAS_CURVE_25519) std::unique_ptr x25519(new Curve25519_PrivateKey(rng)); ecdh_public_val = x25519->public_value(); m_kex_key.reset(x25519.release()); #else throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); #endif } else { Group_Params curve = policy.choose_key_exchange_group(ec_groups); const std::string curve_name = state.callbacks().tls_decode_group_param(curve); EC_Group ec_group(curve_name); std::unique_ptr ecdh(new ECDH_PrivateKey(rng, ec_group)); // follow client's preference for point compression ecdh_public_val = ecdh->public_value( state.client_hello()->prefers_compressed_ec_points() ? PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED); m_kex_key.reset(ecdh.release()); } const uint16_t named_curve_id = static_cast(shared_group); m_params.push_back(3); // named curve m_params.push_back(get_byte(0, named_curve_id)); m_params.push_back(get_byte(1, named_curve_id)); append_tls_length_value(m_params, ecdh_public_val, 1); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == Kex_Algo::SRP_SHA) { const std::string srp_identifier = state.client_hello()->srp_identifier(); std::string group_id; BigInt v; std::vector salt; const bool found = creds.srp_verifier("tls-server", hostname, srp_identifier, group_id, v, salt, policy.hide_unknown_users()); if(!found) throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, "Unknown SRP user " + srp_identifier); m_srp_params.reset(new SRP6_Server_Session); BigInt B = m_srp_params->step1(v, group_id, "SHA-1", rng); DL_Group group(group_id); append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2); append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2); append_tls_length_value(m_params, salt, 1); append_tls_length_value(m_params, BigInt::encode(B), 2); } #endif #if defined(BOTAN_HAS_CECPQ1) else if(kex_algo == Kex_Algo::CECPQ1) { std::vector cecpq1_offer(CECPQ1_OFFER_BYTES); m_cecpq1_key.reset(new CECPQ1_key); CECPQ1_offer(cecpq1_offer.data(), m_cecpq1_key.get(), rng); append_tls_length_value(m_params, cecpq1_offer, 2); } #endif else if(kex_algo != Kex_Algo::PSK) { throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo)); } if(state.ciphersuite().signature_used()) { BOTAN_ASSERT(signing_key, "Signing key was set"); std::pair format = state.choose_sig_format(*signing_key, m_scheme, false, policy); std::vector buf = state.client_hello()->random(); buf += state.server_hello()->random(); buf += params(); m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf); } state.hash().update(io.send(*this)); } /** * Deserialize a Server Key Exchange message */ Server_Key_Exchange::Server_Key_Exchange(const std::vector& buf, const Kex_Algo kex_algo, const Auth_Method auth_method, Protocol_Version version) { TLS_Data_Reader reader("ServerKeyExchange", buf); /* * Here we are deserializing enough to find out what offset the * signature is at. All processing is done when the Client Key Exchange * is prepared. */ if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) { reader.get_string(2, 0, 65535); // identity hint } if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) { // 3 bigints, DH p, g, Y for(size_t i = 0; i != 3; ++i) { reader.get_range(2, 1, 65535); } } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) { reader.get_byte(); // curve type reader.get_uint16_t(); // curve id reader.get_range(1, 1, 255); // public key } else if(kex_algo == Kex_Algo::SRP_SHA) { // 2 bigints (N,g) then salt, then server B reader.get_range(2, 1, 65535); reader.get_range(2, 1, 65535); reader.get_range(1, 1, 255); reader.get_range(2, 1, 65535); } else if(kex_algo == Kex_Algo::CECPQ1) { // u16 blob reader.get_range(2, 1, 65535); } else if(kex_algo != Kex_Algo::PSK) throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_method_to_string(kex_algo)); m_params.assign(buf.data(), buf.data() + reader.read_so_far()); if(auth_method != Auth_Method::ANONYMOUS && auth_method != Auth_Method::IMPLICIT) { if(version.supports_negotiable_signature_algorithms()) { m_scheme = static_cast(reader.get_uint16_t()); } m_signature = reader.get_range(2, 0, 65535); } reader.assert_done(); } /** * Serialize a Server Key Exchange message */ std::vector Server_Key_Exchange::serialize() const { std::vector buf = params(); if(m_signature.size()) { if(m_scheme != Signature_Scheme::NONE) { const uint16_t scheme_code = static_cast(m_scheme); buf.push_back(get_byte(0, scheme_code)); buf.push_back(get_byte(1, scheme_code)); } append_tls_length_value(buf, m_signature, 2); } return buf; } /** * Verify a Server Key Exchange message */ bool Server_Key_Exchange::verify(const Public_Key& server_key, const Handshake_State& state, const Policy& policy) const { policy.check_peer_key_acceptable(server_key); std::pair format = state.parse_sig_format(server_key, m_scheme, false, policy); std::vector buf = state.client_hello()->random(); buf += state.server_hello()->random(); buf += params(); const bool signature_valid = state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature); #if defined(BOTAN_UNSAFE_FUZZER_MODE) BOTAN_UNUSED(signature_valid); return true; #else return signature_valid; #endif } const Private_Key& Server_Key_Exchange::server_kex_key() const { BOTAN_ASSERT_NONNULL(m_kex_key); return *m_kex_key; } } } /* * Session Tickets * (C) 2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, Handshake_Hash& hash, const std::vector& ticket, uint32_t lifetime) : m_ticket_lifetime_hint(lifetime), m_ticket(ticket) { hash.update(io.send(*this)); } New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, Handshake_Hash& hash) { hash.update(io.send(*this)); } New_Session_Ticket::New_Session_Ticket(const std::vector& buf) { if(buf.size() < 6) throw Decoding_Error("Session ticket message too short to be valid"); TLS_Data_Reader reader("SessionTicket", buf); m_ticket_lifetime_hint = reader.get_uint32_t(); m_ticket = reader.get_range(2, 0, 65535); reader.assert_done(); } std::vector New_Session_Ticket::serialize() const { std::vector buf(4); store_be(m_ticket_lifetime_hint, buf.data()); append_tls_length_value(buf, m_ticket, 2); return buf; } } } /* * Alert Message * (C) 2004-2006,2011 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { Alert::Alert(const secure_vector& buf) { if(buf.size() != 2) throw Decoding_Error("Bad size (" + std::to_string(buf.size()) + ") for TLS alert message"); if(buf[0] == 1) m_fatal = false; else if(buf[0] == 2) m_fatal = true; else throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Bad code for TLS alert level"); const uint8_t dc = buf[1]; m_type_code = static_cast(dc); } std::vector Alert::serialize() const { return std::vector({ static_cast(is_fatal() ? 2 : 1), static_cast(type()) }); } std::string Alert::type_string() const { switch(type()) { case CLOSE_NOTIFY: return "close_notify"; case UNEXPECTED_MESSAGE: return "unexpected_message"; case BAD_RECORD_MAC: return "bad_record_mac"; case DECRYPTION_FAILED: return "decryption_failed"; case RECORD_OVERFLOW: return "record_overflow"; case DECOMPRESSION_FAILURE: return "decompression_failure"; case HANDSHAKE_FAILURE: return "handshake_failure"; case NO_CERTIFICATE: return "no_certificate"; case BAD_CERTIFICATE: return "bad_certificate"; case UNSUPPORTED_CERTIFICATE: return "unsupported_certificate"; case CERTIFICATE_REVOKED: return "certificate_revoked"; case CERTIFICATE_EXPIRED: return "certificate_expired"; case CERTIFICATE_UNKNOWN: return "certificate_unknown"; case ILLEGAL_PARAMETER: return "illegal_parameter"; case UNKNOWN_CA: return "unknown_ca"; case ACCESS_DENIED: return "access_denied"; case DECODE_ERROR: return "decode_error"; case DECRYPT_ERROR: return "decrypt_error"; case EXPORT_RESTRICTION: return "export_restriction"; case PROTOCOL_VERSION: return "protocol_version"; case INSUFFICIENT_SECURITY: return "insufficient_security"; case INTERNAL_ERROR: return "internal_error"; case INAPPROPRIATE_FALLBACK: return "inappropriate_fallback"; case USER_CANCELED: return "user_canceled"; case NO_RENEGOTIATION: return "no_renegotiation"; case UNSUPPORTED_EXTENSION: return "unsupported_extension"; case CERTIFICATE_UNOBTAINABLE: return "certificate_unobtainable"; case UNRECOGNIZED_NAME: return "unrecognized_name"; case BAD_CERTIFICATE_STATUS_RESPONSE: return "bad_certificate_status_response"; case BAD_CERTIFICATE_HASH_VALUE: return "bad_certificate_hash_value"; case UNKNOWN_PSK_IDENTITY: return "unknown_psk_identity"; case CERTIFICATE_REQUIRED: return "certificate_required"; case NO_APPLICATION_PROTOCOL: return "no_application_protocol"; case NULL_ALERT: return "none"; } /* * This is effectively the default case for the switch above, but we * leave it out so that when an alert type is added to the enum the * compiler can warn us that it is not included in the switch * statement. */ return "unrecognized_alert_" + std::to_string(type()); } } } /* * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { std::string kdf_algo_to_string(KDF_Algo algo) { switch(algo) { case KDF_Algo::SHA_1: return "SHA-1"; case KDF_Algo::SHA_256: return "SHA-256"; case KDF_Algo::SHA_384: return "SHA-384"; } throw Invalid_State("kdf_algo_to_string unknown enum value"); } std::string kex_method_to_string(Kex_Algo method) { switch(method) { case Kex_Algo::STATIC_RSA: return "RSA"; case Kex_Algo::DH: return "DH"; case Kex_Algo::ECDH: return "ECDH"; case Kex_Algo::CECPQ1: return "CECPQ1"; case Kex_Algo::SRP_SHA: return "SRP_SHA"; case Kex_Algo::PSK: return "PSK"; case Kex_Algo::DHE_PSK: return "DHE_PSK"; case Kex_Algo::ECDHE_PSK: return "ECDHE_PSK"; } throw Invalid_State("kex_method_to_string unknown enum value"); } Kex_Algo kex_method_from_string(const std::string& str) { if(str == "RSA") return Kex_Algo::STATIC_RSA; if(str == "DH") return Kex_Algo::DH; if(str == "ECDH") return Kex_Algo::ECDH; if(str == "CECPQ1") return Kex_Algo::CECPQ1; if(str == "SRP_SHA") return Kex_Algo::SRP_SHA; if(str == "PSK") return Kex_Algo::PSK; if(str == "DHE_PSK") return Kex_Algo::DHE_PSK; if(str == "ECDHE_PSK") return Kex_Algo::ECDHE_PSK; throw Invalid_Argument("Unknown kex method " + str); } std::string auth_method_to_string(Auth_Method method) { switch(method) { case Auth_Method::RSA: return "RSA"; case Auth_Method::DSA: return "DSA"; case Auth_Method::ECDSA: return "ECDSA"; case Auth_Method::IMPLICIT: return "IMPLICIT"; case Auth_Method::ANONYMOUS: return "ANONYMOUS"; } throw Invalid_State("auth_method_to_string unknown enum value"); } Auth_Method auth_method_from_string(const std::string& str) { if(str == "RSA") return Auth_Method::RSA; if(str == "DSA") return Auth_Method::DSA; if(str == "ECDSA") return Auth_Method::ECDSA; if(str == "IMPLICIT") return Auth_Method::IMPLICIT; if(str == "ANONYMOUS" || str == "") return Auth_Method::ANONYMOUS; throw Invalid_Argument("Bad signature method " + str); } bool group_param_is_dh(Group_Params group) { uint16_t group_id = static_cast(group); return (group_id >= 256 && group_id < 512); } Group_Params group_param_from_string(const std::string& group_name) { if(group_name == "secp256r1") return Group_Params::SECP256R1; if(group_name == "secp384r1") return Group_Params::SECP384R1; if(group_name == "secp521r1") return Group_Params::SECP521R1; if(group_name == "brainpool256r1") return Group_Params::BRAINPOOL256R1; if(group_name == "brainpool384r1") return Group_Params::BRAINPOOL384R1; if(group_name == "brainpool512r1") return Group_Params::BRAINPOOL512R1; if(group_name == "x25519") return Group_Params::X25519; if(group_name == "ffdhe/ietf/2048") return Group_Params::FFDHE_2048; if(group_name == "ffdhe/ietf/3072") return Group_Params::FFDHE_3072; if(group_name == "ffdhe/ietf/4096") return Group_Params::FFDHE_4096; if(group_name == "ffdhe/ietf/6144") return Group_Params::FFDHE_6144; if(group_name == "ffdhe/ietf/8192") return Group_Params::FFDHE_8192; return Group_Params::NONE; // unknown } std::string group_param_to_string(Group_Params group) { switch(group) { case Group_Params::SECP256R1: return "secp256r1"; case Group_Params::SECP384R1: return "secp384r1"; case Group_Params::SECP521R1: return "secp521r1"; case Group_Params::BRAINPOOL256R1: return "brainpool256r1"; case Group_Params::BRAINPOOL384R1: return "brainpool384r1"; case Group_Params::BRAINPOOL512R1: return "brainpool512r1"; case Group_Params::X25519: return "x25519"; case Group_Params::FFDHE_2048: return "ffdhe/ietf/2048"; case Group_Params::FFDHE_3072: return "ffdhe/ietf/3072"; case Group_Params::FFDHE_4096: return "ffdhe/ietf/4096"; case Group_Params::FFDHE_6144: return "ffdhe/ietf/6144"; case Group_Params::FFDHE_8192: return "ffdhe/ietf/8192"; default: return ""; } } std::string hash_function_of_scheme(Signature_Scheme scheme) { switch(scheme) { case Signature_Scheme::DSA_SHA1: case Signature_Scheme::ECDSA_SHA1: case Signature_Scheme::RSA_PKCS1_SHA1: return "SHA-1"; case Signature_Scheme::DSA_SHA256: case Signature_Scheme::ECDSA_SHA256: case Signature_Scheme::RSA_PKCS1_SHA256: case Signature_Scheme::RSA_PSS_SHA256: return "SHA-256"; case Signature_Scheme::DSA_SHA384: case Signature_Scheme::ECDSA_SHA384: case Signature_Scheme::RSA_PKCS1_SHA384: case Signature_Scheme::RSA_PSS_SHA384: return "SHA-384"; case Signature_Scheme::DSA_SHA512: case Signature_Scheme::ECDSA_SHA512: case Signature_Scheme::RSA_PKCS1_SHA512: case Signature_Scheme::RSA_PSS_SHA512: return "SHA-512"; case Signature_Scheme::EDDSA_25519: case Signature_Scheme::EDDSA_448: return "Pure"; case Signature_Scheme::NONE: return ""; } throw Invalid_State("hash_function_of_scheme: Unknown signature algorithm enum"); } const std::vector& all_signature_schemes() { /* * This is ordered in some approximate order of preference */ static const std::vector all_schemes = { //Signature_Scheme::EDDSA_448, //Signature_Scheme::EDDSA_25519, Signature_Scheme::RSA_PSS_SHA384, Signature_Scheme::RSA_PSS_SHA256, Signature_Scheme::RSA_PSS_SHA512, Signature_Scheme::RSA_PKCS1_SHA384, Signature_Scheme::RSA_PKCS1_SHA512, Signature_Scheme::RSA_PKCS1_SHA256, Signature_Scheme::ECDSA_SHA384, Signature_Scheme::ECDSA_SHA512, Signature_Scheme::ECDSA_SHA256, Signature_Scheme::DSA_SHA384, Signature_Scheme::DSA_SHA512, Signature_Scheme::DSA_SHA256, Signature_Scheme::RSA_PKCS1_SHA1, Signature_Scheme::ECDSA_SHA1, Signature_Scheme::DSA_SHA1, }; return all_schemes; } bool signature_scheme_is_known(Signature_Scheme scheme) { switch(scheme) { case Signature_Scheme::RSA_PKCS1_SHA1: case Signature_Scheme::RSA_PKCS1_SHA256: case Signature_Scheme::RSA_PKCS1_SHA384: case Signature_Scheme::RSA_PKCS1_SHA512: case Signature_Scheme::RSA_PSS_SHA256: case Signature_Scheme::RSA_PSS_SHA384: case Signature_Scheme::RSA_PSS_SHA512: case Signature_Scheme::DSA_SHA1: case Signature_Scheme::DSA_SHA256: case Signature_Scheme::DSA_SHA384: case Signature_Scheme::DSA_SHA512: case Signature_Scheme::ECDSA_SHA1: case Signature_Scheme::ECDSA_SHA256: case Signature_Scheme::ECDSA_SHA384: case Signature_Scheme::ECDSA_SHA512: return true; default: return false; } } std::string signature_algorithm_of_scheme(Signature_Scheme scheme) { switch(scheme) { case Signature_Scheme::RSA_PKCS1_SHA1: case Signature_Scheme::RSA_PKCS1_SHA256: case Signature_Scheme::RSA_PKCS1_SHA384: case Signature_Scheme::RSA_PKCS1_SHA512: case Signature_Scheme::RSA_PSS_SHA256: case Signature_Scheme::RSA_PSS_SHA384: case Signature_Scheme::RSA_PSS_SHA512: return "RSA"; case Signature_Scheme::DSA_SHA1: case Signature_Scheme::DSA_SHA256: case Signature_Scheme::DSA_SHA384: case Signature_Scheme::DSA_SHA512: return "DSA"; case Signature_Scheme::ECDSA_SHA1: case Signature_Scheme::ECDSA_SHA256: case Signature_Scheme::ECDSA_SHA384: case Signature_Scheme::ECDSA_SHA512: return "ECDSA"; case Signature_Scheme::EDDSA_25519: return "Ed25519"; case Signature_Scheme::EDDSA_448: return "Ed448"; case Signature_Scheme::NONE: return ""; } throw Invalid_State("signature_algorithm_of_scheme: Unknown signature algorithm enum"); } std::string sig_scheme_to_string(Signature_Scheme scheme) { switch(scheme) { case Signature_Scheme::RSA_PKCS1_SHA1: return "RSA_PKCS1_SHA1"; case Signature_Scheme::RSA_PKCS1_SHA256: return "RSA_PKCS1_SHA256"; case Signature_Scheme::RSA_PKCS1_SHA384: return "RSA_PKCS1_SHA384"; case Signature_Scheme::RSA_PKCS1_SHA512: return "RSA_PKCS1_SHA512"; case Signature_Scheme::DSA_SHA1: return "DSA_SHA1"; case Signature_Scheme::DSA_SHA256: return "DSA_SHA256"; case Signature_Scheme::DSA_SHA384: return "DSA_SHA384"; case Signature_Scheme::DSA_SHA512: return "DSA_SHA512"; case Signature_Scheme::ECDSA_SHA1: return "ECDSA_SHA1"; case Signature_Scheme::ECDSA_SHA256: return "ECDSA_SHA256"; case Signature_Scheme::ECDSA_SHA384: return "ECDSA_SHA384"; case Signature_Scheme::ECDSA_SHA512: return "ECDSA_SHA512"; case Signature_Scheme::RSA_PSS_SHA256: return "RSA_PSS_SHA256"; case Signature_Scheme::RSA_PSS_SHA384: return "RSA_PSS_SHA384"; case Signature_Scheme::RSA_PSS_SHA512: return "RSA_PSS_SHA512"; case Signature_Scheme::EDDSA_25519: return "EDDSA_25519"; case Signature_Scheme::EDDSA_448: return "EDDSA_448"; case Signature_Scheme::NONE: return ""; } throw Invalid_State("sig_scheme_to_string: Unknown signature algorithm enum"); } std::string padding_string_for_scheme(Signature_Scheme scheme) { switch(scheme) { case Signature_Scheme::RSA_PKCS1_SHA1: return "EMSA_PKCS1(SHA-1)"; case Signature_Scheme::RSA_PKCS1_SHA256: return "EMSA_PKCS1(SHA-256)"; case Signature_Scheme::RSA_PKCS1_SHA384: return "EMSA_PKCS1(SHA-384)"; case Signature_Scheme::RSA_PKCS1_SHA512: return "EMSA_PKCS1(SHA-512)"; case Signature_Scheme::DSA_SHA1: case Signature_Scheme::ECDSA_SHA1: return "EMSA1(SHA-1)"; case Signature_Scheme::DSA_SHA256: case Signature_Scheme::ECDSA_SHA256: return "EMSA1(SHA-256)"; case Signature_Scheme::DSA_SHA384: case Signature_Scheme::ECDSA_SHA384: return "EMSA1(SHA-384)"; case Signature_Scheme::DSA_SHA512: case Signature_Scheme::ECDSA_SHA512: return "EMSA1(SHA-512)"; case Signature_Scheme::RSA_PSS_SHA256: return "PSSR(SHA-256,MGF1,32)"; case Signature_Scheme::RSA_PSS_SHA384: return "PSSR(SHA-384,MGF1,48)"; case Signature_Scheme::RSA_PSS_SHA512: return "PSSR(SHA-512,MGF1,64)"; case Signature_Scheme::EDDSA_25519: return "Pure"; case Signature_Scheme::EDDSA_448: return "Pure"; case Signature_Scheme::NONE: return ""; } throw Invalid_State("padding_string_for_scheme: Unknown signature algorithm enum"); } } } /* * TLS Blocking API * (C) 2013 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { Blocking_Client::Blocking_Client(read_fn reader, write_fn writer, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, const Server_Information& server_info, const Protocol_Version& offer_version, const std::vector& next) : m_read(reader), m_callbacks(new TLS::Compat_Callbacks( /* we are ok using deprecated features here because the whole Blocking_Client class is also deprecated, so just silence the warning. */ TLS::Compat_Callbacks::SILENCE_DEPRECATION_WARNING::PLEASE, writer, std::bind(&Blocking_Client::data_cb, this, std::placeholders::_1, std::placeholders::_2), std::function(std::bind(&Blocking_Client::alert_cb, this, std::placeholders::_1)), std::bind(&Blocking_Client::handshake_cb, this, std::placeholders::_1) )), m_channel(*m_callbacks.get(), session_manager, creds, policy, rng, server_info, offer_version, next) { } bool Blocking_Client::handshake_cb(const Session& session) { return this->handshake_complete(session); } void Blocking_Client::alert_cb(const Alert& alert) { this->alert_notification(alert); } void Blocking_Client::data_cb(const uint8_t data[], size_t data_len) { m_plaintext.insert(m_plaintext.end(), data, data + data_len); } void Blocking_Client::do_handshake() { std::vector readbuf(4096); while(!m_channel.is_closed() && !m_channel.is_active()) { const size_t from_socket = m_read(readbuf.data(), readbuf.size()); m_channel.received_data(readbuf.data(), from_socket); } } size_t Blocking_Client::read(uint8_t buf[], size_t buf_len) { std::vector readbuf(4096); while(m_plaintext.empty() && !m_channel.is_closed()) { const size_t from_socket = m_read(readbuf.data(), readbuf.size()); m_channel.received_data(readbuf.data(), from_socket); } const size_t returned = std::min(buf_len, m_plaintext.size()); for(size_t i = 0; i != returned; ++i) buf[i] = m_plaintext[i]; m_plaintext.erase(m_plaintext.begin(), m_plaintext.begin() + returned); BOTAN_ASSERT_IMPLICATION(returned == 0, m_channel.is_closed(), "Only return zero if channel is closed"); return returned; } } } /* * TLS Callbacks * (C) 2016 Jack Lloyd * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_CURVE_25519) #endif namespace Botan { void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message&) { // default is no op } std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector&) { return ""; } std::string TLS::Callbacks::tls_peer_network_identity() { return ""; } void TLS::Callbacks::tls_modify_extensions(Extensions&, Connection_Side) { } void TLS::Callbacks::tls_examine_extensions(const Extensions&, Connection_Side) { } std::string TLS::Callbacks::tls_decode_group_param(Group_Params group_param) { return group_param_to_string(group_param); } void TLS::Callbacks::tls_verify_cert_chain( const std::vector& cert_chain, const std::vector>& ocsp_responses, const std::vector& trusted_roots, Usage_Type usage, const std::string& hostname, const TLS::Policy& policy) { if(cert_chain.empty()) throw Invalid_Argument("Certificate chain was empty"); Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(), policy.minimum_signature_strength()); Path_Validation_Result result = x509_path_validate(cert_chain, restrictions, trusted_roots, (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""), usage, std::chrono::system_clock::now(), tls_verify_cert_chain_ocsp_timeout(), ocsp_responses); if(!result.successful_validation()) { throw TLS_Exception(Alert::BAD_CERTIFICATE, "Certificate validation failure: " + result.result_string()); } } std::vector TLS::Callbacks::tls_sign_message( const Private_Key& key, RandomNumberGenerator& rng, const std::string& emsa, Signature_Format format, const std::vector& msg) { PK_Signer signer(key, rng, emsa, format); return signer.sign_message(msg, rng); } bool TLS::Callbacks::tls_verify_message( const Public_Key& key, const std::string& emsa, Signature_Format format, const std::vector& msg, const std::vector& sig) { PK_Verifier verifier(key, emsa, format); return verifier.verify_message(msg, sig); } std::pair, std::vector> TLS::Callbacks::tls_dh_agree( const std::vector& modulus, const std::vector& generator, const std::vector& peer_public_value, const Policy& policy, RandomNumberGenerator& rng) { BigInt p = BigInt::decode(modulus); BigInt g = BigInt::decode(generator); BigInt Y = BigInt::decode(peer_public_value); /* * A basic check for key validity. As we do not know q here we * cannot check that Y is in the right subgroup. However since * our key is ephemeral there does not seem to be any * advantage to bogus keys anyway. */ if(Y <= 1 || Y >= p - 1) throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Server sent bad DH key for DHE exchange"); DL_Group group(p, g); if(!group.verify_group(rng, false)) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "DH group validation failed"); DH_PublicKey peer_key(group, Y); policy.check_peer_key_acceptable(peer_key); DH_PrivateKey priv_key(rng, group); PK_Key_Agreement ka(priv_key, rng, "Raw"); secure_vector dh_secret = CT::strip_leading_zeros( ka.derive_key(0, peer_key.public_value()).bits_of()); return std::make_pair(dh_secret, priv_key.public_value()); } std::pair, std::vector> TLS::Callbacks::tls_ecdh_agree( const std::string& curve_name, const std::vector& peer_public_value, const Policy& policy, RandomNumberGenerator& rng, bool compressed) { secure_vector ecdh_secret; std::vector our_public_value; if(curve_name == "x25519") { #if defined(BOTAN_HAS_CURVE_25519) if(peer_public_value.size() != 32) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid X25519 key size"); } Curve25519_PublicKey peer_key(peer_public_value); policy.check_peer_key_acceptable(peer_key); Curve25519_PrivateKey priv_key(rng); PK_Key_Agreement ka(priv_key, rng, "Raw"); ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of(); // X25519 is always compressed but sent as "uncompressed" in TLS our_public_value = priv_key.public_value(); #else throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); #endif } else { EC_Group group(OID::from_string(curve_name)); ECDH_PublicKey peer_key(group, group.OS2ECP(peer_public_value)); policy.check_peer_key_acceptable(peer_key); ECDH_PrivateKey priv_key(rng, group); PK_Key_Agreement ka(priv_key, rng, "Raw"); ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of(); our_public_value = priv_key.public_value(compressed ? PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED); } return std::make_pair(ecdh_secret, our_public_value); } } /* * TLS Channels * (C) 2011,2012,2014,2015,2016 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024; Channel::Channel(Callbacks& callbacks, Session_Manager& session_manager, RandomNumberGenerator& rng, const Policy& policy, bool is_server, bool is_datagram, size_t reserved_io_buffer_size) : m_is_server(is_server), m_is_datagram(is_datagram), m_callbacks(callbacks), m_session_manager(session_manager), m_policy(policy), m_rng(rng), m_has_been_closed(false) { init(reserved_io_buffer_size); } Channel::Channel(output_fn out, data_cb app_data_cb, alert_cb recv_alert_cb, handshake_cb hs_cb, handshake_msg_cb hs_msg_cb, Session_Manager& session_manager, RandomNumberGenerator& rng, const Policy& policy, bool is_server, bool is_datagram, size_t io_buf_sz) : m_is_server(is_server), m_is_datagram(is_datagram), m_compat_callbacks(new Compat_Callbacks( /* this Channel constructor is also deprecated so its ok that it relies on a deprecated API */ Compat_Callbacks::SILENCE_DEPRECATION_WARNING::PLEASE, out, app_data_cb, recv_alert_cb, hs_cb, hs_msg_cb)), m_callbacks(*m_compat_callbacks.get()), m_session_manager(session_manager), m_policy(policy), m_rng(rng), m_has_been_closed(false) { init(io_buf_sz); } void Channel::init(size_t io_buf_sz) { /* epoch 0 is plaintext, thus null cipher state */ m_write_cipher_states[0] = nullptr; m_read_cipher_states[0] = nullptr; m_writebuf.reserve(io_buf_sz); m_readbuf.reserve(io_buf_sz); } void Channel::reset_state() { m_active_state.reset(); m_pending_state.reset(); m_readbuf.clear(); m_write_cipher_states.clear(); m_read_cipher_states.clear(); } void Channel::reset_active_association_state() { // This operation only makes sense for DTLS BOTAN_ASSERT_NOMSG(m_is_datagram); m_active_state.reset(); m_read_cipher_states.clear(); m_write_cipher_states.clear(); m_write_cipher_states[0] = nullptr; m_read_cipher_states[0] = nullptr; if(m_sequence_numbers) m_sequence_numbers->reset(); } Channel::~Channel() { // So unique_ptr destructors run correctly } Connection_Sequence_Numbers& Channel::sequence_numbers() const { BOTAN_ASSERT(m_sequence_numbers, "Have a sequence numbers object"); return *m_sequence_numbers; } std::shared_ptr Channel::read_cipher_state_epoch(uint16_t epoch) const { auto i = m_read_cipher_states.find(epoch); if(i == m_read_cipher_states.end()) throw Internal_Error("TLS::Channel No read cipherstate for epoch " + std::to_string(epoch)); return i->second; } std::shared_ptr Channel::write_cipher_state_epoch(uint16_t epoch) const { auto i = m_write_cipher_states.find(epoch); if(i == m_write_cipher_states.end()) throw Internal_Error("TLS::Channel No write cipherstate for epoch " + std::to_string(epoch)); return i->second; } std::vector Channel::peer_cert_chain() const { if(auto active = active_state()) return get_peer_cert_chain(*active); return std::vector(); } bool Channel::save_session(const Session& session) { return callbacks().tls_session_established(session); } Handshake_State& Channel::create_handshake_state(Protocol_Version version) { if(pending_state()) throw Internal_Error("create_handshake_state called during handshake"); if(auto active = active_state()) { Protocol_Version active_version = active->version(); if(active_version.is_datagram_protocol() != version.is_datagram_protocol()) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Active state using version " + active_version.to_string() + " cannot change to " + version.to_string() + " in pending"); } } if(!m_sequence_numbers) { if(version.is_datagram_protocol()) m_sequence_numbers.reset(new Datagram_Sequence_Numbers); else m_sequence_numbers.reset(new Stream_Sequence_Numbers); } using namespace std::placeholders; std::unique_ptr io; if(version.is_datagram_protocol()) { io.reset(new Datagram_Handshake_IO( std::bind(&Channel::send_record_under_epoch, this, _1, _2, _3), sequence_numbers(), static_cast(m_policy.dtls_default_mtu()), m_policy.dtls_initial_timeout(), m_policy.dtls_maximum_timeout())); } else { io.reset(new Stream_Handshake_IO(std::bind(&Channel::send_record, this, _1, _2))); } m_pending_state.reset(new_handshake_state(io.release())); if(auto active = active_state()) m_pending_state->set_version(active->version()); return *m_pending_state.get(); } bool Channel::timeout_check() { if(m_pending_state) return m_pending_state->handshake_io().timeout_check(); //FIXME: scan cipher suites and remove epochs older than 2*MSL return false; } void Channel::renegotiate(bool force_full_renegotiation) { if(pending_state()) // currently in handshake? return; if(auto active = active_state()) { if(force_full_renegotiation == false) force_full_renegotiation = !policy().allow_resumption_for_renegotiation(); initiate_handshake(create_handshake_state(active->version()), force_full_renegotiation); } else throw Invalid_State("Cannot renegotiate on inactive connection"); } void Channel::change_cipher_spec_reader(Connection_Side side) { auto pending = pending_state(); BOTAN_ASSERT(pending && pending->server_hello(), "Have received server hello"); if(pending->server_hello()->compression_method() != 0) throw Internal_Error("Negotiated unknown compression algorithm"); sequence_numbers().new_read_cipher_state(); const uint16_t epoch = sequence_numbers().current_read_epoch(); BOTAN_ASSERT(m_read_cipher_states.count(epoch) == 0, "No read cipher state currently set for next epoch"); // flip side as we are reading std::shared_ptr read_state( new Connection_Cipher_State(pending->version(), (side == CLIENT) ? SERVER : CLIENT, false, pending->ciphersuite(), pending->session_keys(), pending->server_hello()->supports_encrypt_then_mac())); m_read_cipher_states[epoch] = read_state; } void Channel::change_cipher_spec_writer(Connection_Side side) { auto pending = pending_state(); BOTAN_ASSERT(pending && pending->server_hello(), "Have received server hello"); if(pending->server_hello()->compression_method() != 0) throw Internal_Error("Negotiated unknown compression algorithm"); sequence_numbers().new_write_cipher_state(); const uint16_t epoch = sequence_numbers().current_write_epoch(); BOTAN_ASSERT(m_write_cipher_states.count(epoch) == 0, "No write cipher state currently set for next epoch"); std::shared_ptr write_state( new Connection_Cipher_State(pending->version(), side, true, pending->ciphersuite(), pending->session_keys(), pending->server_hello()->supports_encrypt_then_mac())); m_write_cipher_states[epoch] = write_state; } bool Channel::is_active() const { if(is_closed()) return false; return (active_state() != nullptr); } bool Channel::is_closed() const { return m_has_been_closed; } void Channel::activate_session() { std::swap(m_active_state, m_pending_state); m_pending_state.reset(); if(!m_active_state->version().is_datagram_protocol()) { // TLS is easy just remove all but the current state const uint16_t current_epoch = sequence_numbers().current_write_epoch(); const auto not_current_epoch = [current_epoch](uint16_t epoch) { return (epoch != current_epoch); }; map_remove_if(not_current_epoch, m_write_cipher_states); map_remove_if(not_current_epoch, m_read_cipher_states); } callbacks().tls_session_activated(); } size_t Channel::received_data(const std::vector& buf) { return this->received_data(buf.data(), buf.size()); } size_t Channel::received_data(const uint8_t input[], size_t input_size) { const bool allow_epoch0_restart = m_is_datagram && m_is_server && policy().allow_dtls_epoch0_restart(); try { while(input_size) { size_t consumed = 0; auto get_epoch = [this](uint16_t epoch) { return read_cipher_state_epoch(epoch); }; const Record_Header record = read_record(m_is_datagram, m_readbuf, input, input_size, consumed, m_record_buf, m_sequence_numbers.get(), get_epoch, allow_epoch0_restart); const size_t needed = record.needed(); BOTAN_ASSERT(consumed > 0, "Got to eat something"); BOTAN_ASSERT(consumed <= input_size, "Record reader consumed sane amount"); input += consumed; input_size -= consumed; BOTAN_ASSERT(input_size == 0 || needed == 0, "Got a full record or consumed all input"); if(input_size == 0 && needed != 0) return needed; // need more data to complete record // Ignore invalid records in DTLS if(m_is_datagram && record.type() == NO_RECORD) { return 0; } if(m_record_buf.size() > MAX_PLAINTEXT_SIZE) throw TLS_Exception(Alert::RECORD_OVERFLOW, "TLS plaintext record is larger than allowed maximum"); const bool epoch0_restart = m_is_datagram && record.epoch() == 0 && active_state(); BOTAN_ASSERT_IMPLICATION(epoch0_restart, allow_epoch0_restart, "Allowed state"); const bool initial_record = epoch0_restart || (!pending_state() && !active_state()); if(record.type() != ALERT) { if(initial_record) { // For initial records just check for basic sanity if(record.version().major_version() != 3 && record.version().major_version() != 0xFE) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Received unexpected record version in initial record"); } } else if(auto pending = pending_state()) { if(pending->server_hello() != nullptr && record.version() != pending->version()) { if(record.version() != pending->version()) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Received unexpected record version"); } } } else if(auto active = active_state()) { if(record.version() != active->version()) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Received unexpected record version"); } } } if(record.type() == HANDSHAKE || record.type() == CHANGE_CIPHER_SPEC) { if(m_has_been_closed) throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Received handshake data after connection closure"); process_handshake_ccs(m_record_buf, record.sequence(), record.type(), record.version(), epoch0_restart); } else if(record.type() == APPLICATION_DATA) { if(m_has_been_closed) throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Received application data after connection closure"); if(pending_state() != nullptr) throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Can't interleave application and handshake data"); process_application_data(record.sequence(), m_record_buf); } else if(record.type() == ALERT) { process_alert(m_record_buf); } else if(record.type() != NO_RECORD) throw Unexpected_Message("Unexpected record type " + std::to_string(record.type()) + " from counterparty"); } return 0; // on a record boundary } catch(TLS_Exception& e) { send_fatal_alert(e.type()); throw; } catch(Invalid_Authentication_Tag&) { send_fatal_alert(Alert::BAD_RECORD_MAC); throw; } catch(Decoding_Error&) { send_fatal_alert(Alert::DECODE_ERROR); throw; } catch(...) { send_fatal_alert(Alert::INTERNAL_ERROR); throw; } } void Channel::process_handshake_ccs(const secure_vector& record, uint64_t record_sequence, Record_Type record_type, Protocol_Version record_version, bool epoch0_restart) { if(!m_pending_state) { // No pending handshake, possibly new: if(record_version.is_datagram_protocol() && !epoch0_restart) { if(m_sequence_numbers) { /* * Might be a peer retransmit under epoch - 1 in which * case we must retransmit last flight */ sequence_numbers().read_accept(record_sequence); const uint16_t epoch = record_sequence >> 48; if(epoch == sequence_numbers().current_read_epoch()) { create_handshake_state(record_version); } else if(epoch == sequence_numbers().current_read_epoch() - 1) { BOTAN_ASSERT(m_active_state, "Have active state here"); m_active_state->handshake_io().add_record(record.data(), record.size(), record_type, record_sequence); } } else { create_handshake_state(record_version); } } else { create_handshake_state(record_version); } } // May have been created in above conditional if(m_pending_state) { m_pending_state->handshake_io().add_record(record.data(), record.size(), record_type, record_sequence); while(auto pending = m_pending_state.get()) { auto msg = pending->get_next_handshake_msg(); if(msg.first == HANDSHAKE_NONE) // no full handshake yet break; process_handshake_msg(active_state(), *pending, msg.first, msg.second, epoch0_restart); if(!m_pending_state) break; } } } void Channel::process_application_data(uint64_t seq_no, const secure_vector& record) { if(!active_state()) throw Unexpected_Message("Application data before handshake done"); callbacks().tls_record_received(seq_no, record.data(), record.size()); } void Channel::process_alert(const secure_vector& record) { Alert alert_msg(record); if(alert_msg.type() == Alert::NO_RENEGOTIATION) m_pending_state.reset(); callbacks().tls_alert(alert_msg); if(alert_msg.is_fatal()) { if(auto active = active_state()) m_session_manager.remove_entry(active->server_hello()->session_id()); } if(alert_msg.type() == Alert::CLOSE_NOTIFY) send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal()) { m_has_been_closed = true; } } void Channel::write_record(Connection_Cipher_State* cipher_state, uint16_t epoch, uint8_t record_type, const uint8_t input[], size_t length) { BOTAN_ASSERT(m_pending_state || m_active_state, "Some connection state exists"); const Protocol_Version record_version = (m_pending_state) ? (m_pending_state->version()) : (m_active_state->version()); const uint64_t next_seq = sequence_numbers().next_write_sequence(epoch); if(cipher_state == nullptr) { TLS::write_unencrypted_record(m_writebuf, record_type, record_version, next_seq, input, length); } else { TLS::write_record(m_writebuf, record_type, record_version, next_seq, input, length, *cipher_state, m_rng); } callbacks().tls_emit_data(m_writebuf.data(), m_writebuf.size()); } void Channel::send_record_array(uint16_t epoch, uint8_t type, const uint8_t input[], size_t length) { if(length == 0) return; /* * In versions without an explicit IV field (only TLS v1.0 now that * SSLv3 has been removed) send a single byte record first to randomize * the following (implicit) IV of the following record. * * This isn't needed in TLS v1.1 or higher. * * An empty record also works but apparently some implementations do * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814) * * See https://www.openssl.org/~bodo/tls-cbc.txt for background. */ auto cipher_state = write_cipher_state_epoch(epoch); if(type == APPLICATION_DATA && m_active_state->version().supports_explicit_cbc_ivs() == false) { while(length) { write_record(cipher_state.get(), epoch, type, input, 1); input += 1; length -= 1; const size_t sending = std::min(length, MAX_PLAINTEXT_SIZE); write_record(cipher_state.get(), epoch, type, input, sending); input += sending; length -= sending; } } else { while(length) { const size_t sending = std::min(length, MAX_PLAINTEXT_SIZE); write_record(cipher_state.get(), epoch, type, input, sending); input += sending; length -= sending; } } } void Channel::send_record(uint8_t record_type, const std::vector& record) { send_record_array(sequence_numbers().current_write_epoch(), record_type, record.data(), record.size()); } void Channel::send_record_under_epoch(uint16_t epoch, uint8_t record_type, const std::vector& record) { send_record_array(epoch, record_type, record.data(), record.size()); } void Channel::send(const uint8_t buf[], size_t buf_size) { if(!is_active()) throw Invalid_State("Data cannot be sent on inactive TLS connection"); send_record_array(sequence_numbers().current_write_epoch(), APPLICATION_DATA, buf, buf_size); } void Channel::send(const std::string& string) { this->send(cast_char_ptr_to_uint8(string.data()), string.size()); } void Channel::send_alert(const Alert& alert) { if(alert.is_valid() && !is_closed()) { try { send_record(ALERT, alert.serialize()); } catch(...) { /* swallow it */ } } if(alert.type() == Alert::NO_RENEGOTIATION) m_pending_state.reset(); if(alert.is_fatal()) { if(auto active = active_state()) { m_session_manager.remove_entry(active->server_hello()->session_id()); } reset_state(); } if(alert.type() == Alert::CLOSE_NOTIFY || alert.is_fatal()) { m_has_been_closed = true; } } void Channel::secure_renegotiation_check(const Client_Hello* client_hello) { const bool secure_renegotiation = client_hello->secure_renegotiation(); if(auto active = active_state()) { const bool active_sr = active->client_hello()->secure_renegotiation(); if(active_sr != secure_renegotiation) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client changed its mind about secure renegotiation"); } if(secure_renegotiation) { const std::vector& data = client_hello->renegotiation_info(); if(data != secure_renegotiation_data_for_client_hello()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client sent bad values for secure renegotiation"); } } void Channel::secure_renegotiation_check(const Server_Hello* server_hello) { const bool secure_renegotiation = server_hello->secure_renegotiation(); if(auto active = active_state()) { const bool active_sr = active->server_hello()->secure_renegotiation(); if(active_sr != secure_renegotiation) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server changed its mind about secure renegotiation"); } if(secure_renegotiation) { const std::vector& data = server_hello->renegotiation_info(); if(data != secure_renegotiation_data_for_server_hello()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server sent bad values for secure renegotiation"); } } std::vector Channel::secure_renegotiation_data_for_client_hello() const { if(auto active = active_state()) return active->client_finished()->verify_data(); return std::vector(); } std::vector Channel::secure_renegotiation_data_for_server_hello() const { if(auto active = active_state()) { std::vector buf = active->client_finished()->verify_data(); buf += active->server_finished()->verify_data(); return buf; } return std::vector(); } bool Channel::secure_renegotiation_supported() const { if(auto active = active_state()) return active->server_hello()->secure_renegotiation(); if(auto pending = pending_state()) if(auto hello = pending->server_hello()) return hello->secure_renegotiation(); return false; } SymmetricKey Channel::key_material_export(const std::string& label, const std::string& context, size_t length) const { if(auto active = active_state()) { if(pending_state() != nullptr) throw Invalid_State("Channel::key_material_export cannot export during renegotiation"); std::unique_ptr prf(active->protocol_specific_prf()); const secure_vector& master_secret = active->session_keys().master_secret(); std::vector salt; salt += active->client_hello()->random(); salt += active->server_hello()->random(); if(context != "") { size_t context_size = context.length(); if(context_size > 0xFFFF) throw Invalid_Argument("key_material_export context is too long"); salt.push_back(get_byte(0, static_cast(context_size))); salt.push_back(get_byte(1, static_cast(context_size))); salt += to_byte_vector(context); } return prf->derive_key(length, master_secret, salt, to_byte_vector(label)); } else { throw Invalid_State("Channel::key_material_export connection not active"); } } } } /* * TLS Cipher Suite * (C) 2004-2010,2012,2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { size_t Ciphersuite::nonce_bytes_from_handshake() const { switch(m_nonce_format) { case Nonce_Format::CBC_MODE: { if(cipher_algo() == "3DES") return 8; else return 16; } case Nonce_Format::AEAD_IMPLICIT_4: return 4; case Nonce_Format::AEAD_XOR_12: return 12; } throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); } size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const { switch(m_nonce_format) { case Nonce_Format::CBC_MODE: { if(version.supports_explicit_cbc_ivs()) { return cipher_algo() == "3DES" ? 8 : 16; } else { return 0; } } case Nonce_Format::AEAD_IMPLICIT_4: return 8; case Nonce_Format::AEAD_XOR_12: return 0; } throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); } bool Ciphersuite::is_scsv(uint16_t suite) { // TODO: derive from IANA file in script return (suite == 0x00FF || suite == 0x5600); } bool Ciphersuite::psk_ciphersuite() const { return kex_method() == Kex_Algo::PSK || kex_method() == Kex_Algo::DHE_PSK || kex_method() == Kex_Algo::ECDHE_PSK; } bool Ciphersuite::ecc_ciphersuite() const { return kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK || auth_method() == Auth_Method::ECDSA; } bool Ciphersuite::usable_in_version(Protocol_Version version) const { if(!version.supports_aead_modes()) { // Old versions do not support AEAD, or any MAC but SHA-1 if(mac_algo() != "SHA-1") return false; } return true; } bool Ciphersuite::cbc_ciphersuite() const { return (mac_algo() != "AEAD"); } bool Ciphersuite::signature_used() const { return auth_method() != Auth_Method::ANONYMOUS && auth_method() != Auth_Method::IMPLICIT; } Ciphersuite Ciphersuite::by_id(uint16_t suite) { const std::vector& all_suites = all_known_ciphersuites(); auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite); if(s != all_suites.end() && s->ciphersuite_code() == suite) { return *s; } return Ciphersuite(); // some unknown ciphersuite } Ciphersuite Ciphersuite::from_name(const std::string& name) { const std::vector& all_suites = all_known_ciphersuites(); for(auto suite : all_suites) { if(suite.to_string() == name) return suite; } return Ciphersuite(); // some unknown ciphersuite } namespace { bool have_hash(const std::string& prf) { return (HashFunction::providers(prf).size() > 0); } bool have_cipher(const std::string& cipher) { return (BlockCipher::providers(cipher).size() > 0) || (StreamCipher::providers(cipher).size() > 0); } } bool Ciphersuite::is_usable() const { if(!m_cipher_keylen) // uninitialized object return false; if(!have_hash(prf_algo())) return false; #if !defined(BOTAN_HAS_TLS_CBC) if(cbc_ciphersuite()) return false; #endif if(mac_algo() == "AEAD") { if(cipher_algo() == "ChaCha20Poly1305") { #if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) return false; #endif } else { auto cipher_and_mode = split_on(cipher_algo(), '/'); BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); if(!have_cipher(cipher_and_mode[0])) return false; const auto mode = cipher_and_mode[1]; #if !defined(BOTAN_HAS_AEAD_CCM) if(mode == "CCM" || mode == "CCM-8") return false; #endif #if !defined(BOTAN_HAS_AEAD_GCM) if(mode == "GCM") return false; #endif #if !defined(BOTAN_HAS_AEAD_OCB) if(mode == "OCB(12)" || mode == "OCB") return false; #endif } } else { // Old non-AEAD schemes if(!have_cipher(cipher_algo())) return false; if(!have_hash(mac_algo())) // HMAC return false; } if(kex_method() == Kex_Algo::SRP_SHA) { #if !defined(BOTAN_HAS_SRP6) return false; #endif } else if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK) { #if !defined(BOTAN_HAS_ECDH) return false; #endif } else if(kex_method() == Kex_Algo::DH || kex_method() == Kex_Algo::DHE_PSK) { #if !defined(BOTAN_HAS_DIFFIE_HELLMAN) return false; #endif } else if(kex_method() == Kex_Algo::CECPQ1) { #if !defined(BOTAN_HAS_CECPQ1) return false; #endif } if(auth_method() == Auth_Method::DSA) { #if !defined(BOTAN_HAS_DSA) return false; #endif } else if(auth_method() == Auth_Method::ECDSA) { #if !defined(BOTAN_HAS_ECDSA) return false; #endif } else if(auth_method() == Auth_Method::RSA) { #if !defined(BOTAN_HAS_RSA) return false; #endif } return true; } } } /* * TLS Client * (C) 2004-2011,2012,2015,2016 Jack Lloyd * 2016 Matthias Gierlings * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { namespace { class Client_Handshake_State final : public Handshake_State { public: Client_Handshake_State(Handshake_IO* io, Callbacks& cb) : Handshake_State(io, cb), m_is_reneg(false) {} const Public_Key& get_server_public_key() const { BOTAN_ASSERT(server_public_key, "Server sent us a certificate"); return *server_public_key.get(); } bool is_a_resumption() const { return (resumed_session != nullptr); } bool is_a_renegotiation() const { return m_is_reneg; } const secure_vector& resume_master_secret() const { BOTAN_STATE_CHECK(is_a_resumption()); return resumed_session->master_secret(); } const std::vector& resume_peer_certs() const { BOTAN_STATE_CHECK(is_a_resumption()); return resumed_session->peer_certs(); } std::unique_ptr server_public_key; // Used during session resumption std::unique_ptr resumed_session; bool m_is_reneg = false; }; } /* * TLS Client Constructor */ Client::Client(Callbacks& callbacks, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, const Server_Information& info, const Protocol_Version& offer_version, const std::vector& next_protos, size_t io_buf_sz) : Channel(callbacks, session_manager, rng, policy, false, offer_version.is_datagram_protocol(), io_buf_sz), m_creds(creds), m_info(info) { init(offer_version, next_protos); } Client::Client(output_fn data_output_fn, data_cb proc_cb, alert_cb recv_alert_cb, handshake_cb hs_cb, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, const Server_Information& info, const Protocol_Version& offer_version, const std::vector& next_protos, size_t io_buf_sz) : Channel(data_output_fn, proc_cb, recv_alert_cb, hs_cb, Channel::handshake_msg_cb(), session_manager, rng, policy, false, offer_version.is_datagram_protocol(), io_buf_sz), m_creds(creds), m_info(info) { init(offer_version, next_protos); } Client::Client(output_fn data_output_fn, data_cb proc_cb, alert_cb recv_alert_cb, handshake_cb hs_cb, handshake_msg_cb hs_msg_cb, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, const Server_Information& info, const Protocol_Version& offer_version, const std::vector& next_protos) : Channel(data_output_fn, proc_cb, recv_alert_cb, hs_cb, hs_msg_cb, session_manager, rng, policy, false, offer_version.is_datagram_protocol()), m_creds(creds), m_info(info) { init(offer_version, next_protos); } void Client::init(const Protocol_Version& protocol_version, const std::vector& next_protocols) { const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname()); Handshake_State& state = create_handshake_state(protocol_version); send_client_hello(state, false, protocol_version, srp_identifier, next_protocols); } Handshake_State* Client::new_handshake_state(Handshake_IO* io) { return new Client_Handshake_State(io, callbacks()); } std::vector Client::get_peer_cert_chain(const Handshake_State& state) const { const Client_Handshake_State& cstate = dynamic_cast(state); if(cstate.is_a_resumption()) return cstate.resume_peer_certs(); if(state.server_certs()) return state.server_certs()->cert_chain(); return std::vector(); } /* * Send a new client hello to renegotiate */ void Client::initiate_handshake(Handshake_State& state, bool force_full_renegotiation) { send_client_hello(state, force_full_renegotiation, policy().latest_supported_version(state.version().is_datagram_protocol())); } void Client::send_client_hello(Handshake_State& state_base, bool force_full_renegotiation, Protocol_Version version, const std::string& srp_identifier, const std::vector& next_protocols) { Client_Handshake_State& state = dynamic_cast(state_base); if(state.version().is_datagram_protocol()) state.set_expected_next(HELLO_VERIFY_REQUEST); // optional state.set_expected_next(SERVER_HELLO); if(!force_full_renegotiation && !m_info.empty()) { std::unique_ptr session_info(new Session);; if(session_manager().load_from_server_info(m_info, *session_info)) { /* Ensure that the session protocol cipher and version are acceptable If not skip the resume and establish a new session */ const bool exact_version = session_info->version() == version; const bool ok_version = (session_info->version().is_datagram_protocol() == version.is_datagram_protocol()) && policy().acceptable_protocol_version(session_info->version()); const bool session_version_ok = policy().only_resume_with_exact_version() ? exact_version : ok_version; if(policy().acceptable_ciphersuite(session_info->ciphersuite()) && session_version_ok) { if(srp_identifier == "" || session_info->srp_identifier() == srp_identifier) { state.client_hello( new Client_Hello(state.handshake_io(), state.hash(), policy(), callbacks(), rng(), secure_renegotiation_data_for_client_hello(), *session_info, next_protocols)); state.resumed_session = std::move(session_info); } } } } if(!state.client_hello()) // not resuming { Client_Hello::Settings client_settings(version, m_info.hostname(), srp_identifier); state.client_hello(new Client_Hello( state.handshake_io(), state.hash(), policy(), callbacks(), rng(), secure_renegotiation_data_for_client_hello(), client_settings, next_protocols)); } secure_renegotiation_check(state.client_hello()); } namespace { bool key_usage_matches_ciphersuite(Key_Constraints usage, const Ciphersuite& suite) { if(usage == NO_CONSTRAINTS) return true; // anything goes ... if(suite.kex_method() == Kex_Algo::STATIC_RSA) { return (usage & KEY_ENCIPHERMENT) | (usage & DATA_ENCIPHERMENT); } else { return (usage & DIGITAL_SIGNATURE) | (usage & NON_REPUDIATION); } } } /* * Process a handshake message */ void Client::process_handshake_msg(const Handshake_State* active_state, Handshake_State& state_base, Handshake_Type type, const std::vector& contents, bool epoch0_restart) { BOTAN_ASSERT_NOMSG(epoch0_restart == false); // only happens on server side Client_Handshake_State& state = dynamic_cast(state_base); if(type == HELLO_REQUEST && active_state) { Hello_Request hello_request(contents); if(state.client_hello()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Cannot renegotiate during a handshake"); } if(policy().allow_server_initiated_renegotiation()) { if(secure_renegotiation_supported() || policy().allow_insecure_renegotiation()) { state.m_is_reneg = true; this->initiate_handshake(state, true); } else { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client policy prohibits insecure renegotiation"); } } else { if(policy().abort_connection_on_undesired_renegotiation()) { throw TLS_Exception(Alert::NO_RENEGOTIATION, "Client policy prohibits renegotiation"); } else { // RFC 5746 section 4.2 send_warning_alert(Alert::NO_RENEGOTIATION); } } return; } state.confirm_transition_to(type); if(type != HANDSHAKE_CCS && type != FINISHED && type != HELLO_VERIFY_REQUEST) state.hash().update(state.handshake_io().format(contents, type)); if(type == HELLO_VERIFY_REQUEST) { state.set_expected_next(SERVER_HELLO); state.set_expected_next(HELLO_VERIFY_REQUEST); // might get it again Hello_Verify_Request hello_verify_request(contents); state.hello_verify_request(hello_verify_request); } else if(type == SERVER_HELLO) { state.server_hello(new Server_Hello(contents)); if(!state.client_hello()->offered_suite(state.server_hello()->ciphersuite())) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server replied with ciphersuite we didn't send"); } if(!Ciphersuite::by_id(state.server_hello()->ciphersuite()).usable_in_version(state.server_hello()->version())) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server replied using a ciphersuite not allowed in version it offered"); } if(Ciphersuite::is_scsv(state.server_hello()->ciphersuite())) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server replied with a signaling ciphersuite"); } if(state.server_hello()->compression_method() != 0) { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Server replied with non-null compression method"); } if(state.client_hello()->version() > state.server_hello()->version()) { if(state.server_hello()->random_signals_downgrade()) throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Downgrade attack detected"); } auto client_extn = state.client_hello()->extension_types(); auto server_extn = state.server_hello()->extension_types(); std::vector diff; std::set_difference(server_extn.begin(), server_extn.end(), client_extn.begin(), client_extn.end(), std::back_inserter(diff)); if(!diff.empty()) { // Server sent us back an extension we did not send! std::ostringstream msg; msg << "Server replied with unsupported extensions:"; for(auto&& d : diff) msg << " " << static_cast(d); throw TLS_Exception(Alert::UNSUPPORTED_EXTENSION, msg.str()); } if(uint16_t srtp = state.server_hello()->srtp_profile()) { if(!value_exists(state.client_hello()->srtp_profiles(), srtp)) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server replied with DTLS-SRTP alg we did not send"); } callbacks().tls_examine_extensions(state.server_hello()->extensions(), SERVER); state.set_version(state.server_hello()->version()); m_application_protocol = state.server_hello()->next_protocol(); secure_renegotiation_check(state.server_hello()); const bool server_returned_same_session_id = !state.server_hello()->session_id().empty() && (state.server_hello()->session_id() == state.client_hello()->session_id()); if(server_returned_same_session_id) { // successful resumption /* * In this case, we offered the version used in the original * session, and the server must resume with the same version. */ if(state.server_hello()->version() != state.client_hello()->version()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server resumed session but with wrong version"); if(state.server_hello()->supports_extended_master_secret() && !state.resumed_session->supports_extended_master_secret()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server resumed session but added extended master secret"); } if(!state.server_hello()->supports_extended_master_secret() && state.resumed_session->supports_extended_master_secret()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server resumed session and removed extended master secret"); } state.compute_session_keys(state.resume_master_secret()); if(state.server_hello()->supports_session_ticket()) { state.set_expected_next(NEW_SESSION_TICKET); } else { state.set_expected_next(HANDSHAKE_CCS); } } else { // new session if(active_state) { // Here we are testing things that should not change during a renegotation, // even if the server creates a new session. Howerver they might change // in a resumption scenario. if(active_state->version() != state.server_hello()->version()) throw TLS_Exception(Alert::PROTOCOL_VERSION, "Server changed version after renegotiation"); if(state.server_hello()->supports_extended_master_secret() != active_state->server_hello()->supports_extended_master_secret()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server changed its mind about extended master secret"); } } state.resumed_session.reset(); // non-null if we were attempting a resumption if(state.client_hello()->version().is_datagram_protocol() != state.server_hello()->version().is_datagram_protocol()) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Server replied with different protocol type than we offered"); } if(state.version() > state.client_hello()->version()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server replied with later version than client offered"); } if(state.version().major_version() == 3 && state.version().minor_version() == 0) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Server attempting to negotiate SSLv3 which is not supported"); } if(!policy().acceptable_protocol_version(state.version())) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Server version " + state.version().to_string() + " is unacceptable by policy"); } if(state.ciphersuite().signature_used() || state.ciphersuite().kex_method() == Kex_Algo::STATIC_RSA) { state.set_expected_next(CERTIFICATE); } else if(state.ciphersuite().kex_method() == Kex_Algo::PSK) { /* PSK is anonymous so no certificate/cert req message is ever sent. The server may or may not send a server kex, depending on if it has an identity hint for us. (EC)DHE_PSK always sends a server key exchange for the DH exchange portion, and is covered by block below */ state.set_expected_next(SERVER_KEX); state.set_expected_next(SERVER_HELLO_DONE); } else if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) { state.set_expected_next(SERVER_KEX); } else { state.set_expected_next(CERTIFICATE_REQUEST); // optional state.set_expected_next(SERVER_HELLO_DONE); } } } else if(type == CERTIFICATE) { state.server_certs(new Certificate(contents, policy())); const std::vector& server_certs = state.server_certs()->cert_chain(); if(server_certs.empty()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client: No certificates sent by server"); /* If the server supports certificate status messages, certificate verification happens after we receive the server hello done, in case an OCSP response was also available */ X509_Certificate server_cert = server_certs[0]; if(active_state && active_state->server_certs()) { X509_Certificate current_cert = active_state->server_certs()->cert_chain().at(0); if(current_cert != server_cert) throw TLS_Exception(Alert::BAD_CERTIFICATE, "Server certificate changed during renegotiation"); } std::unique_ptr peer_key(server_cert.subject_public_key()); const std::string expected_key_type = state.ciphersuite().signature_used() ? state.ciphersuite().sig_algo() : "RSA"; if(peer_key->algo_name() != expected_key_type) throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Certificate key type did not match ciphersuite"); if(!key_usage_matches_ciphersuite(server_cert.constraints(), state.ciphersuite())) throw TLS_Exception(Alert::BAD_CERTIFICATE, "Certificate usage constraints do not allow this ciphersuite"); state.server_public_key.reset(peer_key.release()); if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) { state.set_expected_next(SERVER_KEX); } else { state.set_expected_next(CERTIFICATE_REQUEST); // optional state.set_expected_next(SERVER_HELLO_DONE); } if(state.server_hello()->supports_certificate_status_message()) { state.set_expected_next(CERTIFICATE_STATUS); // optional } else { try { auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); callbacks().tls_verify_cert_chain(server_certs, {}, trusted_CAs, Usage_Type::TLS_SERVER_AUTH, m_info.hostname(), policy()); } catch(TLS_Exception&) { throw; } catch(std::exception& e) { throw TLS_Exception(Alert::INTERNAL_ERROR, e.what()); } } } else if(type == CERTIFICATE_STATUS) { state.server_cert_status(new Certificate_Status(contents)); if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) { state.set_expected_next(SERVER_KEX); } else { state.set_expected_next(CERTIFICATE_REQUEST); // optional state.set_expected_next(SERVER_HELLO_DONE); } } else if(type == SERVER_KEX) { if(state.ciphersuite().psk_ciphersuite() == false) state.set_expected_next(CERTIFICATE_REQUEST); // optional state.set_expected_next(SERVER_HELLO_DONE); state.server_kex( new Server_Key_Exchange(contents, state.ciphersuite().kex_method(), state.ciphersuite().auth_method(), state.version()) ); if(state.ciphersuite().signature_used()) { const Public_Key& server_key = state.get_server_public_key(); if(!state.server_kex()->verify(server_key, state, policy())) { throw TLS_Exception(Alert::DECRYPT_ERROR, "Bad signature on server key exchange"); } } } else if(type == CERTIFICATE_REQUEST) { state.set_expected_next(SERVER_HELLO_DONE); state.cert_req(new Certificate_Req(contents, state.version())); } else if(type == SERVER_HELLO_DONE) { state.server_hello_done(new Server_Hello_Done(contents)); if(state.server_certs() != nullptr && state.server_hello()->supports_certificate_status_message()) { try { auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); std::vector> ocsp; if(state.server_cert_status() != nullptr) { try { ocsp.push_back(std::make_shared(state.server_cert_status()->response())); } catch(Decoding_Error&) { // ignore it here because it might be our fault } } callbacks().tls_verify_cert_chain(state.server_certs()->cert_chain(), ocsp, trusted_CAs, Usage_Type::TLS_SERVER_AUTH, m_info.hostname(), policy()); } catch(TLS_Exception&) { throw; } catch(std::exception& e) { throw TLS_Exception(Alert::INTERNAL_ERROR, e.what()); } } if(state.received_handshake_msg(CERTIFICATE_REQUEST)) { const auto& types = state.cert_req()->acceptable_cert_types(); std::vector client_certs = m_creds.find_cert_chain(types, state.cert_req()->acceptable_CAs(), "tls-client", m_info.hostname()); state.client_certs(new Certificate(state.handshake_io(), state.hash(), client_certs)); } state.client_kex( new Client_Key_Exchange(state.handshake_io(), state, policy(), m_creds, state.server_public_key.get(), m_info.hostname(), rng()) ); state.compute_session_keys(); if(state.received_handshake_msg(CERTIFICATE_REQUEST) && !state.client_certs()->empty()) { Private_Key* private_key = m_creds.private_key_for(state.client_certs()->cert_chain()[0], "tls-client", m_info.hostname()); state.client_verify( new Certificate_Verify(state.handshake_io(), state, policy(), rng(), private_key) ); } state.handshake_io().send(Change_Cipher_Spec()); change_cipher_spec_writer(CLIENT); state.client_finished(new Finished(state.handshake_io(), state, CLIENT)); if(state.server_hello()->supports_session_ticket()) state.set_expected_next(NEW_SESSION_TICKET); else state.set_expected_next(HANDSHAKE_CCS); } else if(type == NEW_SESSION_TICKET) { state.new_session_ticket(new New_Session_Ticket(contents)); state.set_expected_next(HANDSHAKE_CCS); } else if(type == HANDSHAKE_CCS) { state.set_expected_next(FINISHED); change_cipher_spec_reader(CLIENT); } else if(type == FINISHED) { state.server_finished(new Finished(contents)); if(!state.server_finished()->verify(state, SERVER)) throw TLS_Exception(Alert::DECRYPT_ERROR, "Finished message didn't verify"); state.hash().update(state.handshake_io().format(contents, type)); if(!state.client_finished()) // session resume case { state.handshake_io().send(Change_Cipher_Spec()); change_cipher_spec_writer(CLIENT); state.client_finished(new Finished(state.handshake_io(), state, CLIENT)); } std::vector session_id = state.server_hello()->session_id(); const std::vector& session_ticket = state.session_ticket(); if(session_id.empty() && !session_ticket.empty()) session_id = make_hello_random(rng(), policy()); Session session_info( session_id, state.session_keys().master_secret(), state.server_hello()->version(), state.server_hello()->ciphersuite(), CLIENT, state.server_hello()->supports_extended_master_secret(), state.server_hello()->supports_encrypt_then_mac(), get_peer_cert_chain(state), session_ticket, m_info, "", state.server_hello()->srtp_profile() ); const bool should_save = save_session(session_info); if(session_id.size() > 0 && state.is_a_resumption() == false) { if(should_save) session_manager().save(session_info); else session_manager().remove_entry(session_info.session_id()); } activate_session(); } else throw Unexpected_Message("Unknown handshake message received"); } } } /* * TLS Extensions * (C) 2011,2012,2015,2016 Jack Lloyd * 2016 Juraj Somorovsky * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { namespace { Extension* make_extension(TLS_Data_Reader& reader, uint16_t code, uint16_t size, Connection_Side from) { switch(code) { case TLSEXT_SERVER_NAME_INDICATION: return new Server_Name_Indicator(reader, size); #if defined(BOTAN_HAS_SRP6) case TLSEXT_SRP_IDENTIFIER: return new SRP_Identifier(reader, size); #endif case TLSEXT_SUPPORTED_GROUPS: return new Supported_Groups(reader, size); case TLSEXT_CERT_STATUS_REQUEST: return new Certificate_Status_Request(reader, size, from); case TLSEXT_EC_POINT_FORMATS: return new Supported_Point_Formats(reader, size); case TLSEXT_SAFE_RENEGOTIATION: return new Renegotiation_Extension(reader, size); case TLSEXT_SIGNATURE_ALGORITHMS: return new Signature_Algorithms(reader, size); case TLSEXT_USE_SRTP: return new SRTP_Protection_Profiles(reader, size); case TLSEXT_ALPN: return new Application_Layer_Protocol_Notification(reader, size); case TLSEXT_EXTENDED_MASTER_SECRET: return new Extended_Master_Secret(reader, size); case TLSEXT_ENCRYPT_THEN_MAC: return new Encrypt_then_MAC(reader, size); case TLSEXT_SESSION_TICKET: return new Session_Ticket(reader, size); case TLSEXT_SUPPORTED_VERSIONS: return new Supported_Versions(reader, size, from); } return new Unknown_Extension(static_cast(code), reader, size); } } void Extensions::deserialize(TLS_Data_Reader& reader, Connection_Side from) { if(reader.has_remaining()) { const uint16_t all_extn_size = reader.get_uint16_t(); if(reader.remaining_bytes() != all_extn_size) throw Decoding_Error("Bad extension size"); while(reader.has_remaining()) { const uint16_t extension_code = reader.get_uint16_t(); const uint16_t extension_size = reader.get_uint16_t(); const auto type = static_cast(extension_code); if(m_extensions.find(type) != m_extensions.end()) throw TLS_Exception(TLS::Alert::DECODE_ERROR, "Peer sent duplicated extensions"); Extension* extn = make_extension( reader, extension_code, extension_size, from); this->add(extn); } } } std::vector Extensions::serialize(Connection_Side whoami) const { std::vector buf(2); // 2 bytes for length field for(auto& extn : m_extensions) { if(extn.second->empty()) continue; const uint16_t extn_code = static_cast(extn.second->type()); const std::vector extn_val = extn.second->serialize(whoami); buf.push_back(get_byte(0, extn_code)); buf.push_back(get_byte(1, extn_code)); buf.push_back(get_byte(0, static_cast(extn_val.size()))); buf.push_back(get_byte(1, static_cast(extn_val.size()))); buf += extn_val; } const uint16_t extn_size = static_cast(buf.size() - 2); buf[0] = get_byte(0, extn_size); buf[1] = get_byte(1, extn_size); // avoid sending a completely empty extensions block if(buf.size() == 2) return std::vector(); return buf; } bool Extensions::remove_extension(Handshake_Extension_Type typ) { auto i = m_extensions.find(typ); if(i == m_extensions.end()) return false; m_extensions.erase(i); return true; } std::set Extensions::extension_types() const { std::set offers; for(auto i = m_extensions.begin(); i != m_extensions.end(); ++i) offers.insert(i->first); return offers; } Unknown_Extension::Unknown_Extension(Handshake_Extension_Type type, TLS_Data_Reader& reader, uint16_t extension_size) : m_type(type), m_value(reader.get_fixed(extension_size)) { } std::vector Unknown_Extension::serialize(Connection_Side /*whoami*/) const { throw Invalid_State("Cannot encode an unknown TLS extension"); } Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader, uint16_t extension_size) { /* * This is used by the server to confirm that it knew the name */ if(extension_size == 0) return; uint16_t name_bytes = reader.get_uint16_t(); if(name_bytes + 2 != extension_size) throw Decoding_Error("Bad encoding of SNI extension"); while(name_bytes) { uint8_t name_type = reader.get_byte(); name_bytes--; if(name_type == 0) // DNS { m_sni_host_name = reader.get_string(2, 1, 65535); name_bytes -= static_cast(2 + m_sni_host_name.size()); } else // some other unknown name type { reader.discard_next(name_bytes); name_bytes = 0; } } } std::vector Server_Name_Indicator::serialize(Connection_Side /*whoami*/) const { std::vector buf; size_t name_len = m_sni_host_name.size(); buf.push_back(get_byte(0, static_cast(name_len+3))); buf.push_back(get_byte(1, static_cast(name_len+3))); buf.push_back(0); // DNS buf.push_back(get_byte(0, static_cast(name_len))); buf.push_back(get_byte(1, static_cast(name_len))); buf += std::make_pair( cast_char_ptr_to_uint8(m_sni_host_name.data()), m_sni_host_name.size()); return buf; } #if defined(BOTAN_HAS_SRP6) SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader, uint16_t extension_size) : m_srp_identifier(reader.get_string(1, 1, 255)) { if(m_srp_identifier.size() + 1 != extension_size) throw Decoding_Error("Bad encoding for SRP identifier extension"); } std::vector SRP_Identifier::serialize(Connection_Side /*whoami*/) const { std::vector buf; const uint8_t* srp_bytes = cast_char_ptr_to_uint8(m_srp_identifier.data()); append_tls_length_value(buf, srp_bytes, m_srp_identifier.size(), 1); return buf; } #endif Renegotiation_Extension::Renegotiation_Extension(TLS_Data_Reader& reader, uint16_t extension_size) : m_reneg_data(reader.get_range(1, 0, 255)) { if(m_reneg_data.size() + 1 != extension_size) throw Decoding_Error("Bad encoding for secure renegotiation extn"); } std::vector Renegotiation_Extension::serialize(Connection_Side /*whoami*/) const { std::vector buf; append_tls_length_value(buf, m_reneg_data, 1); return buf; } Application_Layer_Protocol_Notification::Application_Layer_Protocol_Notification(TLS_Data_Reader& reader, uint16_t extension_size) { if(extension_size == 0) return; // empty extension const uint16_t name_bytes = reader.get_uint16_t(); size_t bytes_remaining = extension_size - 2; if(name_bytes != bytes_remaining) throw Decoding_Error("Bad encoding of ALPN extension, bad length field"); while(bytes_remaining) { const std::string p = reader.get_string(1, 0, 255); if(bytes_remaining < p.size() + 1) throw Decoding_Error("Bad encoding of ALPN, length field too long"); if(p.empty()) throw Decoding_Error("Empty ALPN protocol not allowed"); bytes_remaining -= (p.size() + 1); m_protocols.push_back(p); } } const std::string& Application_Layer_Protocol_Notification::single_protocol() const { if(m_protocols.size() != 1) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server sent " + std::to_string(m_protocols.size()) + " protocols in ALPN extension response"); return m_protocols[0]; } std::vector Application_Layer_Protocol_Notification::serialize(Connection_Side /*whoami*/) const { std::vector buf(2); for(auto&& p: m_protocols) { if(p.length() >= 256) throw TLS_Exception(Alert::INTERNAL_ERROR, "ALPN name too long"); if(p != "") append_tls_length_value(buf, cast_char_ptr_to_uint8(p.data()), p.size(), 1); } buf[0] = get_byte(0, static_cast(buf.size()-2)); buf[1] = get_byte(1, static_cast(buf.size()-2)); return buf; } Supported_Groups::Supported_Groups(const std::vector& groups) : m_groups(groups) { } std::vector Supported_Groups::ec_groups() const { std::vector ec; for(auto g : m_groups) { if(group_param_is_dh(g) == false) ec.push_back(g); } return ec; } std::vector Supported_Groups::dh_groups() const { std::vector dh; for(auto g : m_groups) { if(group_param_is_dh(g) == true) dh.push_back(g); } return dh; } std::vector Supported_Groups::serialize(Connection_Side /*whoami*/) const { std::vector buf(2); for(auto g : m_groups) { const uint16_t id = static_cast(g); if(id > 0) { buf.push_back(get_byte(0, id)); buf.push_back(get_byte(1, id)); } } buf[0] = get_byte(0, static_cast(buf.size()-2)); buf[1] = get_byte(1, static_cast(buf.size()-2)); return buf; } Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, uint16_t extension_size) { const uint16_t len = reader.get_uint16_t(); if(len + 2 != extension_size) throw Decoding_Error("Inconsistent length field in supported groups list"); if(len % 2 == 1) throw Decoding_Error("Supported groups list of strange size"); const size_t elems = len / 2; for(size_t i = 0; i != elems; ++i) { const uint16_t id = reader.get_uint16_t(); m_groups.push_back(static_cast(id)); } } std::vector Supported_Point_Formats::serialize(Connection_Side /*whoami*/) const { // if this extension is sent, it MUST include uncompressed (RFC 4492, section 5.1) if(m_prefers_compressed) { return std::vector{2, ANSIX962_COMPRESSED_PRIME, UNCOMPRESSED}; } else { return std::vector{1, UNCOMPRESSED}; } } Supported_Point_Formats::Supported_Point_Formats(TLS_Data_Reader& reader, uint16_t extension_size) { uint8_t len = reader.get_byte(); if(len + 1 != extension_size) throw Decoding_Error("Inconsistent length field in supported point formats list"); for(size_t i = 0; i != len; ++i) { uint8_t format = reader.get_byte(); if(static_cast(format) == UNCOMPRESSED) { m_prefers_compressed = false; reader.discard_next(len-i-1); return; } else if(static_cast(format) == ANSIX962_COMPRESSED_PRIME) { m_prefers_compressed = true; reader.discard_next(len-i-1); return; } // ignore ANSIX962_COMPRESSED_CHAR2, we don't support these curves } } std::vector Signature_Algorithms::serialize(Connection_Side /*whoami*/) const { BOTAN_ASSERT(m_schemes.size() < 256, "Too many signature schemes"); std::vector buf; const uint16_t len = static_cast(m_schemes.size() * 2); buf.push_back(get_byte(0, len)); buf.push_back(get_byte(1, len)); for(Signature_Scheme scheme : m_schemes) { const uint16_t scheme_code = static_cast(scheme); buf.push_back(get_byte(0, scheme_code)); buf.push_back(get_byte(1, scheme_code)); } return buf; } Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader, uint16_t extension_size) { uint16_t len = reader.get_uint16_t(); if(len + 2 != extension_size || len % 2 == 1 || len == 0) { throw Decoding_Error("Bad encoding on signature algorithms extension"); } while(len) { const uint16_t scheme_code = reader.get_uint16_t(); m_schemes.push_back(static_cast(scheme_code)); len -= 2; } } Session_Ticket::Session_Ticket(TLS_Data_Reader& reader, uint16_t extension_size) : m_ticket(reader.get_elem>(extension_size)) {} SRTP_Protection_Profiles::SRTP_Protection_Profiles(TLS_Data_Reader& reader, uint16_t extension_size) : m_pp(reader.get_range(2, 0, 65535)) { const std::vector mki = reader.get_range(1, 0, 255); if(m_pp.size() * 2 + mki.size() + 3 != extension_size) throw Decoding_Error("Bad encoding for SRTP protection extension"); if(!mki.empty()) throw Decoding_Error("Unhandled non-empty MKI for SRTP protection extension"); } std::vector SRTP_Protection_Profiles::serialize(Connection_Side /*whoami*/) const { std::vector buf; const uint16_t pp_len = static_cast(m_pp.size() * 2); buf.push_back(get_byte(0, pp_len)); buf.push_back(get_byte(1, pp_len)); for(uint16_t pp : m_pp) { buf.push_back(get_byte(0, pp)); buf.push_back(get_byte(1, pp)); } buf.push_back(0); // srtp_mki, always empty here return buf; } Extended_Master_Secret::Extended_Master_Secret(TLS_Data_Reader&, uint16_t extension_size) { if(extension_size != 0) throw Decoding_Error("Invalid extended_master_secret extension"); } std::vector Extended_Master_Secret::serialize(Connection_Side /*whoami*/) const { return std::vector(); } Encrypt_then_MAC::Encrypt_then_MAC(TLS_Data_Reader&, uint16_t extension_size) { if(extension_size != 0) throw Decoding_Error("Invalid encrypt_then_mac extension"); } std::vector Encrypt_then_MAC::serialize(Connection_Side /*whoami*/) const { return std::vector(); } std::vector Certificate_Status_Request::serialize(Connection_Side whoami) const { std::vector buf; if(whoami == Connection_Side::SERVER) return buf; // server reply is empty /* opaque ResponderID<1..2^16-1>; opaque Extensions<0..2^16-1>; CertificateStatusType status_type = ocsp(1) ResponderID responder_id_list<0..2^16-1> Extensions request_extensions; */ buf.push_back(1); // CertificateStatusType ocsp buf.push_back(0); buf.push_back(0); buf.push_back(0); buf.push_back(0); return buf; } Certificate_Status_Request::Certificate_Status_Request(TLS_Data_Reader& reader, uint16_t extension_size, Connection_Side from) { if(from == Connection_Side::SERVER) { if(extension_size != 0) throw Decoding_Error("Server sent non-empty Certificate_Status_Request extension"); } else if(extension_size > 0) { const uint8_t type = reader.get_byte(); if(type == 1) { const size_t len_resp_id_list = reader.get_uint16_t(); m_ocsp_names = reader.get_fixed(len_resp_id_list); const size_t len_requ_ext = reader.get_uint16_t(); m_extension_bytes = reader.get_fixed(len_requ_ext); } else { reader.discard_next(extension_size - 1); } } } Certificate_Status_Request::Certificate_Status_Request(const std::vector& ocsp_responder_ids, const std::vector>& ocsp_key_ids) : m_ocsp_names(ocsp_responder_ids), m_ocsp_keys(ocsp_key_ids) { } std::vector Supported_Versions::serialize(Connection_Side whoami) const { std::vector buf; if(whoami == Connection_Side::SERVER) { BOTAN_ASSERT_NOMSG(m_versions.size() == 1); buf.push_back(m_versions[0].major_version()); buf.push_back(m_versions[0].minor_version()); } else { BOTAN_ASSERT_NOMSG(m_versions.size() >= 1); const uint8_t len = static_cast(m_versions.size() * 2); buf.push_back(len); for(Protocol_Version version : m_versions) { buf.push_back(get_byte(0, version.major_version())); buf.push_back(get_byte(1, version.minor_version())); } } return buf; } Supported_Versions::Supported_Versions(Protocol_Version offer, const Policy& policy) { if(offer.is_datagram_protocol()) { if(offer >= Protocol_Version::DTLS_V12 && policy.allow_dtls12()) m_versions.push_back(Protocol_Version::DTLS_V12); #if defined(BOTAN_HAS_TLS_V10) if(offer >= Protocol_Version::DTLS_V10 && policy.allow_dtls10()) m_versions.push_back(Protocol_Version::DTLS_V10); #endif } else { if(offer >= Protocol_Version::TLS_V12 && policy.allow_tls12()) m_versions.push_back(Protocol_Version::TLS_V12); #if defined(BOTAN_HAS_TLS_V10) if(offer >= Protocol_Version::TLS_V11 && policy.allow_tls11()) m_versions.push_back(Protocol_Version::TLS_V11); if(offer >= Protocol_Version::TLS_V10 && policy.allow_tls10()) m_versions.push_back(Protocol_Version::TLS_V10); #endif } } Supported_Versions::Supported_Versions(TLS_Data_Reader& reader, uint16_t extension_size, Connection_Side from) { if(from == Connection_Side::SERVER) { if(extension_size != 2) throw Decoding_Error("Server sent invalid supported_versions extension"); m_versions.push_back(Protocol_Version(reader.get_uint16_t())); } else { auto versions = reader.get_range(1, 1, 127); for(auto v : versions) m_versions.push_back(Protocol_Version(v)); if(extension_size != 1+2*versions.size()) throw Decoding_Error("Client sent invalid supported_versions extension"); } } bool Supported_Versions::supports(Protocol_Version version) const { for(auto v : m_versions) if(version == v) return true; return false; } } } /* * TLS Handshake Hash * (C) 2004-2006,2011,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { /** * Return a TLS Handshake Hash */ secure_vector Handshake_Hash::final(Protocol_Version version, const std::string& mac_algo) const { std::string hash_algo = mac_algo; if(!version.supports_ciphersuite_specific_prf()) hash_algo = "Parallel(MD5,SHA-160)"; else if(mac_algo == "MD5" || mac_algo == "SHA-1") hash_algo = "SHA-256"; std::unique_ptr hash(HashFunction::create_or_throw(hash_algo)); hash->update(m_data); return hash->final(); } } } /* * TLS Handshake IO * (C) 2012,2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { namespace { inline size_t load_be24(const uint8_t q[3]) { return make_uint32(0, q[0], q[1], q[2]); } void store_be24(uint8_t out[3], size_t val) { out[0] = get_byte(1, static_cast(val)); out[1] = get_byte(2, static_cast(val)); out[2] = get_byte(3, static_cast(val)); } uint64_t steady_clock_ms() { return std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()).count(); } } Protocol_Version Stream_Handshake_IO::initial_record_version() const { return Protocol_Version::TLS_V10; } void Stream_Handshake_IO::add_record(const uint8_t record[], size_t record_len, Record_Type record_type, uint64_t) { if(record_type == HANDSHAKE) { m_queue.insert(m_queue.end(), record, record + record_len); } else if(record_type == CHANGE_CIPHER_SPEC) { if(record_len != 1 || record[0] != 1) throw Decoding_Error("Invalid ChangeCipherSpec"); // Pretend it's a regular handshake message of zero length const uint8_t ccs_hs[] = { HANDSHAKE_CCS, 0, 0, 0 }; m_queue.insert(m_queue.end(), ccs_hs, ccs_hs + sizeof(ccs_hs)); } else throw Decoding_Error("Unknown message type " + std::to_string(record_type) + " in handshake processing"); } std::pair> Stream_Handshake_IO::get_next_record(bool) { if(m_queue.size() >= 4) { const size_t length = 4 + make_uint32(0, m_queue[1], m_queue[2], m_queue[3]); if(m_queue.size() >= length) { Handshake_Type type = static_cast(m_queue[0]); if(type == HANDSHAKE_NONE) throw Decoding_Error("Invalid handshake message type"); std::vector contents(m_queue.begin() + 4, m_queue.begin() + length); m_queue.erase(m_queue.begin(), m_queue.begin() + length); return std::make_pair(type, contents); } } return std::make_pair(HANDSHAKE_NONE, std::vector()); } std::vector Stream_Handshake_IO::format(const std::vector& msg, Handshake_Type type) const { std::vector send_buf(4 + msg.size()); const size_t buf_size = msg.size(); send_buf[0] = static_cast(type); store_be24(&send_buf[1], buf_size); if (msg.size() > 0) { copy_mem(&send_buf[4], msg.data(), msg.size()); } return send_buf; } std::vector Stream_Handshake_IO::send_under_epoch(const Handshake_Message& /*msg*/, uint16_t /*epoch*/) { throw Invalid_State("Not possible to send under arbitrary epoch with stream based TLS"); } std::vector Stream_Handshake_IO::send(const Handshake_Message& msg) { const std::vector msg_bits = msg.serialize(); if(msg.type() == HANDSHAKE_CCS) { m_send_hs(CHANGE_CIPHER_SPEC, msg_bits); return std::vector(); // not included in handshake hashes } const std::vector buf = format(msg_bits, msg.type()); m_send_hs(HANDSHAKE, buf); return buf; } Protocol_Version Datagram_Handshake_IO::initial_record_version() const { return Protocol_Version::DTLS_V10; } void Datagram_Handshake_IO::retransmit_last_flight() { const size_t flight_idx = (m_flights.size() == 1) ? 0 : (m_flights.size() - 2); retransmit_flight(flight_idx); } void Datagram_Handshake_IO::retransmit_flight(size_t flight_idx) { const std::vector& flight = m_flights.at(flight_idx); BOTAN_ASSERT(flight.size() > 0, "Nonempty flight to retransmit"); uint16_t epoch = m_flight_data[flight[0]].epoch; for(auto msg_seq : flight) { auto& msg = m_flight_data[msg_seq]; if(msg.epoch != epoch) { // Epoch gap: insert the CCS std::vector ccs(1, 1); m_send_hs(epoch, CHANGE_CIPHER_SPEC, ccs); } send_message(msg_seq, msg.epoch, msg.msg_type, msg.msg_bits); epoch = msg.epoch; } } bool Datagram_Handshake_IO::timeout_check() { if(m_last_write == 0 || (m_flights.size() > 1 && !m_flights.rbegin()->empty())) { /* If we haven't written anything yet obviously no timeout. Also no timeout possible if we are mid-flight, */ return false; } const uint64_t ms_since_write = steady_clock_ms() - m_last_write; if(ms_since_write < m_next_timeout) return false; retransmit_last_flight(); m_next_timeout = std::min(2 * m_next_timeout, m_max_timeout); return true; } void Datagram_Handshake_IO::add_record(const uint8_t record[], size_t record_len, Record_Type record_type, uint64_t record_sequence) { const uint16_t epoch = static_cast(record_sequence >> 48); if(record_type == CHANGE_CIPHER_SPEC) { if(record_len != 1 || record[0] != 1) throw Decoding_Error("Invalid ChangeCipherSpec"); // TODO: check this is otherwise empty m_ccs_epochs.insert(epoch); return; } const size_t DTLS_HANDSHAKE_HEADER_LEN = 12; while(record_len) { if(record_len < DTLS_HANDSHAKE_HEADER_LEN) return; // completely bogus? at least degenerate/weird const uint8_t msg_type = record[0]; const size_t msg_len = load_be24(&record[1]); const uint16_t message_seq = load_be(&record[4], 0); const size_t fragment_offset = load_be24(&record[6]); const size_t fragment_length = load_be24(&record[9]); const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length; if(record_len < total_size) throw Decoding_Error("Bad lengths in DTLS header"); if(message_seq >= m_in_message_seq) { m_messages[message_seq].add_fragment(&record[DTLS_HANDSHAKE_HEADER_LEN], fragment_length, fragment_offset, epoch, msg_type, msg_len); } else { // TODO: detect retransmitted flight } record += total_size; record_len -= total_size; } } std::pair> Datagram_Handshake_IO::get_next_record(bool expecting_ccs) { // Expecting a message means the last flight is concluded if(!m_flights.rbegin()->empty()) m_flights.push_back(std::vector()); if(expecting_ccs) { if(!m_messages.empty()) { const uint16_t current_epoch = m_messages.begin()->second.epoch(); if(m_ccs_epochs.count(current_epoch)) return std::make_pair(HANDSHAKE_CCS, std::vector()); } return std::make_pair(HANDSHAKE_NONE, std::vector()); } auto i = m_messages.find(m_in_message_seq); if(i == m_messages.end() || !i->second.complete()) { return std::make_pair(HANDSHAKE_NONE, std::vector()); } m_in_message_seq += 1; return i->second.message(); } void Datagram_Handshake_IO::Handshake_Reassembly::add_fragment( const uint8_t fragment[], size_t fragment_length, size_t fragment_offset, uint16_t epoch, uint8_t msg_type, size_t msg_length) { if(complete()) return; // already have entire message, ignore this if(m_msg_type == HANDSHAKE_NONE) { m_epoch = epoch; m_msg_type = msg_type; m_msg_length = msg_length; } if(msg_type != m_msg_type || msg_length != m_msg_length || epoch != m_epoch) throw Decoding_Error("Inconsistent values in fragmented DTLS handshake header"); if(fragment_offset > m_msg_length) throw Decoding_Error("Fragment offset past end of message"); if(fragment_offset + fragment_length > m_msg_length) throw Decoding_Error("Fragment overlaps past end of message"); if(fragment_offset == 0 && fragment_length == m_msg_length) { m_fragments.clear(); m_message.assign(fragment, fragment+fragment_length); } else { /* * FIXME. This is a pretty lame way to do defragmentation, huge * overhead with a tree node per byte. * * Also should confirm that all overlaps have no changes, * otherwise we expose ourselves to the classic fingerprinting * and IDS evasion attacks on IP fragmentation. */ for(size_t i = 0; i != fragment_length; ++i) m_fragments[fragment_offset+i] = fragment[i]; if(m_fragments.size() == m_msg_length) { m_message.resize(m_msg_length); for(size_t i = 0; i != m_msg_length; ++i) m_message[i] = m_fragments[i]; m_fragments.clear(); } } } bool Datagram_Handshake_IO::Handshake_Reassembly::complete() const { return (m_msg_type != HANDSHAKE_NONE && m_message.size() == m_msg_length); } std::pair> Datagram_Handshake_IO::Handshake_Reassembly::message() const { if(!complete()) throw Internal_Error("Datagram_Handshake_IO - message not complete"); return std::make_pair(static_cast(m_msg_type), m_message); } std::vector Datagram_Handshake_IO::format_fragment(const uint8_t fragment[], size_t frag_len, uint16_t frag_offset, uint16_t msg_len, Handshake_Type type, uint16_t msg_sequence) const { std::vector send_buf(12 + frag_len); send_buf[0] = static_cast(type); store_be24(&send_buf[1], msg_len); store_be(msg_sequence, &send_buf[4]); store_be24(&send_buf[6], frag_offset); store_be24(&send_buf[9], frag_len); if (frag_len > 0) { copy_mem(&send_buf[12], fragment, frag_len); } return send_buf; } std::vector Datagram_Handshake_IO::format_w_seq(const std::vector& msg, Handshake_Type type, uint16_t msg_sequence) const { return format_fragment(msg.data(), msg.size(), 0, static_cast(msg.size()), type, msg_sequence); } std::vector Datagram_Handshake_IO::format(const std::vector& msg, Handshake_Type type) const { return format_w_seq(msg, type, m_in_message_seq - 1); } std::vector Datagram_Handshake_IO::send(const Handshake_Message& msg) { return this->send_under_epoch(msg, m_seqs.current_write_epoch()); } std::vector Datagram_Handshake_IO::send_under_epoch(const Handshake_Message& msg, uint16_t epoch) { const std::vector msg_bits = msg.serialize(); const Handshake_Type msg_type = msg.type(); if(msg_type == HANDSHAKE_CCS) { m_send_hs(epoch, CHANGE_CIPHER_SPEC, msg_bits); return std::vector(); // not included in handshake hashes } else if(msg_type == HELLO_VERIFY_REQUEST) { // This message is not included in the handshake hashes send_message(m_out_message_seq, epoch, msg_type, msg_bits); m_out_message_seq += 1; return std::vector(); } // Note: not saving CCS, instead we know it was there due to change in epoch m_flights.rbegin()->push_back(m_out_message_seq); m_flight_data[m_out_message_seq] = Message_Info(epoch, msg_type, msg_bits); m_out_message_seq += 1; m_last_write = steady_clock_ms(); m_next_timeout = m_initial_timeout; return send_message(m_out_message_seq - 1, epoch, msg_type, msg_bits); } std::vector Datagram_Handshake_IO::send_message(uint16_t msg_seq, uint16_t epoch, Handshake_Type msg_type, const std::vector& msg_bits) { const size_t DTLS_HANDSHAKE_HEADER_LEN = 12; const std::vector no_fragment = format_w_seq(msg_bits, msg_type, msg_seq); if(no_fragment.size() + DTLS_HEADER_SIZE <= m_mtu) { m_send_hs(epoch, HANDSHAKE, no_fragment); } else { size_t frag_offset = 0; /** * Largest possible overhead is for SHA-384 CBC ciphers, with 16 byte IV, * 16+ for padding and 48 bytes for MAC. 128 is probably a strict * over-estimate here. When CBC ciphers are removed this can be reduced * since AEAD modes have no padding, at most 16 byte mac, and smaller * per-record nonce. */ const size_t ciphersuite_overhead = (epoch > 0) ? 128 : 0; const size_t header_overhead = DTLS_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_LEN; if(m_mtu <= (header_overhead + ciphersuite_overhead)) throw Invalid_Argument("DTLS MTU is too small to send headers"); const size_t max_rec_size = m_mtu - (header_overhead + ciphersuite_overhead); while(frag_offset != msg_bits.size()) { const size_t frag_len = std::min(msg_bits.size() - frag_offset, max_rec_size); const std::vector frag = format_fragment(&msg_bits[frag_offset], frag_len, static_cast(frag_offset), static_cast(msg_bits.size()), msg_type, msg_seq); m_send_hs(epoch, HANDSHAKE, frag); frag_offset += frag_len; } } return no_fragment; } } } /* * TLS Handshaking * (C) 2004-2006,2011,2012,2015,2016 Jack Lloyd * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { std::string Handshake_Message::type_string() const { return handshake_type_to_string(type()); } const char* handshake_type_to_string(Handshake_Type type) { switch(type) { case HELLO_VERIFY_REQUEST: return "hello_verify_request"; case HELLO_REQUEST: return "hello_request"; case CLIENT_HELLO: return "client_hello"; case SERVER_HELLO: return "server_hello"; case CERTIFICATE: return "certificate"; case CERTIFICATE_URL: return "certificate_url"; case CERTIFICATE_STATUS: return "certificate_status"; case SERVER_KEX: return "server_key_exchange"; case CERTIFICATE_REQUEST: return "certificate_request"; case SERVER_HELLO_DONE: return "server_hello_done"; case CERTIFICATE_VERIFY: return "certificate_verify"; case CLIENT_KEX: return "client_key_exchange"; case NEW_SESSION_TICKET: return "new_session_ticket"; case HANDSHAKE_CCS: return "change_cipher_spec"; case FINISHED: return "finished"; case HANDSHAKE_NONE: return "invalid"; } throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Unknown TLS handshake message type " + std::to_string(type)); } namespace { uint32_t bitmask_for_handshake_type(Handshake_Type type) { switch(type) { case HELLO_VERIFY_REQUEST: return (1 << 0); case HELLO_REQUEST: return (1 << 1); case CLIENT_HELLO: return (1 << 2); case SERVER_HELLO: return (1 << 3); case CERTIFICATE: return (1 << 4); case CERTIFICATE_URL: return (1 << 5); case CERTIFICATE_STATUS: return (1 << 6); case SERVER_KEX: return (1 << 7); case CERTIFICATE_REQUEST: return (1 << 8); case SERVER_HELLO_DONE: return (1 << 9); case CERTIFICATE_VERIFY: return (1 << 10); case CLIENT_KEX: return (1 << 11); case NEW_SESSION_TICKET: return (1 << 12); case HANDSHAKE_CCS: return (1 << 13); case FINISHED: return (1 << 14); // allow explicitly disabling new handshakes case HANDSHAKE_NONE: return 0; } throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Unknown TLS handshake message type " + std::to_string(type)); } std::string handshake_mask_to_string(uint32_t mask, char combiner) { const Handshake_Type types[] = { HELLO_VERIFY_REQUEST, HELLO_REQUEST, CLIENT_HELLO, SERVER_HELLO, CERTIFICATE, CERTIFICATE_URL, CERTIFICATE_STATUS, SERVER_KEX, CERTIFICATE_REQUEST, SERVER_HELLO_DONE, CERTIFICATE_VERIFY, CLIENT_KEX, NEW_SESSION_TICKET, HANDSHAKE_CCS, FINISHED }; std::ostringstream o; bool empty = true; for(auto&& t : types) { if(mask & bitmask_for_handshake_type(t)) { if(!empty) o << combiner; o << handshake_type_to_string(t); empty = false; } } return o.str(); } } /* * Initialize the SSL/TLS Handshake State */ Handshake_State::Handshake_State(Handshake_IO* io, Callbacks& cb) : m_callbacks(cb), m_handshake_io(io), m_version(m_handshake_io->initial_record_version()) { } void Handshake_State::note_message(const Handshake_Message& msg) { m_callbacks.tls_inspect_handshake_msg(msg); } void Handshake_State::hello_verify_request(const Hello_Verify_Request& hello_verify) { note_message(hello_verify); m_client_hello->update_hello_cookie(hello_verify); hash().reset(); hash().update(handshake_io().send(*m_client_hello)); note_message(*m_client_hello); } void Handshake_State::client_hello(Client_Hello* client_hello) { if(client_hello == nullptr) { m_client_hello.reset(); hash().reset(); } else { m_client_hello.reset(client_hello); note_message(*m_client_hello); } } void Handshake_State::server_hello(Server_Hello* server_hello) { m_server_hello.reset(server_hello); m_ciphersuite = Ciphersuite::by_id(m_server_hello->ciphersuite()); note_message(*m_server_hello); } void Handshake_State::server_certs(Certificate* server_certs) { m_server_certs.reset(server_certs); note_message(*m_server_certs); } void Handshake_State::server_cert_status(Certificate_Status* server_cert_status) { m_server_cert_status.reset(server_cert_status); note_message(*m_server_cert_status); } void Handshake_State::server_kex(Server_Key_Exchange* server_kex) { m_server_kex.reset(server_kex); note_message(*m_server_kex); } void Handshake_State::cert_req(Certificate_Req* cert_req) { m_cert_req.reset(cert_req); note_message(*m_cert_req); } void Handshake_State::server_hello_done(Server_Hello_Done* server_hello_done) { m_server_hello_done.reset(server_hello_done); note_message(*m_server_hello_done); } void Handshake_State::client_certs(Certificate* client_certs) { m_client_certs.reset(client_certs); note_message(*m_client_certs); } void Handshake_State::client_kex(Client_Key_Exchange* client_kex) { m_client_kex.reset(client_kex); note_message(*m_client_kex); } void Handshake_State::client_verify(Certificate_Verify* client_verify) { m_client_verify.reset(client_verify); note_message(*m_client_verify); } void Handshake_State::new_session_ticket(New_Session_Ticket* new_session_ticket) { m_new_session_ticket.reset(new_session_ticket); note_message(*m_new_session_ticket); } void Handshake_State::server_finished(Finished* server_finished) { m_server_finished.reset(server_finished); note_message(*m_server_finished); } void Handshake_State::client_finished(Finished* client_finished) { m_client_finished.reset(client_finished); note_message(*m_client_finished); } void Handshake_State::set_version(const Protocol_Version& version) { m_version = version; } void Handshake_State::compute_session_keys() { m_session_keys = Session_Keys(this, client_kex()->pre_master_secret(), false); } void Handshake_State::compute_session_keys(const secure_vector& resume_master_secret) { m_session_keys = Session_Keys(this, resume_master_secret, true); } void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg) { const uint32_t mask = bitmask_for_handshake_type(handshake_msg); m_hand_received_mask |= mask; const bool ok = (m_hand_expecting_mask & mask) != 0; // overlap? if(!ok) { const uint32_t seen_so_far = m_hand_received_mask & ~mask; std::ostringstream msg; msg << "Unexpected state transition in handshake got a " << handshake_type_to_string(handshake_msg); if(m_hand_expecting_mask == 0) msg << " not expecting messages"; else msg << " expected " << handshake_mask_to_string(m_hand_expecting_mask, '|'); if(seen_so_far != 0) msg << " seen " << handshake_mask_to_string(seen_so_far, '+'); throw Unexpected_Message(msg.str()); } /* We don't know what to expect next, so force a call to set_expected_next; if it doesn't happen, the next transition check will always fail which is what we want. */ m_hand_expecting_mask = 0; } void Handshake_State::set_expected_next(Handshake_Type handshake_msg) { m_hand_expecting_mask |= bitmask_for_handshake_type(handshake_msg); } bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const { const uint32_t mask = bitmask_for_handshake_type(handshake_msg); return (m_hand_received_mask & mask) != 0; } std::pair> Handshake_State::get_next_handshake_msg() { const bool expecting_ccs = (bitmask_for_handshake_type(HANDSHAKE_CCS) & m_hand_expecting_mask) != 0; return m_handshake_io->get_next_record(expecting_ccs); } std::string Handshake_State::srp_identifier() const { #if defined(BOTAN_HAS_SRP6) // Authenticated via the successful key exchange if(ciphersuite().valid() && ciphersuite().kex_method() == Kex_Algo::SRP_SHA) return client_hello()->srp_identifier(); #endif return ""; } std::vector Handshake_State::session_ticket() const { if(new_session_ticket() && !new_session_ticket()->ticket().empty()) return new_session_ticket()->ticket(); return client_hello()->session_ticket(); } KDF* Handshake_State::protocol_specific_prf() const { if(version().supports_ciphersuite_specific_prf()) { const std::string prf_algo = ciphersuite().prf_algo(); if(prf_algo == "MD5" || prf_algo == "SHA-1") return get_kdf("TLS-12-PRF(SHA-256)"); return get_kdf("TLS-12-PRF(" + prf_algo + ")"); } // Old PRF used in TLS v1.0, v1.1 and DTLS v1.0 return get_kdf("TLS-PRF"); } std::pair Handshake_State::choose_sig_format(const Private_Key& key, Signature_Scheme& chosen_scheme, bool for_client_auth, const Policy& policy) const { const std::string sig_algo = key.algo_name(); if(this->version().supports_negotiable_signature_algorithms()) { const std::vector allowed = policy.allowed_signature_schemes(); std::vector requested = (for_client_auth) ? cert_req()->signature_schemes() : client_hello()->signature_schemes(); if(requested.empty()) { // Implicit SHA-1 requested.push_back(Signature_Scheme::RSA_PKCS1_SHA1); requested.push_back(Signature_Scheme::ECDSA_SHA1); requested.push_back(Signature_Scheme::DSA_SHA1); } for(Signature_Scheme scheme : allowed) { if(signature_scheme_is_known(scheme) == false) { continue; } if(signature_algorithm_of_scheme(scheme) == sig_algo) { if(std::find(requested.begin(), requested.end(), scheme) != requested.end()) { chosen_scheme = scheme; break; } } } const std::string hash = hash_function_of_scheme(chosen_scheme); if(!policy.allowed_signature_hash(hash)) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy refuses to accept signing with any hash supported by peer"); } if(sig_algo == "RSA") { return std::make_pair(padding_string_for_scheme(chosen_scheme), IEEE_1363); } else if(sig_algo == "DSA" || sig_algo == "ECDSA") { return std::make_pair(padding_string_for_scheme(chosen_scheme), DER_SEQUENCE); } } else { if(sig_algo == "RSA") { const std::string padding = "PKCS1v15(Parallel(MD5,SHA-160))"; return std::make_pair(padding, IEEE_1363); } else if(sig_algo == "DSA" || sig_algo == "ECDSA") { const std::string padding = "EMSA1(SHA-1)"; return std::make_pair(padding, DER_SEQUENCE); } } throw Invalid_Argument(sig_algo + " is invalid/unknown for TLS signatures"); } namespace { bool supported_algos_include( const std::vector& schemes, const std::string& key_type, const std::string& hash_type) { for(Signature_Scheme scheme : schemes) { if(signature_scheme_is_known(scheme) && hash_function_of_scheme(scheme) == hash_type && signature_algorithm_of_scheme(scheme) == key_type) { return true; } } return false; } } std::pair Handshake_State::parse_sig_format(const Public_Key& key, Signature_Scheme scheme, bool for_client_auth, const Policy& policy) const { const std::string key_type = key.algo_name(); if(!policy.allowed_signature_method(key_type)) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Rejecting " + key_type + " signature"); } if(this->version().supports_negotiable_signature_algorithms() == false) { if(scheme != Signature_Scheme::NONE) throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); /* There is no check on the acceptability of a v1.0/v1.1 hash type, since it's implicit with use of the protocol */ if(key_type == "RSA") { const std::string padding = "PKCS1v15(Parallel(MD5,SHA-160))"; return std::make_pair(padding, IEEE_1363); } else if(key_type == "DSA" || key_type == "ECDSA") { const std::string padding = "EMSA1(SHA-1)"; return std::make_pair(padding, DER_SEQUENCE); } else throw Invalid_Argument(key_type + " is invalid/unknown for TLS signatures"); } if(scheme == Signature_Scheme::NONE) throw Decoding_Error("Counterparty did not send hash/sig IDS"); if(key_type != signature_algorithm_of_scheme(scheme)) throw Decoding_Error("Counterparty sent inconsistent key and sig types"); if(for_client_auth && !cert_req()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "No certificate verify set"); } /* Confirm the signature type we just received against the supported_algos list that we sent; it better be there. */ const std::vector supported_algos = for_client_auth ? cert_req()->signature_schemes() : client_hello()->signature_schemes(); if(!signature_scheme_is_known(scheme)) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Peer sent unknown signature scheme"); const std::string hash_algo = hash_function_of_scheme(scheme); if(!supported_algos_include(supported_algos, key_type, hash_algo)) { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "TLS signature extension did not allow for " + key_type + "/" + hash_algo + " signature"); } if(key_type == "RSA") { return std::make_pair(padding_string_for_scheme(scheme), IEEE_1363); } else if(key_type == "DSA" || key_type == "ECDSA") { return std::make_pair(padding_string_for_scheme(scheme), DER_SEQUENCE); } throw Invalid_Argument(key_type + " is invalid/unknown for TLS signatures"); } } } /* * Policies for TLS * (C) 2004-2010,2012,2015,2016 Jack Lloyd * 2016 Christian Mainka * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { std::vector Policy::allowed_signature_schemes() const { std::vector schemes; for(Signature_Scheme scheme : all_signature_schemes()) { if(signature_scheme_is_known(scheme) == false) continue; const bool sig_allowed = allowed_signature_method(signature_algorithm_of_scheme(scheme)); const bool hash_allowed = allowed_signature_hash(hash_function_of_scheme(scheme)); if(sig_allowed && hash_allowed) { schemes.push_back(scheme); } } return schemes; } std::vector Policy::allowed_ciphers() const { return { //"AES-256/OCB(12)", //"AES-128/OCB(12)", "ChaCha20Poly1305", "AES-256/GCM", "AES-128/GCM", //"AES-256/CCM", //"AES-128/CCM", //"AES-256/CCM(8)", //"AES-128/CCM(8)", //"Camellia-256/GCM", //"Camellia-128/GCM", //"ARIA-256/GCM", //"ARIA-128/GCM", //"AES-256", //"AES-128", //"Camellia-256", //"Camellia-128", //"SEED", //"3DES", }; } std::vector Policy::allowed_signature_hashes() const { return { "SHA-512", "SHA-384", "SHA-256", //"SHA-1", }; } std::vector Policy::allowed_macs() const { /* SHA-256 is preferred because the Lucky13 countermeasure works somewhat better for SHA-256 vs SHA-384: https://github.com/randombit/botan/pull/675 */ return { "AEAD", "SHA-256", "SHA-384", "SHA-1", }; } std::vector Policy::allowed_key_exchange_methods() const { return { //"SRP_SHA", //"ECDHE_PSK", //"DHE_PSK", //"PSK", "CECPQ1", "ECDH", "DH", //"RSA", }; } std::vector Policy::allowed_signature_methods() const { return { "ECDSA", "RSA", //"DSA", //"IMPLICIT", //"ANONYMOUS" (anon) }; } bool Policy::allowed_signature_method(const std::string& sig_method) const { return value_exists(allowed_signature_methods(), sig_method); } bool Policy::allowed_signature_hash(const std::string& sig_hash) const { return value_exists(allowed_signature_hashes(), sig_hash); } bool Policy::use_ecc_point_compression() const { return false; } Group_Params Policy::choose_key_exchange_group(const std::vector& peer_groups) const { if(peer_groups.empty()) return Group_Params::NONE; const std::vector our_groups = key_exchange_groups(); for(auto g : our_groups) { if(value_exists(peer_groups, g)) return g; } return Group_Params::NONE; } Group_Params Policy::default_dh_group() const { /* * Return the first listed or just default to 2048 */ for(auto g : key_exchange_groups()) { if(group_param_is_dh(g)) return g; } return Group_Params::FFDHE_2048; } std::vector Policy::key_exchange_groups() const { // Default list is ordered by performance return { #if defined(BOTAN_HAS_CURVE_25519) Group_Params::X25519, #endif Group_Params::SECP256R1, Group_Params::BRAINPOOL256R1, Group_Params::SECP384R1, Group_Params::BRAINPOOL384R1, Group_Params::SECP521R1, Group_Params::BRAINPOOL512R1, Group_Params::FFDHE_2048, Group_Params::FFDHE_3072, Group_Params::FFDHE_4096, Group_Params::FFDHE_6144, Group_Params::FFDHE_8192, }; } size_t Policy::minimum_dh_group_size() const { return 2048; } size_t Policy::minimum_ecdsa_group_size() const { // Here we are at the mercy of whatever the CA signed, but most certs should be 256 bit by now return 256; } size_t Policy::minimum_ecdh_group_size() const { // x25519 is smallest curve currently supported for TLS key exchange return 255; } size_t Policy::minimum_signature_strength() const { return 110; } bool Policy::require_cert_revocation_info() const { return true; } size_t Policy::minimum_rsa_bits() const { /* Default assumption is all end-entity certificates should be at least 2048 bits these days. If you are connecting to arbitrary servers on the Internet (ie as a web browser or SMTP client) you'll probably have to reduce this to 1024 bits, or perhaps even lower. */ return 2048; } size_t Policy::minimum_dsa_group_size() const { // FIPS 186-3 return 2048; } void Policy::check_peer_key_acceptable(const Public_Key& public_key) const { const std::string algo_name = public_key.algo_name(); const size_t keylength = public_key.key_length(); size_t expected_keylength = 0; if(algo_name == "RSA") { expected_keylength = minimum_rsa_bits(); } else if(algo_name == "DH") { expected_keylength = minimum_dh_group_size(); } else if(algo_name == "DSA") { expected_keylength = minimum_dsa_group_size(); } else if(algo_name == "ECDH" || algo_name == "Curve25519") { expected_keylength = minimum_ecdh_group_size(); } else if(algo_name == "ECDSA") { expected_keylength = minimum_ecdsa_group_size(); } // else some other algo, so leave expected_keylength as zero and the check is a no-op if(keylength < expected_keylength) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "Peer sent " + std::to_string(keylength) + " bit " + algo_name + " key" ", policy requires at least " + std::to_string(expected_keylength)); } uint32_t Policy::session_ticket_lifetime() const { return 86400; // ~1 day } bool Policy::send_fallback_scsv(Protocol_Version version) const { return version != latest_supported_version(version.is_datagram_protocol()); } bool Policy::acceptable_protocol_version(Protocol_Version version) const { if(version == Protocol_Version::TLS_V12 && allow_tls12()) return true; if(version == Protocol_Version::DTLS_V12 && allow_dtls12()) return true; #if defined(BOTAN_HAS_TLS_V10) if(version == Protocol_Version::TLS_V11 && allow_tls11()) return true; if(version == Protocol_Version::TLS_V10 && allow_tls10()) return true; if(version == Protocol_Version::DTLS_V10 && allow_dtls10()) return true; #endif return false; } Protocol_Version Policy::latest_supported_version(bool datagram) const { if(datagram) { if(acceptable_protocol_version(Protocol_Version::DTLS_V12)) return Protocol_Version::DTLS_V12; #if defined(BOTAN_HAS_TLS_V10) if(acceptable_protocol_version(Protocol_Version::DTLS_V10)) return Protocol_Version::DTLS_V10; #endif throw Invalid_State("Policy forbids all available DTLS version"); } else { if(acceptable_protocol_version(Protocol_Version::TLS_V12)) return Protocol_Version::TLS_V12; #if defined(BOTAN_HAS_TLS_V10) if(acceptable_protocol_version(Protocol_Version::TLS_V11)) return Protocol_Version::TLS_V11; if(acceptable_protocol_version(Protocol_Version::TLS_V10)) return Protocol_Version::TLS_V10; #endif throw Invalid_State("Policy forbids all available TLS version"); } } bool Policy::acceptable_ciphersuite(const Ciphersuite& ciphersuite) const { return value_exists(allowed_ciphers(), ciphersuite.cipher_algo()) && value_exists(allowed_macs(), ciphersuite.mac_algo()); } bool Policy::allow_client_initiated_renegotiation() const { return false; } bool Policy::allow_server_initiated_renegotiation() const { return false; } bool Policy::allow_insecure_renegotiation() const { return false; } bool Policy::allow_tls10() const { return false; } bool Policy::allow_tls11() const { return false; } bool Policy::allow_tls12() const { return true; } bool Policy::allow_dtls10() const { return false; } bool Policy::allow_dtls12() const { return true; } bool Policy::include_time_in_hello_random() const { return true; } bool Policy::hide_unknown_users() const { return false; } bool Policy::server_uses_own_ciphersuite_preferences() const { return true; } bool Policy::negotiate_encrypt_then_mac() const { return true; } bool Policy::support_cert_status_message() const { return true; } bool Policy::allow_resumption_for_renegotiation() const { return true; } bool Policy::only_resume_with_exact_version() const { return true; } bool Policy::require_client_certificate_authentication() const { return false; } bool Policy::request_client_certificate_authentication() const { return require_client_certificate_authentication(); } bool Policy::abort_connection_on_undesired_renegotiation() const { return false; } bool Policy::allow_dtls_epoch0_restart() const { return false; } size_t Policy::maximum_certificate_chain_size() const { return 0; } // 1 second initial timeout, 60 second max - see RFC 6347 sec 4.2.4.1 size_t Policy::dtls_initial_timeout() const { return 1*1000; } size_t Policy::dtls_maximum_timeout() const { return 60*1000; } size_t Policy::dtls_default_mtu() const { // default MTU is IPv6 min MTU minus UDP/IP headers return 1280 - 40 - 8; } std::vector Policy::srtp_profiles() const { return std::vector(); } namespace { class Ciphersuite_Preference_Ordering final { public: Ciphersuite_Preference_Ordering(const std::vector& ciphers, const std::vector& macs, const std::vector& kex, const std::vector& sigs) : m_ciphers(ciphers), m_macs(macs), m_kex(kex), m_sigs(sigs) {} bool operator()(const Ciphersuite& a, const Ciphersuite& b) const { if(a.kex_method() != b.kex_method()) { for(size_t i = 0; i != m_kex.size(); ++i) { if(a.kex_algo() == m_kex[i]) return true; if(b.kex_algo() == m_kex[i]) return false; } } if(a.cipher_algo() != b.cipher_algo()) { for(size_t i = 0; i != m_ciphers.size(); ++i) { if(a.cipher_algo() == m_ciphers[i]) return true; if(b.cipher_algo() == m_ciphers[i]) return false; } } if(a.cipher_keylen() != b.cipher_keylen()) { if(a.cipher_keylen() < b.cipher_keylen()) return false; if(a.cipher_keylen() > b.cipher_keylen()) return true; } if(a.auth_method() != b.auth_method()) { for(size_t i = 0; i != m_sigs.size(); ++i) { if(a.sig_algo() == m_sigs[i]) return true; if(b.sig_algo() == m_sigs[i]) return false; } } if(a.mac_algo() != b.mac_algo()) { for(size_t i = 0; i != m_macs.size(); ++i) { if(a.mac_algo() == m_macs[i]) return true; if(b.mac_algo() == m_macs[i]) return false; } } return false; // equal (?!?) } private: std::vector m_ciphers, m_macs, m_kex, m_sigs; }; } std::vector Policy::ciphersuite_list(Protocol_Version version, bool have_srp) const { const std::vector ciphers = allowed_ciphers(); const std::vector macs = allowed_macs(); const std::vector kex = allowed_key_exchange_methods(); const std::vector sigs = allowed_signature_methods(); std::vector ciphersuites; for(auto&& suite : Ciphersuite::all_known_ciphersuites()) { // Can we use it? if(!suite.valid()) continue; // Can we use it in this version? if(!suite.usable_in_version(version)) continue; // Is it acceptable to the policy? if(!this->acceptable_ciphersuite(suite)) continue; // Are we doing SRP? if(!have_srp && suite.kex_method() == Kex_Algo::SRP_SHA) continue; if(!value_exists(kex, suite.kex_algo())) continue; // unsupported key exchange if(!value_exists(ciphers, suite.cipher_algo())) continue; // unsupported cipher if(!value_exists(macs, suite.mac_algo())) continue; // unsupported MAC algo if(!value_exists(sigs, suite.sig_algo())) { // allow if it's an empty sig algo and we want to use PSK if(suite.auth_method() != Auth_Method::IMPLICIT || !suite.psk_ciphersuite()) continue; } /* CECPQ1 always uses x25519 for ECDH, so treat the applications removal of x25519 from the ECC curve list as equivalent to saying they do not trust CECPQ1 */ if(suite.kex_method() == Kex_Algo::CECPQ1) { if(value_exists(key_exchange_groups(), Group_Params::X25519) == false) continue; } // OK, consider it ciphersuites.push_back(suite); } if(ciphersuites.empty()) { throw Invalid_State("Policy does not allow any available cipher suite"); } Ciphersuite_Preference_Ordering order(ciphers, macs, kex, sigs); std::sort(ciphersuites.begin(), ciphersuites.end(), order); std::vector ciphersuite_codes; for(auto i : ciphersuites) ciphersuite_codes.push_back(i.ciphersuite_code()); return ciphersuite_codes; } namespace { void print_vec(std::ostream& o, const char* key, const std::vector& v) { o << key << " = "; for(size_t i = 0; i != v.size(); ++i) { o << v[i]; if(i != v.size() - 1) o << ' '; } o << '\n'; } void print_vec(std::ostream& o, const char* key, const std::vector& v) { o << key << " = "; for(size_t i = 0; i != v.size(); ++i) { o << group_param_to_string(v[i]); if(i != v.size() - 1) o << ' '; } o << '\n'; } void print_bool(std::ostream& o, const char* key, bool b) { o << key << " = " << (b ? "true" : "false") << '\n'; } } void Policy::print(std::ostream& o) const { print_bool(o, "allow_tls10", allow_tls10()); print_bool(o, "allow_tls11", allow_tls11()); print_bool(o, "allow_tls12", allow_tls12()); print_bool(o, "allow_dtls10", allow_dtls10()); print_bool(o, "allow_dtls12", allow_dtls12()); print_vec(o, "ciphers", allowed_ciphers()); print_vec(o, "macs", allowed_macs()); print_vec(o, "signature_hashes", allowed_signature_hashes()); print_vec(o, "signature_methods", allowed_signature_methods()); print_vec(o, "key_exchange_methods", allowed_key_exchange_methods()); print_vec(o, "key_exchange_groups", key_exchange_groups()); print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation()); print_bool(o, "include_time_in_hello_random", include_time_in_hello_random()); print_bool(o, "allow_server_initiated_renegotiation", allow_server_initiated_renegotiation()); print_bool(o, "hide_unknown_users", hide_unknown_users()); print_bool(o, "server_uses_own_ciphersuite_preferences", server_uses_own_ciphersuite_preferences()); print_bool(o, "negotiate_encrypt_then_mac", negotiate_encrypt_then_mac()); print_bool(o, "support_cert_status_message", support_cert_status_message()); o << "session_ticket_lifetime = " << session_ticket_lifetime() << '\n'; o << "minimum_dh_group_size = " << minimum_dh_group_size() << '\n'; o << "minimum_ecdh_group_size = " << minimum_ecdh_group_size() << '\n'; o << "minimum_rsa_bits = " << minimum_rsa_bits() << '\n'; o << "minimum_signature_strength = " << minimum_signature_strength() << '\n'; } std::string Policy::to_string() const { std::ostringstream oss; this->print(oss); return oss.str(); } std::vector Strict_Policy::allowed_ciphers() const { return { "ChaCha20Poly1305", "AES-256/GCM", "AES-128/GCM" }; } std::vector Strict_Policy::allowed_signature_hashes() const { return { "SHA-512", "SHA-384"}; } std::vector Strict_Policy::allowed_macs() const { return { "AEAD" }; } std::vector Strict_Policy::allowed_key_exchange_methods() const { return { "CECPQ1", "ECDH" }; } bool Strict_Policy::allow_tls10() const { return false; } bool Strict_Policy::allow_tls11() const { return false; } bool Strict_Policy::allow_tls12() const { return true; } bool Strict_Policy::allow_dtls10() const { return false; } bool Strict_Policy::allow_dtls12() const { return true; } } } /* * TLS Record Handling * (C) 2012,2013,2014,2015,2016,2019 Jack Lloyd * 2016 Juraj Somorovsky * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_TLS_CBC) #endif namespace Botan { namespace TLS { Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, Connection_Side side, bool our_side, const Ciphersuite& suite, const Session_Keys& keys, bool uses_encrypt_then_mac) : m_start_time(std::chrono::system_clock::now()) { m_nonce_format = suite.nonce_format(); m_nonce_bytes_from_record = suite.nonce_bytes_from_record(version); m_nonce_bytes_from_handshake = suite.nonce_bytes_from_handshake(); const secure_vector& aead_key = keys.aead_key(side); m_nonce = keys.nonce(side); BOTAN_ASSERT_NOMSG(m_nonce.size() == m_nonce_bytes_from_handshake); if(nonce_format() == Nonce_Format::CBC_MODE) { #if defined(BOTAN_HAS_TLS_CBC) // legacy CBC+HMAC mode auto mac = MessageAuthenticationCode::create_or_throw("HMAC(" + suite.mac_algo() + ")"); auto cipher = BlockCipher::create_or_throw(suite.cipher_algo()); if(our_side) { m_aead.reset(new TLS_CBC_HMAC_AEAD_Encryption( std::move(cipher), std::move(mac), suite.cipher_keylen(), suite.mac_keylen(), version, uses_encrypt_then_mac)); } else { m_aead.reset(new TLS_CBC_HMAC_AEAD_Decryption( std::move(cipher), std::move(mac), suite.cipher_keylen(), suite.mac_keylen(), version, uses_encrypt_then_mac)); } #else BOTAN_UNUSED(uses_encrypt_then_mac); throw Internal_Error("Negotiated disabled TLS CBC+HMAC ciphersuite"); #endif } else { m_aead = AEAD_Mode::create_or_throw(suite.cipher_algo(), our_side ? ENCRYPTION : DECRYPTION); } m_aead->set_key(aead_key); } std::vector Connection_Cipher_State::aead_nonce(uint64_t seq, RandomNumberGenerator& rng) { switch(m_nonce_format) { case Nonce_Format::CBC_MODE: { if(m_nonce.size()) { std::vector nonce; nonce.swap(m_nonce); return nonce; } std::vector nonce(nonce_bytes_from_record()); rng.randomize(nonce.data(), nonce.size()); return nonce; } case Nonce_Format::AEAD_XOR_12: { std::vector nonce(12); store_be(seq, nonce.data() + 4); xor_buf(nonce, m_nonce.data(), m_nonce.size()); return nonce; } case Nonce_Format::AEAD_IMPLICIT_4: { BOTAN_ASSERT_NOMSG(m_nonce.size() == 4); std::vector nonce(12); copy_mem(&nonce[0], m_nonce.data(), 4); store_be(seq, &nonce[nonce_bytes_from_handshake()]); return nonce; } } throw Invalid_State("Unknown nonce format specified"); } std::vector Connection_Cipher_State::aead_nonce(const uint8_t record[], size_t record_len, uint64_t seq) { switch(m_nonce_format) { case Nonce_Format::CBC_MODE: { if(nonce_bytes_from_record() == 0 && m_nonce.size()) { std::vector nonce; nonce.swap(m_nonce); return nonce; } if(record_len < nonce_bytes_from_record()) throw Decoding_Error("Invalid CBC packet too short to be valid"); std::vector nonce(record, record + nonce_bytes_from_record()); return nonce; } case Nonce_Format::AEAD_XOR_12: { std::vector nonce(12); store_be(seq, nonce.data() + 4); xor_buf(nonce, m_nonce.data(), m_nonce.size()); return nonce; } case Nonce_Format::AEAD_IMPLICIT_4: { BOTAN_ASSERT_NOMSG(m_nonce.size() == 4); if(record_len < nonce_bytes_from_record()) throw Decoding_Error("Invalid AEAD packet too short to be valid"); std::vector nonce(12); copy_mem(&nonce[0], m_nonce.data(), 4); copy_mem(&nonce[nonce_bytes_from_handshake()], record, nonce_bytes_from_record()); return nonce; } } throw Invalid_State("Unknown nonce format specified"); } std::vector Connection_Cipher_State::format_ad(uint64_t msg_sequence, uint8_t msg_type, Protocol_Version version, uint16_t msg_length) { std::vector ad(13); store_be(msg_sequence, &ad[0]); ad[8] = msg_type; ad[9] = version.major_version(); ad[10] = version.minor_version(); ad[11] = get_byte(0, msg_length); ad[12] = get_byte(1, msg_length); return ad; } namespace { inline void append_u16_len(secure_vector& output, size_t len_field) { const uint16_t len16 = static_cast(len_field); BOTAN_ASSERT_EQUAL(len_field, len16, "No truncation"); output.push_back(get_byte(0, len16)); output.push_back(get_byte(1, len16)); } void write_record_header(secure_vector& output, uint8_t record_type, Protocol_Version version, uint64_t record_sequence) { output.clear(); output.push_back(record_type); output.push_back(version.major_version()); output.push_back(version.minor_version()); if(version.is_datagram_protocol()) { for(size_t i = 0; i != 8; ++i) output.push_back(get_byte(i, record_sequence)); } } } void write_unencrypted_record(secure_vector& output, uint8_t record_type, Protocol_Version version, uint64_t record_sequence, const uint8_t* message, size_t message_len) { if(record_type == APPLICATION_DATA) throw Internal_Error("Writing an unencrypted TLS application data record"); write_record_header(output, record_type, version, record_sequence); append_u16_len(output, message_len); output.insert(output.end(), message, message + message_len); } void write_record(secure_vector& output, uint8_t record_type, Protocol_Version version, uint64_t record_sequence, const uint8_t* message, size_t message_len, Connection_Cipher_State& cs, RandomNumberGenerator& rng) { write_record_header(output, record_type, version, record_sequence); AEAD_Mode& aead = cs.aead(); std::vector aad = cs.format_ad(record_sequence, record_type, version, static_cast(message_len)); const size_t ctext_size = aead.output_length(message_len); const size_t rec_size = ctext_size + cs.nonce_bytes_from_record(); aead.set_ad(aad); const std::vector nonce = cs.aead_nonce(record_sequence, rng); append_u16_len(output, rec_size); if(cs.nonce_bytes_from_record() > 0) { if(cs.nonce_format() == Nonce_Format::CBC_MODE) output += nonce; else output += std::make_pair(&nonce[cs.nonce_bytes_from_handshake()], cs.nonce_bytes_from_record()); } const size_t header_size = output.size(); output += std::make_pair(message, message_len); aead.start(nonce); aead.finish(output, header_size); BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE, "Produced ciphertext larger than protocol allows"); } namespace { size_t fill_buffer_to(secure_vector& readbuf, const uint8_t*& input, size_t& input_size, size_t& input_consumed, size_t desired) { if(readbuf.size() >= desired) return 0; // already have it const size_t taken = std::min(input_size, desired - readbuf.size()); readbuf.insert(readbuf.end(), input, input + taken); input_consumed += taken; input_size -= taken; input += taken; return (desired - readbuf.size()); // how many bytes do we still need? } void decrypt_record(secure_vector& output, uint8_t record_contents[], size_t record_len, uint64_t record_sequence, Protocol_Version record_version, Record_Type record_type, Connection_Cipher_State& cs) { AEAD_Mode& aead = cs.aead(); const std::vector nonce = cs.aead_nonce(record_contents, record_len, record_sequence); const uint8_t* msg = &record_contents[cs.nonce_bytes_from_record()]; const size_t msg_length = record_len - cs.nonce_bytes_from_record(); /* * This early rejection is based just on public information (length of the * encrypted packet) and so does not leak any information. We used to use * decode_error here which really is more appropriate, but that confuses some * tools which are attempting automated detection of padding oracles, * including older versions of TLS-Attacker. */ if(msg_length < aead.minimum_final_size()) throw TLS_Exception(Alert::BAD_RECORD_MAC, "AEAD packet is shorter than the tag"); const size_t ptext_size = aead.output_length(msg_length); aead.set_associated_data_vec( cs.format_ad(record_sequence, static_cast(record_type), record_version, static_cast(ptext_size)) ); aead.start(nonce); output.assign(msg, msg + msg_length); aead.finish(output, 0); } Record_Header read_tls_record(secure_vector& readbuf, const uint8_t input[], size_t input_len, size_t& consumed, secure_vector& recbuf, Connection_Sequence_Numbers* sequence_numbers, get_cipherstate_fn get_cipherstate) { if(readbuf.size() < TLS_HEADER_SIZE) // header incomplete? { if(size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE)) { return Record_Header(needed); } BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header"); } if(readbuf[1] != 3) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Got unexpected TLS record version"); } const Protocol_Version version(readbuf[1], readbuf[2]); const size_t record_size = make_uint16(readbuf[TLS_HEADER_SIZE-2], readbuf[TLS_HEADER_SIZE-1]); if(record_size > MAX_CIPHERTEXT_SIZE) throw TLS_Exception(Alert::RECORD_OVERFLOW, "Received a record that exceeds maximum size"); if(record_size == 0) throw TLS_Exception(Alert::DECODE_ERROR, "Received a completely empty record"); if(size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE + record_size)) { return Record_Header(needed); } BOTAN_ASSERT_EQUAL(static_cast(TLS_HEADER_SIZE) + record_size, readbuf.size(), "Have the full record"); const Record_Type type = static_cast(readbuf[0]); uint16_t epoch = 0; uint64_t sequence = 0; if(sequence_numbers) { sequence = sequence_numbers->next_read_sequence(); epoch = sequence_numbers->current_read_epoch(); } else { // server initial handshake case epoch = 0; } if(epoch == 0) // Unencrypted initial handshake { recbuf.assign(readbuf.begin() + TLS_HEADER_SIZE, readbuf.begin() + TLS_HEADER_SIZE + record_size); readbuf.clear(); return Record_Header(sequence, version, type); } // Otherwise, decrypt, check MAC, return plaintext auto cs = get_cipherstate(epoch); BOTAN_ASSERT(cs, "Have cipherstate for this epoch"); decrypt_record(recbuf, &readbuf[TLS_HEADER_SIZE], record_size, sequence, version, type, *cs); if(sequence_numbers) sequence_numbers->read_accept(sequence); readbuf.clear(); return Record_Header(sequence, version, type); } Record_Header read_dtls_record(secure_vector& readbuf, const uint8_t input[], size_t input_len, size_t& consumed, secure_vector& recbuf, Connection_Sequence_Numbers* sequence_numbers, get_cipherstate_fn get_cipherstate, bool allow_epoch0_restart) { if(readbuf.size() < DTLS_HEADER_SIZE) // header incomplete? { if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE)) { readbuf.clear(); return Record_Header(0); } BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, "Have an entire header"); } const Protocol_Version version(readbuf[1], readbuf[2]); if(version.is_datagram_protocol() == false) { readbuf.clear(); return Record_Header(0); } const size_t record_size = make_uint16(readbuf[DTLS_HEADER_SIZE-2], readbuf[DTLS_HEADER_SIZE-1]); if(record_size > MAX_CIPHERTEXT_SIZE) { // Too large to be valid, ignore it readbuf.clear(); return Record_Header(0); } if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE + record_size)) { // Truncated packet? readbuf.clear(); return Record_Header(0); } BOTAN_ASSERT_EQUAL(static_cast(DTLS_HEADER_SIZE) + record_size, readbuf.size(), "Have the full record"); const Record_Type type = static_cast(readbuf[0]); const uint64_t sequence = load_be(&readbuf[3], 0); const uint16_t epoch = (sequence >> 48); const bool already_seen = sequence_numbers && sequence_numbers->already_seen(sequence); if(already_seen && !(epoch == 0 && allow_epoch0_restart)) { readbuf.clear(); return Record_Header(0); } if(epoch == 0) // Unencrypted initial handshake { recbuf.assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_size); readbuf.clear(); if(sequence_numbers) sequence_numbers->read_accept(sequence); return Record_Header(sequence, version, type); } try { // Otherwise, decrypt, check MAC, return plaintext auto cs = get_cipherstate(epoch); BOTAN_ASSERT(cs, "Have cipherstate for this epoch"); decrypt_record(recbuf, &readbuf[DTLS_HEADER_SIZE], record_size, sequence, version, type, *cs); } catch(std::exception&) { readbuf.clear(); return Record_Header(0); } if(sequence_numbers) sequence_numbers->read_accept(sequence); readbuf.clear(); return Record_Header(sequence, version, type); } } Record_Header read_record(bool is_datagram, secure_vector& readbuf, const uint8_t input[], size_t input_len, size_t& consumed, secure_vector& recbuf, Connection_Sequence_Numbers* sequence_numbers, get_cipherstate_fn get_cipherstate, bool allow_epoch0_restart) { if(is_datagram) return read_dtls_record(readbuf, input, input_len, consumed, recbuf, sequence_numbers, get_cipherstate, allow_epoch0_restart); else return read_tls_record(readbuf, input, input_len, consumed, recbuf, sequence_numbers, get_cipherstate); } } } /* * TLS Server * (C) 2004-2011,2012,2016 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { class Server_Handshake_State final : public Handshake_State { public: Server_Handshake_State(Handshake_IO* io, Callbacks& cb) : Handshake_State(io, cb) {} Private_Key* server_rsa_kex_key() { return m_server_rsa_kex_key; } void set_server_rsa_kex_key(Private_Key* key) { m_server_rsa_kex_key = key; } bool allow_session_resumption() const { return m_allow_session_resumption; } void set_allow_session_resumption(bool allow_session_resumption) { m_allow_session_resumption = allow_session_resumption; } const std::vector& resume_peer_certs() const { return m_resume_peer_certs; } void set_resume_certs(const std::vector& certs) { m_resume_peer_certs = certs; } void mark_as_resumption() { m_is_a_resumption = true; } bool is_a_resumption() const { return m_is_a_resumption; } private: // Used by the server only, in case of RSA key exchange. Not owned Private_Key* m_server_rsa_kex_key = nullptr; /* * Used by the server to know if resumption should be allowed on * a server-initiated renegotiation */ bool m_allow_session_resumption = true; bool m_is_a_resumption = false; std::vector m_resume_peer_certs; }; namespace { bool check_for_resume(Session& session_info, Session_Manager& session_manager, Credentials_Manager& credentials, const Client_Hello* client_hello, std::chrono::seconds session_ticket_lifetime) { const std::vector& client_session_id = client_hello->session_id(); const std::vector& session_ticket = client_hello->session_ticket(); if(session_ticket.empty()) { if(client_session_id.empty()) // not resuming return false; // not found if(!session_manager.load_from_session_id(client_session_id, session_info)) return false; } else { // If a session ticket was sent, ignore client session ID try { session_info = Session::decrypt( session_ticket, credentials.psk("tls-server", "session-ticket", "")); if(session_ticket_lifetime != std::chrono::seconds(0) && session_info.session_age() > session_ticket_lifetime) return false; // ticket has expired } catch(...) { return false; } } // wrong version if(client_hello->version() != session_info.version()) return false; // client didn't send original ciphersuite if(!value_exists(client_hello->ciphersuites(), session_info.ciphersuite_code())) return false; #if defined(BOTAN_HAS_SRP6) // client sent a different SRP identity if(client_hello->srp_identifier() != "") { if(client_hello->srp_identifier() != session_info.srp_identifier()) return false; } #endif // client sent a different SNI hostname if(client_hello->sni_hostname() != "") { if(client_hello->sni_hostname() != session_info.server_info().hostname()) return false; } // Checking extended_master_secret on resume (RFC 7627 section 5.3) if(client_hello->supports_extended_master_secret() != session_info.supports_extended_master_secret()) { if(!session_info.supports_extended_master_secret()) { return false; // force new handshake with extended master secret } else { /* Client previously negotiated session with extended master secret, but has now attempted to resume without the extension: abort */ throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client resumed extended ms session without sending extension"); } } // Checking encrypt_then_mac on resume (RFC 7366 section 3.1) if(!client_hello->supports_encrypt_then_mac() && session_info.supports_encrypt_then_mac()) { /* Client previously negotiated session with Encrypt-then-MAC, but has now attempted to resume without the extension: abort */ throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client resumed Encrypt-then-MAC session without sending extension"); } return true; } /* * Choose which ciphersuite to use */ uint16_t choose_ciphersuite( const Policy& policy, Protocol_Version version, Credentials_Manager& creds, const std::map>& cert_chains, const Client_Hello& client_hello) { const bool our_choice = policy.server_uses_own_ciphersuite_preferences(); const bool have_srp = creds.attempt_srp("tls-server", client_hello.sni_hostname()); const std::vector client_suites = client_hello.ciphersuites(); const std::vector server_suites = policy.ciphersuite_list(version, have_srp); if(server_suites.empty()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy forbids us from negotiating any ciphersuite"); const bool have_shared_ecc_curve = (policy.choose_key_exchange_group(client_hello.supported_ecc_curves()) != Group_Params::NONE); /* Walk down one list in preference order */ std::vector pref_list = server_suites; std::vector other_list = client_suites; if(!our_choice) std::swap(pref_list, other_list); for(auto suite_id : pref_list) { if(!value_exists(other_list, suite_id)) continue; const Ciphersuite suite = Ciphersuite::by_id(suite_id); if(suite.valid() == false) { continue; } if(have_shared_ecc_curve == false && suite.ecc_ciphersuite()) { continue; } // For non-anon ciphersuites if(suite.signature_used()) { const std::string sig_algo = suite.sig_algo(); // Do we have any certificates for this sig? if(cert_chains.count(sig_algo) == 0) { continue; } if(version.supports_negotiable_signature_algorithms()) { const std::vector allowed = policy.allowed_signature_schemes(); std::vector client_sig_methods = client_hello.signature_schemes(); if(client_sig_methods.empty()) { // If empty, then implicit SHA-1 (TLS v1.2 rules) client_sig_methods.push_back(Signature_Scheme::RSA_PKCS1_SHA1); client_sig_methods.push_back(Signature_Scheme::ECDSA_SHA1); client_sig_methods.push_back(Signature_Scheme::DSA_SHA1); } bool we_support_some_hash_by_client = false; for(Signature_Scheme scheme : client_sig_methods) { if(signature_scheme_is_known(scheme) == false) continue; if(signature_algorithm_of_scheme(scheme) == suite.sig_algo() && policy.allowed_signature_hash(hash_function_of_scheme(scheme))) { we_support_some_hash_by_client = true; } } if(we_support_some_hash_by_client == false) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy does not accept any hash function supported by client"); } } } #if defined(BOTAN_HAS_SRP6) /* The client may offer SRP cipher suites in the hello message but omit the SRP extension. If the server would like to select an SRP cipher suite in this case, the server SHOULD return a fatal "unknown_psk_identity" alert immediately after processing the client hello message. - RFC 5054 section 2.5.1.2 */ if(suite.kex_method() == Kex_Algo::SRP_SHA && client_hello.srp_identifier() == "") throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, "Client wanted SRP but did not send username"); #endif return suite_id; } throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Can't agree on a ciphersuite with client"); } std::map> get_server_certs(const std::string& hostname, Credentials_Manager& creds) { const char* cert_types[] = { "RSA", "ECDSA", "DSA", nullptr }; std::map> cert_chains; for(size_t i = 0; cert_types[i]; ++i) { const std::vector certs = creds.cert_chain_single_type(cert_types[i], "tls-server", hostname); if(!certs.empty()) cert_chains[cert_types[i]] = certs; } return cert_chains; } } /* * TLS Server Constructor */ Server::Server(Callbacks& callbacks, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, bool is_datagram, size_t io_buf_sz) : Channel(callbacks, session_manager, rng, policy, true, is_datagram, io_buf_sz), m_creds(creds) { } Server::Server(output_fn output, data_cb got_data_cb, alert_cb recv_alert_cb, handshake_cb hs_cb, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, next_protocol_fn next_proto, bool is_datagram, size_t io_buf_sz) : Channel(output, got_data_cb, recv_alert_cb, hs_cb, Channel::handshake_msg_cb(), session_manager, rng, policy, true, is_datagram, io_buf_sz), m_creds(creds), m_choose_next_protocol(next_proto) { } Server::Server(output_fn output, data_cb got_data_cb, alert_cb recv_alert_cb, handshake_cb hs_cb, handshake_msg_cb hs_msg_cb, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, next_protocol_fn next_proto, bool is_datagram) : Channel(output, got_data_cb, recv_alert_cb, hs_cb, hs_msg_cb, session_manager, rng, policy, true, is_datagram), m_creds(creds), m_choose_next_protocol(next_proto) { } Handshake_State* Server::new_handshake_state(Handshake_IO* io) { std::unique_ptr state(new Server_Handshake_State(io, callbacks())); state->set_expected_next(CLIENT_HELLO); return state.release(); } std::vector Server::get_peer_cert_chain(const Handshake_State& state_base) const { const Server_Handshake_State& state = dynamic_cast(state_base); if(state.resume_peer_certs().size() > 0) return state.resume_peer_certs(); if(state.client_certs()) return state.client_certs()->cert_chain(); return std::vector(); } /* * Send a hello request to the client */ void Server::initiate_handshake(Handshake_State& state, bool force_full_renegotiation) { dynamic_cast(state). set_allow_session_resumption(!force_full_renegotiation); Hello_Request hello_req(state.handshake_io()); } namespace { Protocol_Version select_version(const Botan::TLS::Policy& policy, Protocol_Version client_offer, Protocol_Version active_version, bool is_fallback, const std::vector& supported_versions) { const bool is_datagram = client_offer.is_datagram_protocol(); const bool initial_handshake = (active_version.valid() == false); const Protocol_Version latest_supported = policy.latest_supported_version(is_datagram); if(is_fallback) { if(latest_supported > client_offer) throw TLS_Exception(Alert::INAPPROPRIATE_FALLBACK, "Client signalled fallback SCSV, possible attack"); } if(supported_versions.size() > 0) { if(is_datagram) { if(policy.allow_dtls12() && value_exists(supported_versions, Protocol_Version(Protocol_Version::DTLS_V12))) return Protocol_Version::DTLS_V12; #if defined(BOTAN_HAS_TLS_V10) if(policy.allow_dtls10() && value_exists(supported_versions, Protocol_Version(Protocol_Version::DTLS_V10))) return Protocol_Version::DTLS_V10; #endif throw TLS_Exception(Alert::PROTOCOL_VERSION, "No shared DTLS version"); } else { if(policy.allow_tls12() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V12))) return Protocol_Version::TLS_V12; #if defined(BOTAN_HAS_TLS_V10) if(policy.allow_tls11() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V11))) return Protocol_Version::TLS_V11; if(policy.allow_tls10() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V10))) return Protocol_Version::TLS_V10; #endif throw TLS_Exception(Alert::PROTOCOL_VERSION, "No shared TLS version"); } } const bool client_offer_acceptable = client_offer.known_version() && policy.acceptable_protocol_version(client_offer); if(!initial_handshake) { /* * If this is a renegotiation, and the client has offered a * later version than what it initially negotiated, negotiate * the old version. This matches OpenSSL's behavior. If the * client is offering a version earlier than what it initially * negotiated, reject as a probable attack. */ if(active_version > client_offer) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client negotiated " + active_version.to_string() + " then renegotiated with " + client_offer.to_string()); } else { return active_version; } } else if(client_offer_acceptable) { return client_offer; } else if(!client_offer.known_version() || client_offer > latest_supported) { /* The client offered some version newer than the latest we support. Offer them the best we know. */ return latest_supported; } else { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client version " + client_offer.to_string() + " is unacceptable by policy"); } } } /* * Process a CLIENT HELLO Message */ void Server::process_client_hello_msg(const Handshake_State* active_state, Server_Handshake_State& pending_state, const std::vector& contents, bool epoch0_restart) { BOTAN_ASSERT_IMPLICATION(epoch0_restart, active_state != nullptr, "Can't restart with a dead connection"); const bool initial_handshake = epoch0_restart || !active_state; if(initial_handshake == false && policy().allow_client_initiated_renegotiation() == false) { if(policy().abort_connection_on_undesired_renegotiation()) throw TLS_Exception(Alert::NO_RENEGOTIATION, "Server policy prohibits renegotiation"); else send_warning_alert(Alert::NO_RENEGOTIATION); return; } if(!policy().allow_insecure_renegotiation() && !(initial_handshake || secure_renegotiation_supported())) { send_warning_alert(Alert::NO_RENEGOTIATION); return; } pending_state.client_hello(new Client_Hello(contents)); const Protocol_Version client_offer = pending_state.client_hello()->version(); const bool datagram = client_offer.is_datagram_protocol(); if(datagram) { if(client_offer.major_version() == 0xFF) throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered DTLS version with major version 0xFF"); } else { if(client_offer.major_version() < 3) throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered TLS version with major version under 3"); if(client_offer.major_version() == 3 && client_offer.minor_version() == 0) throw TLS_Exception(Alert::PROTOCOL_VERSION, "SSLv3 is not supported"); } /* * BoGo test suite expects that we will send the hello verify with a record * version matching the version that is eventually negotiated. This is wrong * but harmless, so go with it. Also doing the version negotiation step first * allows to immediately close the connection with an alert if the client has * offered a version that we are not going to negotiate anyway, instead of * making them first do the cookie exchange and then telling them no. * * There is no issue with amplification here, since the alert is just 2 bytes. */ const Protocol_Version negotiated_version = select_version(policy(), client_offer, active_state ? active_state->version() : Protocol_Version(), pending_state.client_hello()->sent_fallback_scsv(), pending_state.client_hello()->supported_versions()); pending_state.set_version(negotiated_version); const auto compression_methods = pending_state.client_hello()->compression_methods(); if(!value_exists(compression_methods, uint8_t(0))) throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Client did not offer NULL compression"); if(initial_handshake && datagram) { SymmetricKey cookie_secret; try { cookie_secret = m_creds.psk("tls-server", "dtls-cookie-secret", ""); } catch(...) {} if(cookie_secret.size() > 0) { const std::string client_identity = callbacks().tls_peer_network_identity(); Hello_Verify_Request verify(pending_state.client_hello()->cookie_input_data(), client_identity, cookie_secret); if(pending_state.client_hello()->cookie() != verify.cookie()) { if(epoch0_restart) pending_state.handshake_io().send_under_epoch(verify, 0); else pending_state.handshake_io().send(verify); pending_state.client_hello(nullptr); pending_state.set_expected_next(CLIENT_HELLO); return; } } else if(epoch0_restart) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Reuse of DTLS association requires DTLS cookie secret be set"); } } if(epoch0_restart) { // If we reached here then we were able to verify the cookie reset_active_association_state(); } secure_renegotiation_check(pending_state.client_hello()); callbacks().tls_examine_extensions(pending_state.client_hello()->extensions(), CLIENT); Session session_info; const bool resuming = pending_state.allow_session_resumption() && check_for_resume(session_info, session_manager(), m_creds, pending_state.client_hello(), std::chrono::seconds(policy().session_ticket_lifetime())); bool have_session_ticket_key = false; try { have_session_ticket_key = m_creds.psk("tls-server", "session-ticket", "").length() > 0; } catch(...) {} m_next_protocol = ""; if(pending_state.client_hello()->supports_alpn()) { m_next_protocol = callbacks().tls_server_choose_app_protocol(pending_state.client_hello()->next_protocols()); // if the callback return was empty, fall back to the (deprecated) std::function if(m_next_protocol.empty() && m_choose_next_protocol) { m_next_protocol = m_choose_next_protocol(pending_state.client_hello()->next_protocols()); } } if(resuming) { this->session_resume(pending_state, have_session_ticket_key, session_info); } else // new session { this->session_create(pending_state, have_session_ticket_key); } } void Server::process_certificate_msg(Server_Handshake_State& pending_state, const std::vector& contents) { pending_state.client_certs(new Certificate(contents, policy())); // CERTIFICATE_REQUIRED would make more sense but BoGo expects handshake failure alert if(pending_state.client_certs()->empty() && policy().require_client_certificate_authentication()) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy requires client send a certificate, but it did not"); pending_state.set_expected_next(CLIENT_KEX); } void Server::process_client_key_exchange_msg(Server_Handshake_State& pending_state, const std::vector& contents) { if(pending_state.received_handshake_msg(CERTIFICATE) && !pending_state.client_certs()->empty()) pending_state.set_expected_next(CERTIFICATE_VERIFY); else pending_state.set_expected_next(HANDSHAKE_CCS); pending_state.client_kex(new Client_Key_Exchange(contents, pending_state, pending_state.server_rsa_kex_key(), m_creds, policy(), rng())); pending_state.compute_session_keys(); } void Server::process_change_cipher_spec_msg(Server_Handshake_State& pending_state) { pending_state.set_expected_next(FINISHED); change_cipher_spec_reader(SERVER); } void Server::process_certificate_verify_msg(Server_Handshake_State& pending_state, Handshake_Type type, const std::vector& contents) { pending_state.client_verify(new Certificate_Verify(contents, pending_state.version())); const std::vector& client_certs = pending_state.client_certs()->cert_chain(); const bool sig_valid = pending_state.client_verify()->verify(client_certs[0], pending_state, policy()); pending_state.hash().update(pending_state.handshake_io().format(contents, type)); /* * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for * "A handshake cryptographic operation failed, including being * unable to correctly verify a signature, ..." */ if(!sig_valid) throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed"); try { const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); callbacks().tls_verify_cert_chain(client_certs, {}, // ocsp trusted_CAs, Usage_Type::TLS_CLIENT_AUTH, sni_hostname, policy()); } catch(std::exception& e) { throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); } pending_state.set_expected_next(HANDSHAKE_CCS); } void Server::process_finished_msg(Server_Handshake_State& pending_state, Handshake_Type type, const std::vector& contents) { pending_state.set_expected_next(HANDSHAKE_NONE); pending_state.client_finished(new Finished(contents)); if(!pending_state.client_finished()->verify(pending_state, CLIENT)) throw TLS_Exception(Alert::DECRYPT_ERROR, "Finished message didn't verify"); if(!pending_state.server_finished()) { // already sent finished if resuming, so this is a new session pending_state.hash().update(pending_state.handshake_io().format(contents, type)); Session session_info( pending_state.server_hello()->session_id(), pending_state.session_keys().master_secret(), pending_state.server_hello()->version(), pending_state.server_hello()->ciphersuite(), SERVER, pending_state.server_hello()->supports_extended_master_secret(), pending_state.server_hello()->supports_encrypt_then_mac(), get_peer_cert_chain(pending_state), std::vector(), Server_Information(pending_state.client_hello()->sni_hostname()), pending_state.srp_identifier(), pending_state.server_hello()->srtp_profile()); if(save_session(session_info)) { if(pending_state.server_hello()->supports_session_ticket()) { try { const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); pending_state.new_session_ticket( new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash(), session_info.encrypt(ticket_key, rng()), policy().session_ticket_lifetime())); } catch(...) {} } else session_manager().save(session_info); } if(!pending_state.new_session_ticket() && pending_state.server_hello()->supports_session_ticket()) { pending_state.new_session_ticket( new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); } pending_state.handshake_io().send(Change_Cipher_Spec()); change_cipher_spec_writer(SERVER); pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); } activate_session(); } /* * Process a handshake message */ void Server::process_handshake_msg(const Handshake_State* active_state, Handshake_State& state_base, Handshake_Type type, const std::vector& contents, bool epoch0_restart) { Server_Handshake_State& state = dynamic_cast(state_base); state.confirm_transition_to(type); /* * The change cipher spec message isn't technically a handshake * message so it's not included in the hash. The finished and * certificate verify messages are verified based on the current * state of the hash *before* this message so we delay adding them * to the hash computation until we've processed them below. */ if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY) { state.hash().update(state.handshake_io().format(contents, type)); } switch(type) { case CLIENT_HELLO: return this->process_client_hello_msg(active_state, state, contents, epoch0_restart); case CERTIFICATE: return this->process_certificate_msg(state, contents); case CLIENT_KEX: return this->process_client_key_exchange_msg(state, contents); case CERTIFICATE_VERIFY: return this->process_certificate_verify_msg(state, type, contents); case HANDSHAKE_CCS: return this->process_change_cipher_spec_msg(state); case FINISHED: return this->process_finished_msg(state, type, contents); default: throw Unexpected_Message("Unknown handshake message received"); } } void Server::session_resume(Server_Handshake_State& pending_state, bool have_session_ticket_key, Session& session_info) { // Only offer a resuming client a new ticket if they didn't send one this time, // ie, resumed via server-side resumption. TODO: also send one if expiring soon? const bool offer_new_session_ticket = (pending_state.client_hello()->supports_session_ticket() && pending_state.client_hello()->session_ticket().empty() && have_session_ticket_key); pending_state.server_hello(new Server_Hello( pending_state.handshake_io(), pending_state.hash(), policy(), callbacks(), rng(), secure_renegotiation_data_for_server_hello(), *pending_state.client_hello(), session_info, offer_new_session_ticket, m_next_protocol)); secure_renegotiation_check(pending_state.server_hello()); pending_state.mark_as_resumption(); pending_state.compute_session_keys(session_info.master_secret()); pending_state.set_resume_certs(session_info.peer_certs()); if(!save_session(session_info)) { session_manager().remove_entry(session_info.session_id()); if(pending_state.server_hello()->supports_session_ticket()) // send an empty ticket { pending_state.new_session_ticket( new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); } } if(pending_state.server_hello()->supports_session_ticket() && !pending_state.new_session_ticket()) { try { const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); pending_state.new_session_ticket( new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash(), session_info.encrypt(ticket_key, rng()), policy().session_ticket_lifetime())); } catch(...) {} if(!pending_state.new_session_ticket()) { pending_state.new_session_ticket( new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); } } pending_state.handshake_io().send(Change_Cipher_Spec()); change_cipher_spec_writer(SERVER); pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); pending_state.set_expected_next(HANDSHAKE_CCS); } void Server::session_create(Server_Handshake_State& pending_state, bool have_session_ticket_key) { std::map> cert_chains; const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); cert_chains = get_server_certs(sni_hostname, m_creds); if(sni_hostname != "" && cert_chains.empty()) { cert_chains = get_server_certs("", m_creds); /* * Only send the unrecognized_name alert if we couldn't * find any certs for the requested name but did find at * least one cert to use in general. That avoids sending an * unrecognized_name when a server is configured for purely * anonymous/PSK operation. */ if(!cert_chains.empty()) send_warning_alert(Alert::UNRECOGNIZED_NAME); } const uint16_t ciphersuite = choose_ciphersuite(policy(), pending_state.version(), m_creds, cert_chains, *pending_state.client_hello()); Server_Hello::Settings srv_settings( make_hello_random(rng(), policy()), // new session ID pending_state.version(), ciphersuite, have_session_ticket_key); pending_state.server_hello(new Server_Hello( pending_state.handshake_io(), pending_state.hash(), policy(), callbacks(), rng(), secure_renegotiation_data_for_server_hello(), *pending_state.client_hello(), srv_settings, m_next_protocol)); secure_renegotiation_check(pending_state.server_hello()); const Ciphersuite& pending_suite = pending_state.ciphersuite(); Private_Key* private_key = nullptr; if(pending_suite.signature_used() || pending_suite.kex_method() == Kex_Algo::STATIC_RSA) { const std::string algo_used = pending_suite.signature_used() ? pending_suite.sig_algo() : "RSA"; BOTAN_ASSERT(!cert_chains[algo_used].empty(), "Attempting to send empty certificate chain"); pending_state.server_certs(new Certificate(pending_state.handshake_io(), pending_state.hash(), cert_chains[algo_used])); if(pending_state.client_hello()->supports_cert_status_message() && pending_state.is_a_resumption() == false) { auto csr = pending_state.client_hello()->extensions().get(); // csr is non-null if client_hello()->supports_cert_status_message() BOTAN_ASSERT_NOMSG(csr != nullptr); const auto resp_bytes = callbacks().tls_provide_cert_status(cert_chains[algo_used], *csr); if(resp_bytes.size() > 0) { pending_state.server_cert_status(new Certificate_Status( pending_state.handshake_io(), pending_state.hash(), resp_bytes )); } } private_key = m_creds.private_key_for( pending_state.server_certs()->cert_chain()[0], "tls-server", sni_hostname); if(!private_key) throw Internal_Error("No private key located for associated server cert"); } if(pending_suite.kex_method() == Kex_Algo::STATIC_RSA) { pending_state.set_server_rsa_kex_key(private_key); } else { pending_state.server_kex(new Server_Key_Exchange(pending_state.handshake_io(), pending_state, policy(), m_creds, rng(), private_key)); } auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); std::vector client_auth_CAs; for(auto store : trusted_CAs) { auto subjects = store->all_subjects(); client_auth_CAs.insert(client_auth_CAs.end(), subjects.begin(), subjects.end()); } const bool request_cert = (client_auth_CAs.empty() == false) || policy().request_client_certificate_authentication(); if(request_cert && pending_state.ciphersuite().signature_used()) { pending_state.cert_req( new Certificate_Req(pending_state.handshake_io(), pending_state.hash(), policy(), client_auth_CAs, pending_state.version())); /* SSLv3 allowed clients to skip the Certificate message entirely if they wanted. In TLS v1.0 and later clients must send a (possibly empty) Certificate message */ pending_state.set_expected_next(CERTIFICATE); } else { pending_state.set_expected_next(CLIENT_KEX); } pending_state.server_hello_done(new Server_Hello_Done(pending_state.handshake_io(), pending_state.hash())); } } } /* * TLS Session State * (C) 2011-2012,2015,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { Session::Session(const std::vector& session_identifier, const secure_vector& master_secret, Protocol_Version version, uint16_t ciphersuite, Connection_Side side, bool extended_master_secret, bool encrypt_then_mac, const std::vector& certs, const std::vector& ticket, const Server_Information& server_info, const std::string& srp_identifier, uint16_t srtp_profile) : m_start_time(std::chrono::system_clock::now()), m_identifier(session_identifier), m_session_ticket(ticket), m_master_secret(master_secret), m_version(version), m_ciphersuite(ciphersuite), m_connection_side(side), m_srtp_profile(srtp_profile), m_extended_master_secret(extended_master_secret), m_encrypt_then_mac(encrypt_then_mac), m_peer_certs(certs), m_server_info(server_info), m_srp_identifier(srp_identifier) { } Session::Session(const std::string& pem) { secure_vector der = PEM_Code::decode_check_label(pem, "TLS SESSION"); *this = Session(der.data(), der.size()); } Session::Session(const uint8_t ber[], size_t ber_len) { uint8_t side_code = 0; ASN1_String server_hostname; ASN1_String server_service; size_t server_port; ASN1_String srp_identifier_str; uint8_t major_version = 0, minor_version = 0; std::vector peer_cert_bits; size_t start_time = 0; size_t srtp_profile = 0; size_t fragment_size = 0; size_t compression_method = 0; BER_Decoder(ber, ber_len) .start_cons(SEQUENCE) .decode_and_check(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION), "Unknown version in serialized TLS session") .decode_integer_type(start_time) .decode_integer_type(major_version) .decode_integer_type(minor_version) .decode(m_identifier, OCTET_STRING) .decode(m_session_ticket, OCTET_STRING) .decode_integer_type(m_ciphersuite) .decode_integer_type(compression_method) .decode_integer_type(side_code) .decode_integer_type(fragment_size) .decode(m_extended_master_secret) .decode(m_encrypt_then_mac) .decode(m_master_secret, OCTET_STRING) .decode(peer_cert_bits, OCTET_STRING) .decode(server_hostname) .decode(server_service) .decode(server_port) .decode(srp_identifier_str) .decode(srtp_profile) .end_cons() .verify_end(); /* * Compression is not supported and must be zero */ if(compression_method != 0) { throw Decoding_Error("Serialized TLS session contains non-null compression method"); } /* Fragment size is not supported anymore, but the field is still set in the session object. */ if(fragment_size != 0) { throw Decoding_Error("Serialized TLS session used maximum fragment length which is " " no longer supported"); } m_version = Protocol_Version(major_version, minor_version); m_start_time = std::chrono::system_clock::from_time_t(start_time); m_connection_side = static_cast(side_code); m_srtp_profile = static_cast(srtp_profile); m_server_info = Server_Information(server_hostname.value(), server_service.value(), static_cast(server_port)); m_srp_identifier = srp_identifier_str.value(); if(!peer_cert_bits.empty()) { DataSource_Memory certs(peer_cert_bits.data(), peer_cert_bits.size()); while(!certs.end_of_data()) m_peer_certs.push_back(X509_Certificate(certs)); } } secure_vector Session::DER_encode() const { std::vector peer_cert_bits; for(size_t i = 0; i != m_peer_certs.size(); ++i) peer_cert_bits += m_peer_certs[i].BER_encode(); return DER_Encoder() .start_cons(SEQUENCE) .encode(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION)) .encode(static_cast(std::chrono::system_clock::to_time_t(m_start_time))) .encode(static_cast(m_version.major_version())) .encode(static_cast(m_version.minor_version())) .encode(m_identifier, OCTET_STRING) .encode(m_session_ticket, OCTET_STRING) .encode(static_cast(m_ciphersuite)) .encode(static_cast(/*old compression method*/0)) .encode(static_cast(m_connection_side)) .encode(static_cast(/*old fragment size*/0)) .encode(m_extended_master_secret) .encode(m_encrypt_then_mac) .encode(m_master_secret, OCTET_STRING) .encode(peer_cert_bits, OCTET_STRING) .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING)) .encode(ASN1_String(m_server_info.service(), UTF8_STRING)) .encode(static_cast(m_server_info.port())) .encode(ASN1_String(m_srp_identifier, UTF8_STRING)) .encode(static_cast(m_srtp_profile)) .end_cons() .get_contents(); } std::string Session::PEM_encode() const { return PEM_Code::encode(this->DER_encode(), "TLS SESSION"); } std::chrono::seconds Session::session_age() const { return std::chrono::duration_cast( std::chrono::system_clock::now() - m_start_time); } namespace { // The output length of the HMAC must be a valid keylength for the AEAD const char* TLS_SESSION_CRYPT_HMAC = "HMAC(SHA-512-256)"; // SIV would be better, but we can't assume it is available const char* TLS_SESSION_CRYPT_AEAD = "AES-256/GCM"; const char* TLS_SESSION_CRYPT_KEY_NAME = "BOTAN TLS SESSION KEY NAME"; const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000; const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8; const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4; const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12; const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16; const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16; const size_t TLS_SESSION_CRYPT_HDR_LEN = TLS_SESSION_CRYPT_MAGIC_LEN + TLS_SESSION_CRYPT_KEY_NAME_LEN + TLS_SESSION_CRYPT_AEAD_NONCE_LEN + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN; const size_t TLS_SESSION_CRYPT_OVERHEAD = TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE; } std::vector Session::encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const { auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC); hmac->set_key(key); // First derive the "key name" std::vector key_name(hmac->output_length()); hmac->update(TLS_SESSION_CRYPT_KEY_NAME); hmac->final(key_name.data()); key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN); std::vector aead_nonce; std::vector key_seed; rng.random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN); rng.random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN); hmac->update(key_seed); const secure_vector aead_key = hmac->final(); secure_vector bits = this->DER_encode(); // create the header std::vector buf; buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size()); buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN); store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]); buf += key_name; buf += key_seed; buf += aead_nonce; std::unique_ptr aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, ENCRYPTION); BOTAN_ASSERT_NOMSG(aead->valid_nonce_length(TLS_SESSION_CRYPT_AEAD_NONCE_LEN)); BOTAN_ASSERT_NOMSG(aead->tag_size() == TLS_SESSION_CRYPT_AEAD_TAG_SIZE); aead->set_key(aead_key); aead->set_associated_data_vec(buf); aead->start(aead_nonce); aead->finish(bits, 0); // append the ciphertext buf += bits; return buf; } Session Session::decrypt(const uint8_t in[], size_t in_len, const SymmetricKey& key) { try { const size_t min_session_size = 48 + 4; // serious under-estimate if(in_len < TLS_SESSION_CRYPT_OVERHEAD + min_session_size) throw Decoding_Error("Encrypted session too short to be valid"); const uint8_t* magic = &in[0]; const uint8_t* key_name = magic + TLS_SESSION_CRYPT_MAGIC_LEN; const uint8_t* key_seed = key_name + TLS_SESSION_CRYPT_KEY_NAME_LEN; const uint8_t* aead_nonce = key_seed + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN; const uint8_t* ctext = aead_nonce + TLS_SESSION_CRYPT_AEAD_NONCE_LEN; const size_t ctext_len = in_len - TLS_SESSION_CRYPT_HDR_LEN; // includes the tag if(load_be(magic, 0) != TLS_SESSION_CRYPT_MAGIC) throw Decoding_Error("Missing expected magic numbers"); auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC); hmac->set_key(key); // First derive and check the "key name" std::vector cmp_key_name(hmac->output_length()); hmac->update(TLS_SESSION_CRYPT_KEY_NAME); hmac->final(cmp_key_name.data()); if(same_mem(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN) == false) throw Decoding_Error("Wrong key name for encrypted session"); hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN); const secure_vector aead_key = hmac->final(); auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, DECRYPTION); aead->set_key(aead_key); aead->set_associated_data(in, TLS_SESSION_CRYPT_HDR_LEN); aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN); secure_vector buf(ctext, ctext + ctext_len); aead->finish(buf, 0); return Session(buf.data(), buf.size()); } catch(std::exception& e) { throw Decoding_Error("Failed to decrypt serialized TLS session: " + std::string(e.what())); } } } } /* * TLS Session Key * (C) 2004-2006,2011,2016,2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { /** * Session_Keys Constructor */ Session_Keys::Session_Keys(const Handshake_State* state, const secure_vector& pre_master_secret, bool resuming) { const size_t cipher_keylen = state->ciphersuite().cipher_keylen(); const size_t mac_keylen = state->ciphersuite().mac_keylen(); const size_t cipher_nonce_bytes = state->ciphersuite().nonce_bytes_from_handshake(); const bool extended_master_secret = state->server_hello()->supports_extended_master_secret(); const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_nonce_bytes); const uint8_t MASTER_SECRET_MAGIC[] = { 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 }; const uint8_t EXT_MASTER_SECRET_MAGIC[] = { 0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 }; const uint8_t KEY_GEN_MAGIC[] = { 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, 0x6E }; std::unique_ptr prf(state->protocol_specific_prf()); if(resuming) { // This is actually the master secret saved as part of the session m_master_sec = pre_master_secret; } else { std::vector salt; std::vector label; if(extended_master_secret) { label.assign(EXT_MASTER_SECRET_MAGIC, EXT_MASTER_SECRET_MAGIC + sizeof(EXT_MASTER_SECRET_MAGIC)); salt += state->hash().final(state->version(), state->ciphersuite().prf_algo()); } else { label.assign(MASTER_SECRET_MAGIC, MASTER_SECRET_MAGIC + sizeof(MASTER_SECRET_MAGIC)); salt += state->client_hello()->random(); salt += state->server_hello()->random(); } m_master_sec = prf->derive_key(48, pre_master_secret, salt, label); } std::vector salt; std::vector label; label.assign(KEY_GEN_MAGIC, KEY_GEN_MAGIC + sizeof(KEY_GEN_MAGIC)); salt += state->server_hello()->random(); salt += state->client_hello()->random(); const secure_vector prf_output = prf->derive_key( prf_gen, m_master_sec.data(), m_master_sec.size(), salt.data(), salt.size(), label.data(), label.size()); const uint8_t* key_data = prf_output.data(); m_c_aead.resize(mac_keylen + cipher_keylen); m_s_aead.resize(mac_keylen + cipher_keylen); copy_mem(&m_c_aead[0], key_data, mac_keylen); copy_mem(&m_s_aead[0], key_data + mac_keylen, mac_keylen); copy_mem(&m_c_aead[mac_keylen], key_data + 2*mac_keylen, cipher_keylen); copy_mem(&m_s_aead[mac_keylen], key_data + 2*mac_keylen + cipher_keylen, cipher_keylen); m_c_nonce.resize(cipher_nonce_bytes); m_s_nonce.resize(cipher_nonce_bytes); copy_mem(&m_c_nonce[0], key_data + 2*(mac_keylen + cipher_keylen), cipher_nonce_bytes); copy_mem(&m_s_nonce[0], key_data + 2*(mac_keylen + cipher_keylen) + cipher_nonce_bytes, cipher_nonce_bytes); } } } /* * TLS Session Management * (C) 2011,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { Session_Manager_In_Memory::Session_Manager_In_Memory( RandomNumberGenerator& rng, size_t max_sessions, std::chrono::seconds session_lifetime) : m_max_sessions(max_sessions), m_session_lifetime(session_lifetime), m_rng(rng), m_session_key(m_rng.random_vec(32)) {} bool Session_Manager_In_Memory::load_from_session_str( const std::string& session_str, Session& session) { // assert(lock is held) auto i = m_sessions.find(session_str); if(i == m_sessions.end()) return false; try { session = Session::decrypt(i->second, m_session_key); } catch(...) { return false; } // if session has expired, remove it const auto now = std::chrono::system_clock::now(); if(session.start_time() + session_lifetime() < now) { m_sessions.erase(i); return false; } return true; } bool Session_Manager_In_Memory::load_from_session_id( const std::vector& session_id, Session& session) { lock_guard_type lock(m_mutex); return load_from_session_str(hex_encode(session_id), session); } bool Session_Manager_In_Memory::load_from_server_info( const Server_Information& info, Session& session) { lock_guard_type lock(m_mutex); auto i = m_info_sessions.find(info); if(i == m_info_sessions.end()) return false; if(load_from_session_str(i->second, session)) return true; /* * It existed at one point but was removed from the sessions map, * remove m_info_sessions entry as well */ m_info_sessions.erase(i); return false; } void Session_Manager_In_Memory::remove_entry( const std::vector& session_id) { lock_guard_type lock(m_mutex); auto i = m_sessions.find(hex_encode(session_id)); if(i != m_sessions.end()) m_sessions.erase(i); } size_t Session_Manager_In_Memory::remove_all() { const size_t removed = m_sessions.size(); m_info_sessions.clear(); m_sessions.clear(); m_rng.random_vec(m_session_key, 32); return removed; } void Session_Manager_In_Memory::save(const Session& session) { lock_guard_type lock(m_mutex); if(m_max_sessions != 0) { /* We generate new session IDs with the first 4 bytes being a timestamp, so this actually removes the oldest sessions first. */ while(m_sessions.size() >= m_max_sessions) m_sessions.erase(m_sessions.begin()); } const std::string session_id_str = hex_encode(session.session_id()); m_sessions[session_id_str] = session.encrypt(m_session_key, m_rng); if(session.side() == CLIENT && !session.server_info().empty()) m_info_sessions[session.server_info()] = session_id_str; } } } /* * TLS cipher suite information * * This file was automatically generated from the IANA assignments * (tls-parameters.txt hash fe1ef8f3492b0708f3b14c9e8f8de55188c1b3c0) * by ./src/scripts/tls_suite_info.py on 2019-05-24 * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { //static const std::vector& Ciphersuite::all_known_ciphersuites() { // Note that this list of ciphersuites is ordered by id! static const std::vector g_ciphersuite_list = { Ciphersuite(0x000A, "RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0013, "DHE_DSS_WITH_3DES_EDE_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0016, "DHE_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x001B, "DH_anon_WITH_3DES_EDE_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x002F, "RSA_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0032, "DHE_DSS_WITH_AES_128_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0033, "DHE_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0034, "DH_anon_WITH_AES_128_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0035, "RSA_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0038, "DHE_DSS_WITH_AES_256_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0039, "DHE_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x003A, "DH_anon_WITH_AES_256_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x003C, "RSA_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x003D, "RSA_WITH_AES_256_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x0040, "DHE_DSS_WITH_AES_128_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x0041, "RSA_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0044, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0045, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0046, "DH_anon_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0067, "DHE_RSA_WITH_AES_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x006A, "DHE_DSS_WITH_AES_256_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x006B, "DHE_RSA_WITH_AES_256_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x006C, "DH_anon_WITH_AES_128_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x006D, "DH_anon_WITH_AES_256_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x0084, "RSA_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0087, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0088, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0089, "DH_anon_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x008B, "PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x008C, "PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x008D, "PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x008F, "DHE_PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0090, "DHE_PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0091, "DHE_PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0096, "RSA_WITH_SEED_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x0099, "DHE_DSS_WITH_SEED_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x009A, "DHE_RSA_WITH_SEED_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x009B, "DH_anon_WITH_SEED_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0x009C, "RSA_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x009D, "RSA_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x009E, "DHE_RSA_WITH_AES_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x009F, "DHE_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::DH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00A2, "DHE_DSS_WITH_AES_128_GCM_SHA256", Auth_Method::DSA, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00A3, "DHE_DSS_WITH_AES_256_GCM_SHA384", Auth_Method::DSA, Kex_Algo::DH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00A6, "DH_anon_WITH_AES_128_GCM_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00A7, "DH_anon_WITH_AES_256_GCM_SHA384", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00A8, "PSK_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00A9, "PSK_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00AA, "DHE_PSK_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00AB, "DHE_PSK_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x00AE, "PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00AF, "PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0x00B2, "DHE_PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00B3, "DHE_PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0x00BA, "RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00BD, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00BE, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00BF, "DH_anon_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00C0, "RSA_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00C3, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00C4, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x00C5, "DH_anon_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0x16B7, "CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::CECPQ1, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0x16B8, "CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0x16B9, "CECPQ1_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::CECPQ1, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0x16BA, "CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC008, "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::ECDSA, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC009, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC00A, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC012, "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC013, "ECDHE_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC014, "ECDHE_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC017, "ECDH_anon_WITH_3DES_EDE_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC018, "ECDH_anon_WITH_AES_128_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC019, "ECDH_anon_WITH_AES_256_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC01A, "SRP_SHA_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC01B, "SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC01C, "SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", Auth_Method::DSA, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC01D, "SRP_SHA_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC01E, "SRP_SHA_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC01F, "SRP_SHA_DSS_WITH_AES_128_CBC_SHA", Auth_Method::DSA, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC020, "SRP_SHA_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC021, "SRP_SHA_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC022, "SRP_SHA_DSS_WITH_AES_256_CBC_SHA", Auth_Method::DSA, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC023, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC024, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC027, "ECDHE_RSA_WITH_AES_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC028, "ECDHE_RSA_WITH_AES_256_CBC_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC02B, "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC02C, "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC02F, "ECDHE_RSA_WITH_AES_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC030, "ECDHE_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC034, "ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC035, "ECDHE_PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC036, "ECDHE_PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), Ciphersuite(0xC037, "ECDHE_PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC038, "ECDHE_PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC050, "RSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC051, "RSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC052, "DHE_RSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC053, "DHE_RSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::DH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC056, "DHE_DSS_WITH_ARIA_128_GCM_SHA256", Auth_Method::DSA, Kex_Algo::DH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC057, "DHE_DSS_WITH_ARIA_256_GCM_SHA384", Auth_Method::DSA, Kex_Algo::DH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC05A, "DH_anon_WITH_ARIA_128_GCM_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC05B, "DH_anon_WITH_ARIA_256_GCM_SHA384", Auth_Method::ANONYMOUS, Kex_Algo::DH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC05C, "ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC05D, "ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC060, "ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC061, "ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC06A, "PSK_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC06B, "PSK_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC06C, "DHE_PSK_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC06D, "DHE_PSK_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC072, "ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC073, "ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC076, "ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC077, "ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC07A, "RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC07B, "RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC07C, "DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC07D, "DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC080, "DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::DSA, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC081, "DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::DSA, Kex_Algo::DH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC084, "DH_anon_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC085, "DH_anon_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC086, "ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC087, "ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC08A, "ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC08B, "ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC08E, "PSK_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC08F, "PSK_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC090, "DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC091, "DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC094, "PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC095, "PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC096, "DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC097, "DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC09A, "ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), Ciphersuite(0xC09B, "ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), Ciphersuite(0xC09C, "RSA_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC09D, "RSA_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC09E, "DHE_RSA_WITH_AES_128_CCM", Auth_Method::RSA, Kex_Algo::DH, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC09F, "DHE_RSA_WITH_AES_256_CCM", Auth_Method::RSA, Kex_Algo::DH, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A0, "RSA_WITH_AES_128_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A1, "RSA_WITH_AES_256_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A2, "DHE_RSA_WITH_AES_128_CCM_8", Auth_Method::RSA, Kex_Algo::DH, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A3, "DHE_RSA_WITH_AES_256_CCM_8", Auth_Method::RSA, Kex_Algo::DH, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A4, "PSK_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A5, "PSK_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A6, "DHE_PSK_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A7, "DHE_PSK_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A8, "PSK_WITH_AES_128_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0A9, "PSK_WITH_AES_256_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0AA, "PSK_DHE_WITH_AES_128_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0AB, "PSK_DHE_WITH_AES_256_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0AC, "ECDHE_ECDSA_WITH_AES_128_CCM", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0AD, "ECDHE_ECDSA_WITH_AES_256_CCM", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0AE, "ECDHE_ECDSA_WITH_AES_128_CCM_8", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xC0AF, "ECDHE_ECDSA_WITH_AES_256_CCM_8", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xCCA8, "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xCCA9, "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xCCAA, "DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::DH, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xCCAB, "PSK_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xCCAC, "ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xCCAD, "DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xD001, "ECDHE_PSK_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xD002, "ECDHE_PSK_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xD003, "ECDHE_PSK_WITH_AES_128_CCM_8_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xD005, "ECDHE_PSK_WITH_AES_128_CCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), Ciphersuite(0xFFC0, "DHE_RSA_WITH_AES_128_OCB_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC1, "DHE_RSA_WITH_AES_256_OCB_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC2, "ECDHE_RSA_WITH_AES_128_OCB_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC3, "ECDHE_RSA_WITH_AES_256_OCB_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC4, "ECDHE_ECDSA_WITH_AES_128_OCB_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC5, "ECDHE_ECDSA_WITH_AES_256_OCB_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC6, "PSK_WITH_AES_128_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC7, "PSK_WITH_AES_256_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC8, "DHE_PSK_WITH_AES_128_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFC9, "DHE_PSK_WITH_AES_256_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFCA, "ECDHE_PSK_WITH_AES_128_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFCB, "ECDHE_PSK_WITH_AES_256_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFCC, "CECPQ1_RSA_WITH_AES_256_OCB_SHA256", Auth_Method::RSA, Kex_Algo::CECPQ1, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), Ciphersuite(0xFFCD, "CECPQ1_ECDSA_WITH_AES_256_OCB_SHA256", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), }; return g_ciphersuite_list; } } } /* * Text-Based TLS Policy * (C) 2016,2017 Jack Lloyd * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { std::vector Text_Policy::allowed_ciphers() const { return get_list("ciphers", Policy::allowed_ciphers()); } std::vector Text_Policy::allowed_signature_hashes() const { return get_list("signature_hashes", Policy::allowed_signature_hashes()); } std::vector Text_Policy::allowed_macs() const { return get_list("macs", Policy::allowed_macs()); } std::vector Text_Policy::allowed_key_exchange_methods() const { return get_list("key_exchange_methods", Policy::allowed_key_exchange_methods()); } std::vector Text_Policy::allowed_signature_methods() const { return get_list("signature_methods", Policy::allowed_signature_methods()); } bool Text_Policy::use_ecc_point_compression() const { return get_bool("use_ecc_point_compression", Policy::use_ecc_point_compression()); } bool Text_Policy::allow_tls10() const { return get_bool("allow_tls10", Policy::allow_tls10()); } bool Text_Policy::allow_tls11() const { return get_bool("allow_tls11", Policy::allow_tls11()); } bool Text_Policy::allow_tls12() const { return get_bool("allow_tls12", Policy::allow_tls12()); } bool Text_Policy::allow_dtls10() const { return get_bool("allow_dtls10", Policy::allow_dtls10()); } bool Text_Policy::allow_dtls12() const { return get_bool("allow_dtls12", Policy::allow_dtls12()); } bool Text_Policy::allow_insecure_renegotiation() const { return get_bool("allow_insecure_renegotiation", Policy::allow_insecure_renegotiation()); } bool Text_Policy::include_time_in_hello_random() const { return get_bool("include_time_in_hello_random", Policy::include_time_in_hello_random()); } bool Text_Policy::require_client_certificate_authentication() const { return get_bool("require_client_certificate_authentication", Policy::require_client_certificate_authentication()); } bool Text_Policy::allow_client_initiated_renegotiation() const { return get_bool("allow_client_initiated_renegotiation", Policy::allow_client_initiated_renegotiation()); } bool Text_Policy::allow_server_initiated_renegotiation() const { return get_bool("allow_server_initiated_renegotiation", Policy::allow_server_initiated_renegotiation()); } bool Text_Policy::server_uses_own_ciphersuite_preferences() const { return get_bool("server_uses_own_ciphersuite_preferences", Policy::server_uses_own_ciphersuite_preferences()); } bool Text_Policy::negotiate_encrypt_then_mac() const { return get_bool("negotiate_encrypt_then_mac", Policy::negotiate_encrypt_then_mac()); } bool Text_Policy::support_cert_status_message() const { return get_bool("support_cert_status_message", Policy::support_cert_status_message()); } std::vector Text_Policy::key_exchange_groups() const { std::string group_str = get_str("key_exchange_groups"); if(group_str.empty()) { // fall back to previously used name group_str = get_str("groups"); } if(group_str.empty()) { return Policy::key_exchange_groups(); } std::vector groups; for(std::string group_name : split_on(group_str, ' ')) { Group_Params group_id = group_param_from_string(group_name); if(group_id == Group_Params::NONE) { try { size_t consumed = 0; unsigned long ll_id = std::stoul(group_name, &consumed, 0); if(consumed != group_name.size()) continue; // some other cruft const uint16_t id = static_cast(ll_id); if(id != ll_id) continue; // integer too large group_id = static_cast(id); } catch(...) { continue; } } if(group_id != Group_Params::NONE) groups.push_back(group_id); } return groups; } size_t Text_Policy::minimum_ecdh_group_size() const { return get_len("minimum_ecdh_group_size", Policy::minimum_ecdh_group_size()); } size_t Text_Policy::minimum_ecdsa_group_size() const { return get_len("minimum_ecdsa_group_size", Policy::minimum_ecdsa_group_size()); } size_t Text_Policy::minimum_dh_group_size() const { return get_len("minimum_dh_group_size", Policy::minimum_dh_group_size()); } size_t Text_Policy::minimum_rsa_bits() const { return get_len("minimum_rsa_bits", Policy::minimum_rsa_bits()); } size_t Text_Policy::minimum_signature_strength() const { return get_len("minimum_signature_strength", Policy::minimum_signature_strength()); } size_t Text_Policy::dtls_default_mtu() const { return get_len("dtls_default_mtu", Policy::dtls_default_mtu()); } size_t Text_Policy::dtls_initial_timeout() const { return get_len("dtls_initial_timeout", Policy::dtls_initial_timeout()); } size_t Text_Policy::dtls_maximum_timeout() const { return get_len("dtls_maximum_timeout", Policy::dtls_maximum_timeout()); } bool Text_Policy::require_cert_revocation_info() const { return get_bool("require_cert_revocation_info", Policy::require_cert_revocation_info()); } bool Text_Policy::hide_unknown_users() const { return get_bool("hide_unknown_users", Policy::hide_unknown_users()); } uint32_t Text_Policy::session_ticket_lifetime() const { return static_cast(get_len("session_ticket_lifetime", Policy::session_ticket_lifetime())); } bool Text_Policy::send_fallback_scsv(Protocol_Version version) const { return get_bool("send_fallback_scsv", false) ? Policy::send_fallback_scsv(version) : false; } std::vector Text_Policy::srtp_profiles() const { std::vector r; for(std::string p : get_list("srtp_profiles", std::vector())) { r.push_back(to_uint16(p)); } return r; } void Text_Policy::set(const std::string& k, const std::string& v) { m_kv[k] = v; } Text_Policy::Text_Policy(const std::string& s) { std::istringstream iss(s); m_kv = read_cfg(iss); } Text_Policy::Text_Policy(std::istream& in) : m_kv(read_cfg(in)) {} std::vector Text_Policy::get_list(const std::string& key, const std::vector& def) const { const std::string v = get_str(key); if(v.empty()) { return def; } return split_on(v, ' '); } size_t Text_Policy::get_len(const std::string& key, size_t def) const { const std::string v = get_str(key); if(v.empty()) { return def; } return to_u32bit(v); } bool Text_Policy::get_bool(const std::string& key, bool def) const { const std::string v = get_str(key); if(v.empty()) { return def; } if(v == "true" || v == "True") { return true; } else if(v == "false" || v == "False") { return false; } else { throw Decoding_Error("Invalid boolean '" + v + "'"); } } std::string Text_Policy::get_str(const std::string& key, const std::string& def) const { auto i = m_kv.find(key); if(i == m_kv.end()) { return def; } return i->second; } bool Text_Policy::set_value(const std::string& key, const std::string& val, bool overwrite) { auto i = m_kv.find(key); if(overwrite == false && i != m_kv.end()) return false; m_kv.insert(i, std::make_pair(key, val)); return true; } } } /* * TLS Protocol Version Management * (C) 2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { std::string Protocol_Version::to_string() const { const uint8_t maj = major_version(); const uint8_t min = minor_version(); if(maj == 3 && min == 0) return "SSL v3"; if(maj == 3 && min >= 1) // TLS v1.x return "TLS v1." + std::to_string(min-1); if(maj == 254) // DTLS 1.x return "DTLS v1." + std::to_string(255 - min); // Some very new or very old protocol (or bogus data) return "Unknown " + std::to_string(maj) + "." + std::to_string(min); } bool Protocol_Version::is_datagram_protocol() const { return major_version() > 250; } bool Protocol_Version::operator>(const Protocol_Version& other) const { if(this->is_datagram_protocol() != other.is_datagram_protocol()) throw TLS_Exception(Alert::PROTOCOL_VERSION, "Version comparing " + to_string() + " with " + other.to_string()); if(this->is_datagram_protocol()) return m_version < other.m_version; // goes backwards return m_version > other.m_version; } bool Protocol_Version::known_version() const { return (m_version == Protocol_Version::TLS_V10 || m_version == Protocol_Version::TLS_V11 || m_version == Protocol_Version::TLS_V12 || m_version == Protocol_Version::DTLS_V10 || m_version == Protocol_Version::DTLS_V12); } bool Protocol_Version::supports_negotiable_signature_algorithms() const { return (m_version != Protocol_Version::TLS_V10 && m_version != Protocol_Version::TLS_V11 && m_version != Protocol_Version::DTLS_V10); } bool Protocol_Version::supports_explicit_cbc_ivs() const { return (m_version != Protocol_Version::TLS_V10); } bool Protocol_Version::supports_ciphersuite_specific_prf() const { return (m_version != Protocol_Version::TLS_V10 && m_version != Protocol_Version::TLS_V11 && m_version != Protocol_Version::DTLS_V10); } bool Protocol_Version::supports_aead_modes() const { return (m_version != Protocol_Version::TLS_V10 && m_version != Protocol_Version::TLS_V11 && m_version != Protocol_Version::DTLS_V10); } } } /* * TLS CBC Record Handling * (C) 2012,2013,2014,2015,2016,2020 Jack Lloyd * (C) 2016 Juraj Somorovsky * (C) 2016 Matthias Gierlings * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace TLS { /* * TLS_CBC_HMAC_AEAD_Mode Constructor */ TLS_CBC_HMAC_AEAD_Mode::TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir dir, std::unique_ptr cipher, std::unique_ptr mac, size_t cipher_keylen, size_t mac_keylen, Protocol_Version version, bool use_encrypt_then_mac) : m_cipher_name(cipher->name()), m_mac_name(mac->name()), m_cipher_keylen(cipher_keylen), m_mac_keylen(mac_keylen), m_use_encrypt_then_mac(use_encrypt_then_mac) { m_tag_size = mac->output_length(); m_block_size = cipher->block_size(); m_iv_size = version.supports_explicit_cbc_ivs() ? m_block_size : 0; m_is_datagram = version.is_datagram_protocol(); m_mac = std::move(mac); if(dir == ENCRYPTION) m_cbc.reset(new CBC_Encryption(cipher.release(), new Null_Padding)); else m_cbc.reset(new CBC_Decryption(cipher.release(), new Null_Padding)); } void TLS_CBC_HMAC_AEAD_Mode::clear() { cbc().clear(); mac().clear(); reset(); } void TLS_CBC_HMAC_AEAD_Mode::reset() { cbc_state().clear(); m_ad.clear(); m_msg.clear(); } std::string TLS_CBC_HMAC_AEAD_Mode::name() const { return "TLS_CBC(" + m_cipher_name + "," + m_mac_name + ")"; } size_t TLS_CBC_HMAC_AEAD_Mode::update_granularity() const { return 1; // just buffers anyway } bool TLS_CBC_HMAC_AEAD_Mode::valid_nonce_length(size_t nl) const { if(m_cbc_state.empty()) return nl == block_size(); return nl == iv_size(); } Key_Length_Specification TLS_CBC_HMAC_AEAD_Mode::key_spec() const { return Key_Length_Specification(m_cipher_keylen + m_mac_keylen); } void TLS_CBC_HMAC_AEAD_Mode::key_schedule(const uint8_t key[], size_t keylen) { // Both keys are of fixed length specified by the ciphersuite if(keylen != m_cipher_keylen + m_mac_keylen) throw Invalid_Key_Length(name(), keylen); mac().set_key(&key[0], m_mac_keylen); cbc().set_key(&key[m_mac_keylen], m_cipher_keylen); } void TLS_CBC_HMAC_AEAD_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) { throw Invalid_IV_Length(name(), nonce_len); } m_msg.clear(); if(nonce_len > 0) { m_cbc_state.assign(nonce, nonce + nonce_len); } } size_t TLS_CBC_HMAC_AEAD_Mode::process(uint8_t buf[], size_t sz) { m_msg.insert(m_msg.end(), buf, buf + sz); return 0; } std::vector TLS_CBC_HMAC_AEAD_Mode::assoc_data_with_len(uint16_t len) { std::vector ad = m_ad; BOTAN_ASSERT(ad.size() == 13, "Expected AAD size"); ad[11] = get_byte(0, len); ad[12] = get_byte(1, len); return ad; } void TLS_CBC_HMAC_AEAD_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) { if(ad_len != 13) throw Invalid_Argument("Invalid TLS AEAD associated data length"); m_ad.assign(ad, ad + ad_len); } void TLS_CBC_HMAC_AEAD_Encryption::set_associated_data(const uint8_t ad[], size_t ad_len) { TLS_CBC_HMAC_AEAD_Mode::set_associated_data(ad, ad_len); if(use_encrypt_then_mac()) { // AAD hack for EtM // EtM uses ciphertext size instead of plaintext size for AEAD input const uint16_t pt_size = make_uint16(assoc_data()[11], assoc_data()[12]); const uint16_t enc_size = static_cast(round_up(iv_size() + pt_size + 1, block_size())); assoc_data()[11] = get_byte(0, enc_size); assoc_data()[12] = get_byte(1, enc_size); } } void TLS_CBC_HMAC_AEAD_Encryption::cbc_encrypt_record( secure_vector& buffer, size_t offset, size_t padding_length) { // We always do short padding: BOTAN_ASSERT_NOMSG(padding_length <= 16); buffer.resize(buffer.size() + padding_length); const uint8_t padding_val = static_cast(padding_length - 1); CT::poison(&padding_val, 1); CT::poison(&padding_length, 1); CT::poison(buffer.data(), buffer.size()); const size_t last_block_starts = buffer.size() - block_size(); const size_t padding_starts = buffer.size() - padding_length; for(size_t i = last_block_starts; i != buffer.size(); ++i) { auto add_padding = CT::Mask(CT::Mask::is_gte(i, padding_starts)); buffer[i] = add_padding.select(padding_val, buffer[i]); } CT::unpoison(padding_val); CT::unpoison(padding_length); CT::unpoison(buffer.data(), buffer.size()); cbc().start(cbc_state()); cbc().process(&buffer[offset], buffer.size() - offset); cbc_state().assign(buffer.data() + (buffer.size() - block_size()), buffer.data() + buffer.size()); } size_t TLS_CBC_HMAC_AEAD_Encryption::output_length(size_t input_length) const { return round_up(input_length + 1 + (use_encrypt_then_mac() ? 0 : tag_size()), block_size()) + (use_encrypt_then_mac() ? tag_size() : 0); } void TLS_CBC_HMAC_AEAD_Encryption::finish(secure_vector& buffer, size_t offset) { update(buffer, offset); const size_t msg_size = msg().size(); const size_t input_size = msg_size + 1 + (use_encrypt_then_mac() ? 0 : tag_size()); const size_t enc_size = round_up(input_size, block_size()); BOTAN_DEBUG_ASSERT(enc_size % block_size() == 0); const uint8_t padding_val = static_cast(enc_size - input_size); const size_t padding_length = static_cast(padding_val) + 1; buffer.reserve(offset + msg_size + padding_length + tag_size()); buffer.resize(offset + msg_size); copy_mem(&buffer[offset], msg().data(), msg_size); mac().update(assoc_data()); if(use_encrypt_then_mac()) { if(iv_size() > 0) { mac().update(cbc_state()); } cbc_encrypt_record(buffer, offset, padding_length); mac().update(&buffer[offset], enc_size); buffer.resize(buffer.size() + tag_size()); mac().final(&buffer[buffer.size() - tag_size()]); } else { mac().update(&buffer[offset], msg_size); buffer.resize(buffer.size() + tag_size()); mac().final(&buffer[buffer.size() - tag_size()]); cbc_encrypt_record(buffer, offset, padding_length); } } /* * Checks the TLS padding. Returns 0 if the padding is invalid (we * count the padding_length field as part of the padding size so a * valid padding will always be at least one byte long), or the length * of the padding otherwise. This is actually padding_length + 1 * because both the padding and padding_length fields are padding from * our perspective. * * Returning 0 in the error case should ensure the MAC check will fail. * This approach is suggested in section 6.2.3.2 of RFC 5246. */ uint16_t check_tls_cbc_padding(const uint8_t record[], size_t record_len) { if(record_len == 0 || record_len > 0xFFFF) return 0; const uint16_t rec16 = static_cast(record_len); /* * TLS v1.0 and up require all the padding bytes be the same value * and allows up to 255 bytes. */ const uint16_t to_check = std::min(256, static_cast(record_len)); const uint8_t pad_byte = record[record_len-1]; const uint16_t pad_bytes = 1 + pad_byte; auto pad_invalid = CT::Mask::is_lt(rec16, pad_bytes); for(uint16_t i = rec16 - to_check; i != rec16; ++i) { const uint16_t offset = rec16 - i; const auto in_pad_range = CT::Mask::is_lte(offset, pad_bytes); const auto pad_correct = CT::Mask::is_equal(record[i], pad_byte); pad_invalid |= in_pad_range & ~pad_correct; } return pad_invalid.if_not_set_return(pad_bytes); } void TLS_CBC_HMAC_AEAD_Decryption::cbc_decrypt_record(uint8_t record_contents[], size_t record_len) { if(record_len == 0 || record_len % block_size() != 0) throw Decoding_Error("Received TLS CBC ciphertext with invalid length"); cbc().start(cbc_state()); cbc_state().assign(record_contents + record_len - block_size(), record_contents + record_len); cbc().process(record_contents, record_len); } size_t TLS_CBC_HMAC_AEAD_Decryption::output_length(size_t) const { /* * We don't know this because the padding is arbitrary */ return 0; } /* * This function performs additional compression calls in order * to protect from the Lucky 13 attack. It adds new compression * function calls over dummy data, by computing additional HMAC updates. * * The countermeasure was described (in a similar way) in the Lucky 13 paper. * * Background: * - One SHA-1/SHA-256 compression is performed with 64 bytes of data. * - HMAC adds 8 byte length field and padding (at least 1 byte) so that we have: * - 0 - 55 bytes: 1 compression * - 56 - 55+64 bytes: 2 compressions * - 56+64 - 55+2*64 bytes: 3 compressions ... * - For SHA-384, this works similarly, but we have 128 byte blocks and 16 byte * long length field. This results in: * - 0 - 111 bytes: 1 compression * - 112 - 111+128 bytes: 2 compressions ... * * The implemented countermeasure works as follows: * 1) It computes max_compressions: number of maximum compressions performed on * the decrypted data * 2) It computes current_compressions: number of compressions performed on the * decrypted data, after padding has been removed * 3) If current_compressions != max_compressions: It invokes an HMAC update * over dummy data so that (max_compressions - current_compressions) * compressions are performed. Otherwise, it invokes an HMAC update so that * no compressions are performed. * * Note that the padding validation in Botan is always performed over * min(plen,256) bytes, see the function check_tls_cbc_padding. This differs * from the countermeasure described in the paper. * * Note that the padding length padlen does also count the last byte * of the decrypted plaintext. This is different from the Lucky 13 paper. * * This countermeasure leaves a difference of about 100 clock cycles (in * comparison to >1000 clock cycles observed without it). * * plen represents the length of the decrypted plaintext message P * padlen represents the padding length * */ void TLS_CBC_HMAC_AEAD_Decryption::perform_additional_compressions(size_t plen, size_t padlen) { uint16_t block_size; uint16_t max_bytes_in_first_block; if(mac().name() == "HMAC(SHA-384)") { block_size = 128; max_bytes_in_first_block = 111; } else { block_size = 64; max_bytes_in_first_block = 55; } // number of maximum MACed bytes const uint16_t L1 = static_cast(13 + plen - tag_size()); // number of current MACed bytes (L1 - padlen) // Here the Lucky 13 paper is different because the padlen length in the paper // does not count the last message byte. const uint16_t L2 = static_cast(13 + plen - padlen - tag_size()); // From the paper, for SHA-256/SHA-1 compute: ceil((L1-55)/64) and ceil((L2-55)/64) // ceil((L1-55)/64) = floor((L1+64-1-55)/64) // Here we compute number of compressions for SHA-* in general const uint16_t max_compresssions = ( (L1 + block_size - 1 - max_bytes_in_first_block) / block_size); const uint16_t current_compressions = ((L2 + block_size - 1 - max_bytes_in_first_block) / block_size); // number of additional compressions we have to perform const uint16_t add_compressions = max_compresssions - current_compressions; const uint16_t equal = CT::Mask::is_equal(max_compresssions, current_compressions).if_set_return(1); // We compute the data length we need to achieve the number of compressions. // If there are no compressions, we just add 55/111 dummy bytes so that no // compression is performed. const uint16_t data_len = block_size * add_compressions + equal * max_bytes_in_first_block; std::vector data(data_len); mac().update(data); // we do not need to clear the MAC since the connection is broken anyway } void TLS_CBC_HMAC_AEAD_Decryption::finish(secure_vector& buffer, size_t offset) { update(buffer, offset); buffer.resize(offset); const size_t record_len = msg().size(); uint8_t* record_contents = msg().data(); // This early exit does not leak info because all the values compared are public if(record_len < tag_size() || (record_len - (use_encrypt_then_mac() ? tag_size() : 0)) % block_size() != 0) { throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); } if(use_encrypt_then_mac()) { const size_t enc_size = record_len - tag_size(); const size_t enc_iv_size = enc_size + iv_size(); BOTAN_ASSERT_NOMSG(enc_iv_size <= 0xFFFF); mac().update(assoc_data_with_len(static_cast(enc_iv_size))); if(iv_size() > 0) { mac().update(cbc_state()); } mac().update(record_contents, enc_size); std::vector mac_buf(tag_size()); mac().final(mac_buf.data()); const size_t mac_offset = enc_size; const bool mac_ok = constant_time_compare(&record_contents[mac_offset], mac_buf.data(), tag_size()); if(!mac_ok) { throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); } cbc_decrypt_record(record_contents, enc_size); // 0 if padding was invalid, otherwise 1 + padding_bytes const uint16_t pad_size = check_tls_cbc_padding(record_contents, enc_size); // No oracle here, whoever sent us this had the key since MAC check passed if(pad_size == 0) { throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); } const uint8_t* plaintext_block = &record_contents[0]; const size_t plaintext_length = enc_size - pad_size; buffer.insert(buffer.end(), plaintext_block, plaintext_block + plaintext_length); } else { cbc_decrypt_record(record_contents, record_len); CT::poison(record_contents, record_len); // 0 if padding was invalid, otherwise 1 + padding_bytes uint16_t pad_size = check_tls_cbc_padding(record_contents, record_len); /* This mask is zero if there is not enough room in the packet to get a valid MAC. We have to accept empty packets, since otherwise we are not compatible with how OpenSSL's countermeasure for fixing BEAST in TLS 1.0 CBC works (sending empty records, instead of 1/(n-1) splitting) */ // We know the cast cannot overflow as pad_size <= 256 && tag_size <= 32 const auto size_ok_mask = CT::Mask::is_lte( static_cast(tag_size() + pad_size), static_cast(record_len)); pad_size = size_ok_mask.if_set_return(pad_size); CT::unpoison(record_contents, record_len); /* This is unpoisoned sooner than it should. The pad_size leaks to plaintext_length and then to the timing channel in the MAC computation described in the Lucky 13 paper. */ CT::unpoison(pad_size); const uint8_t* plaintext_block = &record_contents[0]; const uint16_t plaintext_length = static_cast(record_len - tag_size() - pad_size); mac().update(assoc_data_with_len(plaintext_length)); mac().update(plaintext_block, plaintext_length); std::vector mac_buf(tag_size()); mac().final(mac_buf.data()); const size_t mac_offset = record_len - (tag_size() + pad_size); const bool mac_ok = constant_time_compare(&record_contents[mac_offset], mac_buf.data(), tag_size()); const auto ok_mask = size_ok_mask & CT::Mask::expand(mac_ok) & CT::Mask::expand(pad_size); CT::unpoison(ok_mask); if(ok_mask.is_set()) { buffer.insert(buffer.end(), plaintext_block, plaintext_block + plaintext_length); } else { perform_additional_compressions(record_len, pad_size); /* * In DTLS case we have to finish computing the MAC since we require the * MAC state be reset for future packets. This extra timing channel may * be exploitable in a Lucky13 variant. */ if(is_datagram_protocol()) mac().final(mac_buf); throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); } } } } } /* * RTSS (threshold secret sharing) * (C) 2009,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { const size_t RTSS_HEADER_SIZE = 20; /** Table for GF(2^8) arithmetic (exponentials) */ const uint8_t RTSS_EXP[256] = { 0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35, 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA, 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31, 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD, 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88, 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A, 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3, 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0, 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41, 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75, 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80, 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54, 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA, 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E, 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17, 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01 }; /** Table for GF(2^8) arithmetic (logarithms) */ const uint8_t RTSS_LOG[] = { 0x90, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, 0x68, 0x33, 0xEE, 0xDF, 0x03, 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, 0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1, 0x7D, 0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, 0x9A, 0xC9, 0x09, 0x78, 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, 0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E, 0x96, 0x8F, 0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, 0x46, 0x83, 0x38, 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, 0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10, 0x7E, 0x6E, 0x48, 0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, 0x3D, 0xBA, 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, 0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57, 0xAF, 0x58, 0xA8, 0x50, 0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, 0xE8, 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, 0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0, 0x7F, 0x0C, 0xF6, 0x6F, 0x17, 0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7, 0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, 0x6C, 0xAA, 0x55, 0x29, 0x9D, 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, 0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1, 0x53, 0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, 0x56, 0xF2, 0xD3, 0xAB, 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, 0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5, 0x67, 0x4A, 0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, 0xF7, 0x70, 0x07 }; uint8_t gfp_mul(uint8_t x, uint8_t y) { if(x == 0 || y == 0) return 0; return RTSS_EXP[(RTSS_LOG[x] + RTSS_LOG[y]) % 255]; } uint8_t rtss_hash_id(const std::string& hash_name) { if(hash_name == "None") return 0; else if(hash_name == "SHA-160" || hash_name == "SHA-1" || hash_name == "SHA1") return 1; else if(hash_name == "SHA-256") return 2; else throw Invalid_Argument("RTSS only supports SHA-1 and SHA-256"); } std::unique_ptr get_rtss_hash_by_id(uint8_t id) { if(id == 0) return std::unique_ptr(); if(id == 1) return HashFunction::create_or_throw("SHA-1"); else if(id == 2) return HashFunction::create_or_throw("SHA-256"); else throw Decoding_Error("Unknown RTSS hash identifier"); } } RTSS_Share::RTSS_Share(const std::string& hex_input) { m_contents = hex_decode_locked(hex_input); } RTSS_Share::RTSS_Share(const uint8_t bin[], size_t len) { m_contents.assign(bin, bin + len); } uint8_t RTSS_Share::share_id() const { if(!initialized()) throw Invalid_State("RTSS_Share::share_id not initialized"); if(m_contents.size() < RTSS_HEADER_SIZE + 1) throw Decoding_Error("RTSS_Share::share_id invalid share data"); return m_contents[20]; } std::string RTSS_Share::to_string() const { return hex_encode(m_contents.data(), m_contents.size()); } std::vector RTSS_Share::split(uint8_t M, uint8_t N, const uint8_t S[], uint16_t S_len, const uint8_t identifier[16], RandomNumberGenerator& rng) { return RTSS_Share::split(M, N, S, S_len, std::vector(identifier, identifier + 16), "SHA-256", rng); } std::vector RTSS_Share::split(uint8_t M, uint8_t N, const uint8_t S[], uint16_t S_len, const std::vector& identifier, const std::string& hash_fn, RandomNumberGenerator& rng) { if(M <= 1 || N <= 1 || M > N || N >= 255) throw Invalid_Argument("RTSS_Share::split: Invalid N or M"); if(identifier.size() > 16) throw Invalid_Argument("RTSS_Share::split Invalid identifier size"); const uint8_t hash_id = rtss_hash_id(hash_fn); std::unique_ptr hash; if(hash_id > 0) hash = HashFunction::create_or_throw(hash_fn); // secret = S || H(S) secure_vector secret(S, S + S_len); if(hash) secret += hash->process(S, S_len); if(secret.size() >= 0xFFFE) throw Encoding_Error("RTSS_Share::split secret too large for TSS format"); // +1 byte for the share ID const uint16_t share_len = static_cast(secret.size() + 1); secure_vector share_header(RTSS_HEADER_SIZE); copy_mem(&share_header[0], identifier.data(), identifier.size()); share_header[16] = hash_id; share_header[17] = M; share_header[18] = get_byte(0, share_len); share_header[19] = get_byte(1, share_len); // Create RTSS header in each share std::vector shares(N); for(uint8_t i = 0; i != N; ++i) { shares[i].m_contents.reserve(share_header.size() + share_len); shares[i].m_contents = share_header; } // Choose sequential values for X starting from 1 for(uint8_t i = 0; i != N; ++i) shares[i].m_contents.push_back(i+1); for(size_t i = 0; i != secret.size(); ++i) { std::vector coefficients(M-1); rng.randomize(coefficients.data(), coefficients.size()); for(uint8_t j = 0; j != N; ++j) { const uint8_t X = j + 1; uint8_t sum = secret[i]; uint8_t X_i = X; for(size_t k = 0; k != coefficients.size(); ++k) { sum ^= gfp_mul(X_i, coefficients[k]); X_i = gfp_mul(X_i, X); } shares[j].m_contents.push_back(sum); } } return shares; } secure_vector RTSS_Share::reconstruct(const std::vector& shares) { if(shares.size() <= 1) throw Decoding_Error("Insufficient shares to do TSS reconstruction"); for(size_t i = 0; i != shares.size(); ++i) { if(shares[i].size() < RTSS_HEADER_SIZE + 1) throw Decoding_Error("Missing or malformed RTSS header"); if(shares[i].share_id() == 0) throw Decoding_Error("Invalid (id = 0) RTSS share detected"); if(i > 0) { if(shares[i].size() != shares[0].size()) throw Decoding_Error("Different sized RTSS shares detected"); if(!same_mem(&shares[0].m_contents[0], &shares[i].m_contents[0], RTSS_HEADER_SIZE)) throw Decoding_Error("Different RTSS headers detected"); } } const uint8_t N = shares[0].m_contents[17]; if(shares.size() < N) throw Decoding_Error("Insufficient shares to do TSS reconstruction"); const uint16_t share_len = make_uint16(shares[0].m_contents[18], shares[0].m_contents[19]); const uint8_t hash_id = shares[0].m_contents[16]; std::unique_ptr hash(get_rtss_hash_by_id(hash_id)); const size_t hash_len = (hash ? hash->output_length() : 0); if(shares[0].size() != RTSS_HEADER_SIZE + share_len) { /* * This second (laxer) check accomodates a bug in TSS that was * fixed in 2.9.0 - previous versions used the length of the * *secret* here, instead of the length of the *share*, which is * precisely 1 + hash_len longer. */ if(shares[0].size() <= RTSS_HEADER_SIZE + 1 + hash_len) throw Decoding_Error("Bad RTSS length field in header"); } std::vector V(shares.size()); secure_vector recovered; for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i) { for(size_t j = 0; j != V.size(); ++j) V[j] = shares[j].m_contents[i]; uint8_t r = 0; for(size_t k = 0; k != shares.size(); ++k) { // L_i function: uint8_t r2 = 1; for(size_t l = 0; l != shares.size(); ++l) { if(k == l) continue; uint8_t share_k = shares[k].share_id(); uint8_t share_l = shares[l].share_id(); if(share_k == share_l) throw Decoding_Error("Duplicate shares found in RTSS recovery"); uint8_t div = RTSS_EXP[(255 + RTSS_LOG[share_l] - RTSS_LOG[share_k ^ share_l]) % 255]; r2 = gfp_mul(r2, div); } r ^= gfp_mul(V[k], r2); } recovered.push_back(r); } if(hash) { if(recovered.size() < hash->output_length()) throw Decoding_Error("RTSS recovered value too short to be valid"); const size_t secret_len = recovered.size() - hash->output_length(); hash->update(recovered.data(), secret_len); secure_vector hash_check = hash->final(); if(!constant_time_compare(hash_check.data(), &recovered[secret_len], hash->output_length())) { throw Decoding_Error("RTSS hash check failed"); } // remove the trailing hash value recovered.resize(secret_len); } return recovered; } } /* * Twofish * (C) 1999-2007,2017 Jack Lloyd * * The key schedule implemenation is based on a public domain * implementation by Matthew Skala * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { inline void TF_E(uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, uint32_t RK1, uint32_t RK2, const secure_vector& SB) { uint32_t X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; uint32_t Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; X += Y; Y += X; X += RK1; Y += RK2; C = rotr<1>(C ^ X); D = rotl<1>(D) ^ Y; } inline void TF_D(uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, uint32_t RK1, uint32_t RK2, const secure_vector& SB) { uint32_t X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; uint32_t Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; X += Y; Y += X; X += RK1; Y += RK2; C = rotl<1>(C) ^ X; D = rotr<1>(D ^ Y); } } /* * Twofish Encryption */ void Twofish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SB.empty() == false); while(blocks >= 2) { uint32_t A0, B0, C0, D0; uint32_t A1, B1, C1, D1; load_le(in, A0, B0, C0, D0, A1, B1, C1, D1); A0 ^= m_RK[0]; A1 ^= m_RK[0]; B0 ^= m_RK[1]; B1 ^= m_RK[1]; C0 ^= m_RK[2]; C1 ^= m_RK[2]; D0 ^= m_RK[3]; D1 ^= m_RK[3]; for(size_t k = 8; k != 40; k += 4) { TF_E(A0, B0, C0, D0, m_RK[k+0], m_RK[k+1], m_SB); TF_E(A1, B1, C1, D1, m_RK[k+0], m_RK[k+1], m_SB); TF_E(C0, D0, A0, B0, m_RK[k+2], m_RK[k+3], m_SB); TF_E(C1, D1, A1, B1, m_RK[k+2], m_RK[k+3], m_SB); } C0 ^= m_RK[4]; C1 ^= m_RK[4]; D0 ^= m_RK[5]; D1 ^= m_RK[5]; A0 ^= m_RK[6]; A1 ^= m_RK[6]; B0 ^= m_RK[7]; B1 ^= m_RK[7]; store_le(out, C0, D0, A0, B0, C1, D1, A1, B1); blocks -= 2; out += 2*BLOCK_SIZE; in += 2*BLOCK_SIZE; } if(blocks) { uint32_t A, B, C, D; load_le(in, A, B, C, D); A ^= m_RK[0]; B ^= m_RK[1]; C ^= m_RK[2]; D ^= m_RK[3]; for(size_t k = 8; k != 40; k += 4) { TF_E(A, B, C, D, m_RK[k ], m_RK[k+1], m_SB); TF_E(C, D, A, B, m_RK[k+2], m_RK[k+3], m_SB); } C ^= m_RK[4]; D ^= m_RK[5]; A ^= m_RK[6]; B ^= m_RK[7]; store_le(out, C, D, A, B); } } /* * Twofish Decryption */ void Twofish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_SB.empty() == false); while(blocks >= 2) { uint32_t A0, B0, C0, D0; uint32_t A1, B1, C1, D1; load_le(in, A0, B0, C0, D0, A1, B1, C1, D1); A0 ^= m_RK[4]; A1 ^= m_RK[4]; B0 ^= m_RK[5]; B1 ^= m_RK[5]; C0 ^= m_RK[6]; C1 ^= m_RK[6]; D0 ^= m_RK[7]; D1 ^= m_RK[7]; for(size_t k = 40; k != 8; k -= 4) { TF_D(A0, B0, C0, D0, m_RK[k-2], m_RK[k-1], m_SB); TF_D(A1, B1, C1, D1, m_RK[k-2], m_RK[k-1], m_SB); TF_D(C0, D0, A0, B0, m_RK[k-4], m_RK[k-3], m_SB); TF_D(C1, D1, A1, B1, m_RK[k-4], m_RK[k-3], m_SB); } C0 ^= m_RK[0]; C1 ^= m_RK[0]; D0 ^= m_RK[1]; D1 ^= m_RK[1]; A0 ^= m_RK[2]; A1 ^= m_RK[2]; B0 ^= m_RK[3]; B1 ^= m_RK[3]; store_le(out, C0, D0, A0, B0, C1, D1, A1, B1); blocks -= 2; out += 2*BLOCK_SIZE; in += 2*BLOCK_SIZE; } if(blocks) { uint32_t A, B, C, D; load_le(in, A, B, C, D); A ^= m_RK[4]; B ^= m_RK[5]; C ^= m_RK[6]; D ^= m_RK[7]; for(size_t k = 40; k != 8; k -= 4) { TF_D(A, B, C, D, m_RK[k-2], m_RK[k-1], m_SB); TF_D(C, D, A, B, m_RK[k-4], m_RK[k-3], m_SB); } C ^= m_RK[0]; D ^= m_RK[1]; A ^= m_RK[2]; B ^= m_RK[3]; store_le(out, C, D, A, B); } } /* * Twofish Key Schedule */ void Twofish::key_schedule(const uint8_t key[], size_t length) { m_SB.resize(1024); m_RK.resize(40); secure_vector S(16); for(size_t i = 0; i != length; ++i) { /* * Do one column of the RS matrix multiplcation */ if(key[i]) { uint8_t X = POLY_TO_EXP[key[i] - 1]; uint8_t RS1 = RS[(4*i ) % 32]; uint8_t RS2 = RS[(4*i+1) % 32]; uint8_t RS3 = RS[(4*i+2) % 32]; uint8_t RS4 = RS[(4*i+3) % 32]; S[4*(i/8) ] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; S[4*(i/8)+1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; S[4*(i/8)+2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; S[4*(i/8)+3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; } } if(length == 16) { for(size_t i = 0; i != 256; ++i) { m_SB[ i] = MDS0[Q0[Q0[i]^S[ 0]]^S[ 4]]; m_SB[256+i] = MDS1[Q0[Q1[i]^S[ 1]]^S[ 5]]; m_SB[512+i] = MDS2[Q1[Q0[i]^S[ 2]]^S[ 6]]; m_SB[768+i] = MDS3[Q1[Q1[i]^S[ 3]]^S[ 7]]; } for(size_t i = 0; i < 40; i += 2) { uint32_t X = MDS0[Q0[Q0[i ]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[i ]^key[ 9]]^key[ 1]] ^ MDS2[Q1[Q0[i ]^key[10]]^key[ 2]] ^ MDS3[Q1[Q1[i ]^key[11]]^key[ 3]]; uint32_t Y = MDS0[Q0[Q0[i+1]^key[12]]^key[ 4]] ^ MDS1[Q0[Q1[i+1]^key[13]]^key[ 5]] ^ MDS2[Q1[Q0[i+1]^key[14]]^key[ 6]] ^ MDS3[Q1[Q1[i+1]^key[15]]^key[ 7]]; Y = rotl<8>(Y); X += Y; Y += X; m_RK[i] = X; m_RK[i+1] = rotl<9>(Y); } } else if(length == 24) { for(size_t i = 0; i != 256; ++i) { m_SB[ i] = MDS0[Q0[Q0[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]; m_SB[256+i] = MDS1[Q0[Q1[Q1[i]^S[ 1]]^S[ 5]]^S[ 9]]; m_SB[512+i] = MDS2[Q1[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]; m_SB[768+i] = MDS3[Q1[Q1[Q0[i]^S[ 3]]^S[ 7]]^S[11]]; } for(size_t i = 0; i < 40; i += 2) { uint32_t X = MDS0[Q0[Q0[Q1[i ]^key[16]]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[Q1[i ]^key[17]]^key[ 9]]^key[ 1]] ^ MDS2[Q1[Q0[Q0[i ]^key[18]]^key[10]]^key[ 2]] ^ MDS3[Q1[Q1[Q0[i ]^key[19]]^key[11]]^key[ 3]]; uint32_t Y = MDS0[Q0[Q0[Q1[i+1]^key[20]]^key[12]]^key[ 4]] ^ MDS1[Q0[Q1[Q1[i+1]^key[21]]^key[13]]^key[ 5]] ^ MDS2[Q1[Q0[Q0[i+1]^key[22]]^key[14]]^key[ 6]] ^ MDS3[Q1[Q1[Q0[i+1]^key[23]]^key[15]]^key[ 7]]; Y = rotl<8>(Y); X += Y; Y += X; m_RK[i] = X; m_RK[i+1] = rotl<9>(Y); } } else if(length == 32) { for(size_t i = 0; i != 256; ++i) { m_SB[ i] = MDS0[Q0[Q0[Q1[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]^S[12]]; m_SB[256+i] = MDS1[Q0[Q1[Q1[Q0[i]^S[ 1]]^S[ 5]]^S[ 9]]^S[13]]; m_SB[512+i] = MDS2[Q1[Q0[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]^S[14]]; m_SB[768+i] = MDS3[Q1[Q1[Q0[Q1[i]^S[ 3]]^S[ 7]]^S[11]]^S[15]]; } for(size_t i = 0; i < 40; i += 2) { uint32_t X = MDS0[Q0[Q0[Q1[Q1[i ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[Q1[Q0[i ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^ MDS2[Q1[Q0[Q0[Q0[i ]^key[26]]^key[18]]^key[10]]^key[ 2]] ^ MDS3[Q1[Q1[Q0[Q1[i ]^key[27]]^key[19]]^key[11]]^key[ 3]]; uint32_t Y = MDS0[Q0[Q0[Q1[Q1[i+1]^key[28]]^key[20]]^key[12]]^key[ 4]] ^ MDS1[Q0[Q1[Q1[Q0[i+1]^key[29]]^key[21]]^key[13]]^key[ 5]] ^ MDS2[Q1[Q0[Q0[Q0[i+1]^key[30]]^key[22]]^key[14]]^key[ 6]] ^ MDS3[Q1[Q1[Q0[Q1[i+1]^key[31]]^key[23]]^key[15]]^key[ 7]]; Y = rotl<8>(Y); X += Y; Y += X; m_RK[i] = X; m_RK[i+1] = rotl<9>(Y); } } } /* * Clear memory of sensitive data */ void Twofish::clear() { zap(m_SB); zap(m_RK); } } /* * S-Box and MDS Tables for Twofish * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { alignas(64) const uint8_t Twofish::Q0[256] = { 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 }; alignas(64) const uint8_t Twofish::Q1[256] = { 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 }; alignas(64) const uint8_t Twofish::RS[32] = { 0x01, 0xA4, 0x02, 0xA4, 0xA4, 0x56, 0xA1, 0x55, 0x55, 0x82, 0xFC, 0x87, 0x87, 0xF3, 0xC1, 0x5A, 0x5A, 0x1E, 0x47, 0x58, 0x58, 0xC6, 0xAE, 0xDB, 0xDB, 0x68, 0x3D, 0x9E, 0x9E, 0xE5, 0x19, 0x03 }; alignas(64) const uint8_t Twofish::EXP_TO_POLY[255] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB, 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1, 0x8F, 0x53, 0xA6 }; alignas(64) const uint8_t Twofish::POLY_TO_EXP[255] = { 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19, 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A, 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C, 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B, 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47, 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D, 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8, 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C, 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83, 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48, 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26, 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E, 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3, 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9, 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A, 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D, 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75, 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84, 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64, 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49, 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF, 0x85, 0xC8, 0xA1 }; alignas(64) const uint32_t Twofish::MDS0[256] = { 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 }; alignas(64) const uint32_t Twofish::MDS1[256] = { 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 }; alignas(64) const uint32_t Twofish::MDS2[256] = { 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF }; alignas(64) const uint32_t Twofish::MDS3[256] = { 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 }; } /* * Runtime assertion checking * (C) 2010,2012,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void throw_invalid_argument(const char* message, const char* func, const char* file) { std::ostringstream format; format << message << " in " << func << ":" << file; throw Invalid_Argument(format.str()); } void throw_invalid_state(const char* expr, const char* func, const char* file) { std::ostringstream format; format << "Invalid state: " << expr << " was false in " << func << ":" << file; throw Invalid_State(format.str()); } void assertion_failure(const char* expr_str, const char* assertion_made, const char* func, const char* file, int line) { std::ostringstream format; format << "False assertion "; if(assertion_made && assertion_made[0] != 0) format << "'" << assertion_made << "' (expression " << expr_str << ") "; else format << expr_str << " "; if(func) format << "in " << func << " "; format << "@" << file << ":" << line; throw Internal_Error(format.str()); } } /* * Calendar Functions * (C) 1999-2010,2017 Jack Lloyd * (C) 2015 Simon Warta (Kullo GmbH) * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include namespace Botan { namespace { std::tm do_gmtime(std::time_t time_val) { std::tm tm; #if defined(BOTAN_TARGET_OS_HAS_WIN32) ::gmtime_s(&tm, &time_val); // Windows #elif defined(BOTAN_TARGET_OS_HAS_POSIX1) ::gmtime_r(&time_val, &tm); // Unix/SUSv2 #else std::tm* tm_p = std::gmtime(&time_val); if (tm_p == nullptr) throw Encoding_Error("time_t_to_tm could not convert"); tm = *tm_p; #endif return tm; } /* Portable replacement for timegm, _mkgmtime, etc Algorithm due to Howard Hinnant See https://howardhinnant.github.io/date_algorithms.html#days_from_civil for details and explaination. The code is slightly simplified by our assumption that the date is at least 1970, which is sufficient for our purposes. */ size_t days_since_epoch(uint32_t year, uint32_t month, uint32_t day) { if(month <= 2) year -= 1; const uint32_t era = year / 400; const uint32_t yoe = year - era * 400; // [0, 399] const uint32_t doy = (153*(month + (month > 2 ? -3 : 9)) + 2)/5 + day-1; // [0, 365] const uint32_t doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] return era * 146097 + doe - 719468; } } std::chrono::system_clock::time_point calendar_point::to_std_timepoint() const { if(get_year() < 1970) throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years before 1970"); // 32 bit time_t ends at January 19, 2038 // https://msdn.microsoft.com/en-us/library/2093ets1.aspx // Throw after 2037 if 32 bit time_t is used BOTAN_IF_CONSTEXPR(sizeof(std::time_t) == 4) { if(get_year() > 2037) { throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2037 on this system"); } } // This upper bound is completely arbitrary if(get_year() >= 2400) { throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2400"); } const uint64_t seconds_64 = (days_since_epoch(get_year(), get_month(), get_day()) * 86400) + (get_hour() * 60 * 60) + (get_minutes() * 60) + get_seconds(); const time_t seconds_time_t = static_cast(seconds_64); if(seconds_64 - seconds_time_t != 0) { throw Invalid_Argument("calendar_point::to_std_timepoint time_t overflow"); } return std::chrono::system_clock::from_time_t(seconds_time_t); } std::string calendar_point::to_string() const { // desired format: --
T:: std::stringstream output; output << std::setfill('0') << std::setw(4) << get_year() << "-" << std::setw(2) << get_month() << "-" << std::setw(2) << get_day() << "T" << std::setw(2) << get_hour() << ":" << std::setw(2) << get_minutes() << ":" << std::setw(2) << get_seconds(); return output.str(); } calendar_point calendar_value( const std::chrono::system_clock::time_point& time_point) { std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point)); return calendar_point(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } } /* * Character Set Handling * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { void append_utf8_for(std::string& s, uint32_t c) { if(c >= 0xD800 && c < 0xE000) throw Decoding_Error("Invalid Unicode character"); if(c <= 0x7F) { const uint8_t b0 = static_cast(c); s.push_back(static_cast(b0)); } else if(c <= 0x7FF) { const uint8_t b0 = 0xC0 | static_cast(c >> 6); const uint8_t b1 = 0x80 | static_cast(c & 0x3F); s.push_back(static_cast(b0)); s.push_back(static_cast(b1)); } else if(c <= 0xFFFF) { const uint8_t b0 = 0xE0 | static_cast(c >> 12); const uint8_t b1 = 0x80 | static_cast((c >> 6) & 0x3F); const uint8_t b2 = 0x80 | static_cast(c & 0x3F); s.push_back(static_cast(b0)); s.push_back(static_cast(b1)); s.push_back(static_cast(b2)); } else if(c <= 0x10FFFF) { const uint8_t b0 = 0xF0 | static_cast(c >> 18); const uint8_t b1 = 0x80 | static_cast((c >> 12) & 0x3F); const uint8_t b2 = 0x80 | static_cast((c >> 6) & 0x3F); const uint8_t b3 = 0x80 | static_cast(c & 0x3F); s.push_back(static_cast(b0)); s.push_back(static_cast(b1)); s.push_back(static_cast(b2)); s.push_back(static_cast(b3)); } else throw Decoding_Error("Invalid Unicode character"); } } std::string ucs2_to_utf8(const uint8_t ucs2[], size_t len) { if(len % 2 != 0) throw Decoding_Error("Invalid length for UCS-2 string"); const size_t chars = len / 2; std::string s; for(size_t i = 0; i != chars; ++i) { const uint16_t c = load_be(ucs2, i); append_utf8_for(s, c); } return s; } std::string ucs4_to_utf8(const uint8_t ucs4[], size_t len) { if(len % 4 != 0) throw Decoding_Error("Invalid length for UCS-4 string"); const size_t chars = len / 4; std::string s; for(size_t i = 0; i != chars; ++i) { const uint32_t c = load_be(ucs4, i); append_utf8_for(s, c); } return s; } /* * Convert from UTF-8 to ISO 8859-1 */ std::string utf8_to_latin1(const std::string& utf8) { std::string iso8859; size_t position = 0; while(position != utf8.size()) { const uint8_t c1 = static_cast(utf8[position++]); if(c1 <= 0x7F) { iso8859 += static_cast(c1); } else if(c1 >= 0xC0 && c1 <= 0xC7) { if(position == utf8.size()) throw Decoding_Error("UTF-8: sequence truncated"); const uint8_t c2 = static_cast(utf8[position++]); const uint8_t iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F); if(iso_char <= 0x7F) throw Decoding_Error("UTF-8: sequence longer than needed"); iso8859 += static_cast(iso_char); } else throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used"); } return iso8859; } namespace Charset { namespace { /* * Convert from UCS-2 to ISO 8859-1 */ std::string ucs2_to_latin1(const std::string& ucs2) { if(ucs2.size() % 2 == 1) throw Decoding_Error("UCS-2 string has an odd number of bytes"); std::string latin1; for(size_t i = 0; i != ucs2.size(); i += 2) { const uint8_t c1 = ucs2[i]; const uint8_t c2 = ucs2[i+1]; if(c1 != 0) throw Decoding_Error("UCS-2 has non-Latin1 characters"); latin1 += static_cast(c2); } return latin1; } /* * Convert from ISO 8859-1 to UTF-8 */ std::string latin1_to_utf8(const std::string& iso8859) { std::string utf8; for(size_t i = 0; i != iso8859.size(); ++i) { const uint8_t c = static_cast(iso8859[i]); if(c <= 0x7F) utf8 += static_cast(c); else { utf8 += static_cast((0xC0 | (c >> 6))); utf8 += static_cast((0x80 | (c & 0x3F))); } } return utf8; } } /* * Perform character set transcoding */ std::string transcode(const std::string& str, Character_Set to, Character_Set from) { if(to == LOCAL_CHARSET) to = LATIN1_CHARSET; if(from == LOCAL_CHARSET) from = LATIN1_CHARSET; if(to == from) return str; if(from == LATIN1_CHARSET && to == UTF8_CHARSET) return latin1_to_utf8(str); if(from == UTF8_CHARSET && to == LATIN1_CHARSET) return utf8_to_latin1(str); if(from == UCS2_CHARSET && to == LATIN1_CHARSET) return ucs2_to_latin1(str); throw Invalid_Argument("Unknown transcoding operation from " + std::to_string(from) + " to " + std::to_string(to)); } /* * Check if a character represents a digit */ bool is_digit(char c) { if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9') return true; return false; } /* * Check if a character represents whitespace */ bool is_space(char c) { if(c == ' ' || c == '\t' || c == '\n' || c == '\r') return true; return false; } /* * Convert a character to a digit */ uint8_t char2digit(char c) { switch(c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; } throw Invalid_Argument("char2digit: Input is not a digit character"); } /* * Convert a digit to a character */ char digit2char(uint8_t b) { switch(b) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; } throw Invalid_Argument("digit2char: Input is not a digit"); } /* * Case-insensitive character comparison */ bool caseless_cmp(char a, char b) { return (std::tolower(static_cast(a)) == std::tolower(static_cast(b))); } } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace CT { secure_vector copy_output(CT::Mask bad_input, const uint8_t input[], size_t input_length, size_t offset) { if(input_length == 0) return secure_vector(); /* * Ensure at runtime that offset <= input_length. This is an invalid input, * but we can't throw without using the poisoned value. Instead, if it happens, * set offset to be equal to the input length (so output_bytes becomes 0 and * the returned vector is empty) */ const auto valid_offset = CT::Mask::is_lte(offset, input_length); offset = valid_offset.select(offset, input_length); const size_t output_bytes = input_length - offset; secure_vector output(input_length); /* Move the desired output bytes to the front using a slow (O^n) but constant time loop that does not leak the value of the offset */ for(size_t i = 0; i != input_length; ++i) { /* start index from i rather than 0 since we know j must be >= i + offset to have any effect, and starting from i does not reveal information */ for(size_t j = i; j != input_length; ++j) { const uint8_t b = input[j]; const auto is_eq = CT::Mask::is_equal(j, offset + i); output[i] |= is_eq.if_set_return(b); } } bad_input.if_set_zero_out(output.data(), output.size()); CT::unpoison(output.data(), output.size()); CT::unpoison(output_bytes); /* This is potentially not const time, depending on how std::vector is implemented. But since we are always reducing length, it should just amount to setting the member var holding the length. */ output.resize(output_bytes); return output; } secure_vector strip_leading_zeros(const uint8_t in[], size_t length) { size_t leading_zeros = 0; auto only_zeros = Mask::set(); for(size_t i = 0; i != length; ++i) { only_zeros &= CT::Mask::is_zero(in[i]); leading_zeros += only_zeros.if_set_return(1); } return copy_output(CT::Mask::cleared(), in, length, leading_zeros); } } } /* * DataSource * (C) 1999-2007 Jack Lloyd * 2005 Matthew Gregan * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) #include #endif namespace Botan { /* * Read a single byte from the DataSource */ size_t DataSource::read_byte(uint8_t& out) { return read(&out, 1); } /* * Peek a single byte from the DataSource */ size_t DataSource::peek_byte(uint8_t& out) const { return peek(&out, 1, 0); } /* * Discard the next N bytes of the data */ size_t DataSource::discard_next(size_t n) { uint8_t buf[64] = { 0 }; size_t discarded = 0; while(n) { const size_t got = this->read(buf, std::min(n, sizeof(buf))); discarded += got; n -= got; if(got == 0) break; } return discarded; } /* * Read from a memory buffer */ size_t DataSource_Memory::read(uint8_t out[], size_t length) { const size_t got = std::min(m_source.size() - m_offset, length); copy_mem(out, m_source.data() + m_offset, got); m_offset += got; return got; } bool DataSource_Memory::check_available(size_t n) { return (n <= (m_source.size() - m_offset)); } /* * Peek into a memory buffer */ size_t DataSource_Memory::peek(uint8_t out[], size_t length, size_t peek_offset) const { const size_t bytes_left = m_source.size() - m_offset; if(peek_offset >= bytes_left) return 0; const size_t got = std::min(bytes_left - peek_offset, length); copy_mem(out, &m_source[m_offset + peek_offset], got); return got; } /* * Check if the memory buffer is empty */ bool DataSource_Memory::end_of_data() const { return (m_offset == m_source.size()); } /* * DataSource_Memory Constructor */ DataSource_Memory::DataSource_Memory(const std::string& in) : m_source(cast_char_ptr_to_uint8(in.data()), cast_char_ptr_to_uint8(in.data()) + in.length()), m_offset(0) { } /* * Read from a stream */ size_t DataSource_Stream::read(uint8_t out[], size_t length) { m_source.read(cast_uint8_ptr_to_char(out), length); if(m_source.bad()) throw Stream_IO_Error("DataSource_Stream::read: Source failure"); const size_t got = static_cast(m_source.gcount()); m_total_read += got; return got; } bool DataSource_Stream::check_available(size_t n) { const std::streampos orig_pos = m_source.tellg(); m_source.seekg(0, std::ios::end); const size_t avail = static_cast(m_source.tellg() - orig_pos); m_source.seekg(orig_pos); return (avail >= n); } /* * Peek into a stream */ size_t DataSource_Stream::peek(uint8_t out[], size_t length, size_t offset) const { if(end_of_data()) throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); size_t got = 0; if(offset) { secure_vector buf(offset); m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size()); if(m_source.bad()) throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); got = static_cast(m_source.gcount()); } if(got == offset) { m_source.read(cast_uint8_ptr_to_char(out), length); if(m_source.bad()) throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); got = static_cast(m_source.gcount()); } if(m_source.eof()) m_source.clear(); m_source.seekg(m_total_read, std::ios::beg); return got; } /* * Check if the stream is empty or in error */ bool DataSource_Stream::end_of_data() const { return (!m_source.good()); } /* * Return a human-readable ID for this stream */ std::string DataSource_Stream::id() const { return m_identifier; } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) /* * DataSource_Stream Constructor */ DataSource_Stream::DataSource_Stream(const std::string& path, bool use_binary) : m_identifier(path), m_source_memory(new std::ifstream(path, use_binary ? std::ios::binary : std::ios::in)), m_source(*m_source_memory), m_total_read(0) { if(!m_source.good()) { throw Stream_IO_Error("DataSource: Failure opening file " + path); } } #endif /* * DataSource_Stream Constructor */ DataSource_Stream::DataSource_Stream(std::istream& in, const std::string& name) : m_identifier(name), m_source(in), m_total_read(0) { } DataSource_Stream::~DataSource_Stream() { // for ~unique_ptr } } /* * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string to_string(ErrorType type) { switch(type) { case ErrorType::Unknown: return "Unknown"; case ErrorType::SystemError: return "SystemError"; case ErrorType::NotImplemented: return "NotImplemented"; case ErrorType::OutOfMemory: return "OutOfMemory"; case ErrorType::InternalError: return "InternalError"; case ErrorType::IoError: return "IoError"; case ErrorType::InvalidObjectState : return "InvalidObjectState"; case ErrorType::KeyNotSet: return "KeyNotSet"; case ErrorType::InvalidArgument: return "InvalidArgument"; case ErrorType::InvalidKeyLength: return "InvalidKeyLength"; case ErrorType::InvalidNonceLength: return "InvalidNonceLength"; case ErrorType::LookupError: return "LookupError"; case ErrorType::EncodingFailure: return "EncodingFailure"; case ErrorType::DecodingFailure: return "DecodingFailure"; case ErrorType::TLSError: return "TLSError"; case ErrorType::HttpError: return "HttpError"; case ErrorType::InvalidTag: return "InvalidTag"; case ErrorType::RoughtimeError: return "RoughtimeError"; case ErrorType::OpenSSLError : return "OpenSSLError"; case ErrorType::CommonCryptoError: return "CommonCryptoError"; case ErrorType::Pkcs11Error: return "Pkcs11Error"; case ErrorType::TPMError: return "TPMError"; case ErrorType::DatabaseError: return "DatabaseError"; case ErrorType::ZlibError : return "ZlibError"; case ErrorType::Bzip2Error: return "Bzip2Error" ; case ErrorType::LzmaError: return "LzmaError"; } // No default case in above switch so compiler warns return "Unrecognized Botan error"; } Exception::Exception(const std::string& msg) : m_msg(msg) {} Exception::Exception(const std::string& msg, const std::exception& e) : m_msg(msg + " failed with " + std::string(e.what())) {} Exception::Exception(const char* prefix, const std::string& msg) : m_msg(std::string(prefix) + " " + msg) {} Invalid_Argument::Invalid_Argument(const std::string& msg) : Exception(msg) {} Invalid_Argument::Invalid_Argument(const std::string& msg, const std::string& where) : Exception(msg + " in " + where) {} Invalid_Argument::Invalid_Argument(const std::string& msg, const std::exception& e) : Exception(msg, e) {} Lookup_Error::Lookup_Error(const std::string& type, const std::string& algo, const std::string& provider) : Exception("Unavailable " + type + " " + algo + (provider.empty() ? std::string("") : (" for provider " + provider))) {} Internal_Error::Internal_Error(const std::string& err) : Exception("Internal error: " + err) {} Invalid_Key_Length::Invalid_Key_Length(const std::string& name, size_t length) : Invalid_Argument(name + " cannot accept a key of length " + std::to_string(length)) {} Invalid_IV_Length::Invalid_IV_Length(const std::string& mode, size_t bad_len) : Invalid_Argument("IV length " + std::to_string(bad_len) + " is invalid for " + mode) {} Key_Not_Set::Key_Not_Set(const std::string& algo) : Invalid_State("Key not set in " + algo) {} Policy_Violation::Policy_Violation(const std::string& err) : Invalid_State("Policy violation: " + err) {} PRNG_Unseeded::PRNG_Unseeded(const std::string& algo) : Invalid_State("PRNG not seeded: " + algo) {} Algorithm_Not_Found::Algorithm_Not_Found(const std::string& name) : Lookup_Error("Could not find any algorithm named \"" + name + "\"") {} No_Provider_Found::No_Provider_Found(const std::string& name) : Exception("Could not find any provider for algorithm named \"" + name + "\"") {} Provider_Not_Found::Provider_Not_Found(const std::string& algo, const std::string& provider) : Lookup_Error("Could not find provider '" + provider + "' for " + algo) {} Invalid_Algorithm_Name::Invalid_Algorithm_Name(const std::string& name): Invalid_Argument("Invalid algorithm name: " + name) {} Encoding_Error::Encoding_Error(const std::string& name) : Invalid_Argument("Encoding error: " + name) {} Decoding_Error::Decoding_Error(const std::string& name) : Invalid_Argument(name) {} Decoding_Error::Decoding_Error(const std::string& msg, const std::exception& e) : Invalid_Argument(msg, e) {} Decoding_Error::Decoding_Error(const std::string& name, const char* exception_message) : Invalid_Argument(name + " failed with exception " + exception_message) {} Invalid_Authentication_Tag::Invalid_Authentication_Tag(const std::string& msg) : Exception("Invalid authentication tag: " + msg) {} Invalid_OID::Invalid_OID(const std::string& oid) : Decoding_Error("Invalid ASN.1 OID: " + oid) {} Stream_IO_Error::Stream_IO_Error(const std::string& err) : Exception("I/O error: " + err) {} System_Error::System_Error(const std::string& msg, int err_code) : Exception(msg + " error code " + std::to_string(err_code)), m_error_code(err_code) {} Self_Test_Failure::Self_Test_Failure(const std::string& err) : Internal_Error("Self test failed: " + err) {} Not_Implemented::Not_Implemented(const std::string& err) : Exception("Not implemented", err) {} } /* * (C) 2015,2017,2019 Jack Lloyd * (C) 2015 Simon Warta (Kullo GmbH) * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_TARGET_OS_HAS_POSIX1) #include #include #include #elif defined(BOTAN_TARGET_OS_HAS_WIN32) #define NOMINMAX 1 #define _WINSOCKAPI_ // stop windows.h including winsock.h #endif namespace Botan { namespace { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) std::vector impl_readdir(const std::string& dir_path) { std::vector out; std::deque dir_list; dir_list.push_back(dir_path); while(!dir_list.empty()) { const std::string cur_path = dir_list[0]; dir_list.pop_front(); std::unique_ptr> dir(::opendir(cur_path.c_str()), ::closedir); if(dir) { while(struct dirent* dirent = ::readdir(dir.get())) { const std::string filename = dirent->d_name; if(filename == "." || filename == "..") continue; const std::string full_path = cur_path + "/" + filename; struct stat stat_buf; if(::stat(full_path.c_str(), &stat_buf) == -1) continue; if(S_ISDIR(stat_buf.st_mode)) dir_list.push_back(full_path); else if(S_ISREG(stat_buf.st_mode)) out.push_back(full_path); } } } return out; } #elif defined(BOTAN_TARGET_OS_HAS_WIN32) std::vector impl_win32(const std::string& dir_path) { std::vector out; std::deque dir_list; dir_list.push_back(dir_path); while(!dir_list.empty()) { const std::string cur_path = dir_list[0]; dir_list.pop_front(); WIN32_FIND_DATAA find_data; HANDLE dir = ::FindFirstFileA((cur_path + "/*").c_str(), &find_data); if(dir != INVALID_HANDLE_VALUE) { do { const std::string filename = find_data.cFileName; if(filename == "." || filename == "..") continue; const std::string full_path = cur_path + "/" + filename; if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { dir_list.push_back(full_path); } else { out.push_back(full_path); } } while(::FindNextFileA(dir, &find_data)); } ::FindClose(dir); } return out; } #endif } bool has_filesystem_impl() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) return true; #elif defined(BOTAN_TARGET_OS_HAS_WIN32) return true; #else return false; #endif } std::vector get_files_recursive(const std::string& dir) { std::vector files; #if defined(BOTAN_TARGET_OS_HAS_POSIX1) files = impl_readdir(dir); #elif defined(BOTAN_TARGET_OS_HAS_WIN32) files = impl_win32(dir); #else BOTAN_UNUSED(dir); throw No_Filesystem_Access(); #endif std::sort(files.begin(), files.end()); return files; } } /* * (C) 2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) #endif namespace Botan { BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size) { if(elems == 0 || elem_size == 0) return nullptr; #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) if(void* p = mlock_allocator::instance().allocate(elems, elem_size)) return p; #endif void* ptr = std::calloc(elems, elem_size); if(!ptr) throw std::bad_alloc(); return ptr; } void deallocate_memory(void* p, size_t elems, size_t elem_size) { if(p == nullptr) return; secure_scrub_memory(p, elems * elem_size); #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) if(mlock_allocator::instance().deallocate(p, elems, elem_size)) return; #endif std::free(p); } void initialize_allocator() { #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) mlock_allocator::instance(); #endif } uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len) { volatile uint8_t difference = 0; for(size_t i = 0; i != len; ++i) difference |= (x[i] ^ y[i]); return CT::Mask::is_zero(difference).value(); } } /* * OS and machine specific utility functions * (C) 2015,2016,2017,2018 Jack Lloyd * (C) 2016 Daniel Neus * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_TARGET_OS_HAS_THREADS) #endif #if defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO) #include #endif #if defined(BOTAN_TARGET_OS_HAS_POSIX1) #include #include #include #include #include #include #include #include #undef B0 #endif #if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) #include #endif #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_IS_ANDROID) || \ defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) #include #endif #if defined(BOTAN_TARGET_OS_HAS_WIN32) #define NOMINMAX 1 #define _WINSOCKAPI_ // stop windows.h including winsock.h #endif #if defined(BOTAN_TARGET_OS_IS_ANDROID) #include extern "C" char **environ; #endif #if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS) #include #endif namespace Botan { // Not defined in OS namespace for historical reasons void secure_scrub_memory(void* ptr, size_t n) { #if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY) ::RtlSecureZeroMemory(ptr, n); #elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO) ::explicit_bzero(ptr, n); #elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_MEMSET) (void)::explicit_memset(ptr, 0, n); #elif defined(BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO) && (BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO == 1) /* Call memset through a static volatile pointer, which the compiler should not elide. This construct should be safe in conforming compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and Clang 3.8 both create code that saves the memset address in the data segment and unconditionally loads and jumps to that address. */ static void* (*const volatile memset_ptr)(void*, int, size_t) = std::memset; (memset_ptr)(ptr, 0, n); #else volatile uint8_t* p = reinterpret_cast(ptr); for(size_t i = 0; i != n; ++i) p[i] = 0; #endif } uint32_t OS::get_process_id() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) return ::getpid(); #elif defined(BOTAN_TARGET_OS_HAS_WIN32) return ::GetCurrentProcessId(); #elif defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM) || defined(BOTAN_TARGET_OS_IS_NONE) return 0; // truly no meaningful value #else #error "Missing get_process_id" #endif } unsigned long OS::get_auxval(unsigned long id) { #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) return ::getauxval(id); #elif defined(BOTAN_TARGET_OS_IS_ANDROID) && defined(BOTAN_TARGET_ARCH_IS_ARM32) if(id == 0) return 0; char **p = environ; while(*p++ != nullptr) ; Elf32_auxv_t *e = reinterpret_cast(p); while(e != nullptr) { if(e->a_type == id) return e->a_un.a_val; e++; } return 0; #elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) unsigned long auxinfo = 0; ::elf_aux_info(id, &auxinfo, sizeof(auxinfo)); return auxinfo; #else BOTAN_UNUSED(id); return 0; #endif } bool OS::running_in_privileged_state() { #if defined(AT_SECURE) return OS::get_auxval(AT_SECURE) != 0; #elif defined(BOTAN_TARGET_OS_HAS_POSIX1) return (::getuid() != ::geteuid()) || (::getgid() != ::getegid()); #else return false; #endif } uint64_t OS::get_cpu_cycle_counter() { uint64_t rtc = 0; #if defined(BOTAN_TARGET_OS_HAS_WIN32) LARGE_INTEGER tv; ::QueryPerformanceCounter(&tv); rtc = tv.QuadPart; #elif defined(BOTAN_USE_GCC_INLINE_ASM) #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) if(CPUID::has_rdtsc()) { uint32_t rtc_low = 0, rtc_high = 0; asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); rtc = (static_cast(rtc_high) << 32) | rtc_low; } #elif defined(BOTAN_TARGET_ARCH_IS_PPC64) for(;;) { uint32_t rtc_low = 0, rtc_high = 0, rtc_high2 = 0; asm volatile("mftbu %0" : "=r" (rtc_high)); asm volatile("mftb %0" : "=r" (rtc_low)); asm volatile("mftbu %0" : "=r" (rtc_high2)); if(rtc_high == rtc_high2) { rtc = (static_cast(rtc_high) << 32) | rtc_low; break; } } #elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) asm volatile("rpcc %0" : "=r" (rtc)); // OpenBSD does not trap access to the %tick register #elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) asm volatile("rd %%tick, %0" : "=r" (rtc)); #elif defined(BOTAN_TARGET_ARCH_IS_IA64) asm volatile("mov %0=ar.itc" : "=r" (rtc)); #elif defined(BOTAN_TARGET_ARCH_IS_S390X) asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc"); #elif defined(BOTAN_TARGET_ARCH_IS_HPPA) asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only? #else //#warning "OS::get_cpu_cycle_counter not implemented" #endif #endif return rtc; } size_t OS::get_cpu_total() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_CONF) const long res = ::sysconf(_SC_NPROCESSORS_CONF); if(res > 0) return static_cast(res); #endif #if defined(BOTAN_TARGET_OS_HAS_THREADS) return static_cast(std::thread::hardware_concurrency()); #else return 1; #endif } size_t OS::get_cpu_available() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN) const long res = ::sysconf(_SC_NPROCESSORS_ONLN); if(res > 0) return static_cast(res); #endif return OS::get_cpu_total(); } uint64_t OS::get_high_resolution_clock() { if(uint64_t cpu_clock = OS::get_cpu_cycle_counter()) return cpu_clock; #if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) return emscripten_get_now(); #endif /* If we got here either we either don't have an asm instruction above, or (for x86) RDTSC is not available at runtime. Try some clock_gettimes and return the first one that works, or otherwise fall back to std::chrono. */ #if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) // The ordering here is somewhat arbitrary... const clockid_t clock_types[] = { #if defined(CLOCK_MONOTONIC_HR) CLOCK_MONOTONIC_HR, #endif #if defined(CLOCK_MONOTONIC_RAW) CLOCK_MONOTONIC_RAW, #endif #if defined(CLOCK_MONOTONIC) CLOCK_MONOTONIC, #endif #if defined(CLOCK_PROCESS_CPUTIME_ID) CLOCK_PROCESS_CPUTIME_ID, #endif #if defined(CLOCK_THREAD_CPUTIME_ID) CLOCK_THREAD_CPUTIME_ID, #endif }; for(clockid_t clock : clock_types) { struct timespec ts; if(::clock_gettime(clock, &ts) == 0) { return (static_cast(ts.tv_sec) * 1000000000) + static_cast(ts.tv_nsec); } } #endif // Plain C++11 fallback auto now = std::chrono::high_resolution_clock::now().time_since_epoch(); return std::chrono::duration_cast(now).count(); } uint64_t OS::get_system_timestamp_ns() { #if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) struct timespec ts; if(::clock_gettime(CLOCK_REALTIME, &ts) == 0) { return (static_cast(ts.tv_sec) * 1000000000) + static_cast(ts.tv_nsec); } #endif auto now = std::chrono::system_clock::now().time_since_epoch(); return std::chrono::duration_cast(now).count(); } size_t OS::system_page_size() { const size_t default_page_size = 4096; #if defined(BOTAN_TARGET_OS_HAS_POSIX1) long p = ::sysconf(_SC_PAGESIZE); if(p > 1) return static_cast(p); else return default_page_size; #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) BOTAN_UNUSED(default_page_size); SYSTEM_INFO sys_info; ::GetSystemInfo(&sys_info); return sys_info.dwPageSize; #else return default_page_size; #endif } size_t OS::get_memory_locking_limit() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) && defined(RLIMIT_MEMLOCK) /* * If RLIMIT_MEMLOCK is not defined, likely the OS does not support * unprivileged mlock calls. * * Linux defaults to only 64 KiB of mlockable memory per process * (too small) but BSDs offer a small fraction of total RAM (more * than we need). Bound the total mlock size to 512 KiB which is * enough to run the entire test suite without spilling to non-mlock * memory (and thus presumably also enough for many useful * programs), but small enough that we should not cause problems * even if many processes are mlocking on the same machine. */ const size_t user_req = read_env_variable_sz("BOTAN_MLOCK_POOL_SIZE", BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB); const size_t mlock_requested = std::min(user_req, BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB); if(mlock_requested > 0) { struct ::rlimit limits; ::getrlimit(RLIMIT_MEMLOCK, &limits); if(limits.rlim_cur < limits.rlim_max) { limits.rlim_cur = limits.rlim_max; ::setrlimit(RLIMIT_MEMLOCK, &limits); ::getrlimit(RLIMIT_MEMLOCK, &limits); } return std::min(limits.rlim_cur, mlock_requested * 1024); } #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) SIZE_T working_min = 0, working_max = 0; if(!::GetProcessWorkingSetSize(::GetCurrentProcess(), &working_min, &working_max)) { return 0; } // According to Microsoft MSDN: // The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead // In the book "Windows Internals Part 2": the maximum lockable pages are minimum working set size - 8 pages // But the information in the book seems to be inaccurate/outdated // I've tested this on Windows 8.1 x64, Windows 10 x64 and Windows 7 x86 // On all three OS the value is 11 instead of 8 const size_t overhead = OS::system_page_size() * 11; if(working_min > overhead) { const size_t lockable_bytes = working_min - overhead; return std::min(lockable_bytes, BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024); } #endif // Not supported on this platform return 0; } bool OS::read_env_variable(std::string& value_out, const std::string& name) { value_out = ""; if(running_in_privileged_state()) return false; #if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC) char val[128] = { 0 }; size_t req_size = 0; if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0) { value_out = std::string(val, req_size); return true; } #else if(const char* val = std::getenv(name.c_str())) { value_out = val; return true; } #endif return false; } size_t OS::read_env_variable_sz(const std::string& name, size_t def) { std::string value; if(read_env_variable(value, name)) { try { const size_t val = std::stoul(value, nullptr); return val; } catch(std::exception&) { /* ignore it */ } } return def; } #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) namespace { int get_locked_fd() { #if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS) // On Darwin, tagging anonymous pages allows vmmap to track these. // Allowed from 240 to 255 for userland applications static constexpr int default_locked_fd = 255; int locked_fd = default_locked_fd; if(size_t locked_fdl = OS::read_env_variable_sz("BOTAN_LOCKED_FD", default_locked_fd)) { if(locked_fdl < 240 || locked_fdl > 255) { locked_fdl = default_locked_fd; } locked_fd = static_cast(locked_fdl); } return VM_MAKE_TAG(locked_fd); #else return -1; #endif } } #endif std::vector OS::allocate_locked_pages(size_t count) { std::vector result; #if (defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)) || defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) result.reserve(count); const size_t page_size = OS::system_page_size(); #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) static const int locked_fd = get_locked_fd(); #endif for(size_t i = 0; i != count; ++i) { void* ptr = nullptr; #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) #if !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #if !defined(MAP_NOCORE) #if defined(MAP_CONCEAL) #define MAP_NOCORE MAP_CONCEAL #else #define MAP_NOCORE 0 #endif #endif #if !defined(PROT_MAX) #define PROT_MAX(p) 0 #endif const int pflags = PROT_READ | PROT_WRITE; ptr = ::mmap(nullptr, 3*page_size, pflags | PROT_MAX(pflags), MAP_ANONYMOUS | MAP_PRIVATE | MAP_NOCORE, /*fd=*/locked_fd, /*offset=*/0); if(ptr == MAP_FAILED) { continue; } // lock the data page if(::mlock(static_cast(ptr) + page_size, page_size) != 0) { ::munmap(ptr, 3*page_size); continue; } #if defined(MADV_DONTDUMP) // we ignore errors here, as DONTDUMP is just a bonus ::madvise(static_cast(ptr) + page_size, page_size, MADV_DONTDUMP); #endif #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) ptr = ::VirtualAlloc(nullptr, 3*page_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if(ptr == nullptr) continue; if(::VirtualLock(static_cast(ptr) + page_size, page_size) == 0) { ::VirtualFree(ptr, 0, MEM_RELEASE); continue; } #endif std::memset(ptr, 0, 3*page_size); // zero data page and both guard pages // Make guard page preceeding the data page page_prohibit_access(static_cast(ptr)); // Make guard page following the data page page_prohibit_access(static_cast(ptr) + 2*page_size); result.push_back(static_cast(ptr) + page_size); } #else BOTAN_UNUSED(count); #endif return result; } void OS::page_allow_access(void* page) { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) const size_t page_size = OS::system_page_size(); ::mprotect(page, page_size, PROT_READ | PROT_WRITE); #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) const size_t page_size = OS::system_page_size(); DWORD old_perms = 0; ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms); BOTAN_UNUSED(old_perms); #else BOTAN_UNUSED(page); #endif } void OS::page_prohibit_access(void* page) { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) const size_t page_size = OS::system_page_size(); ::mprotect(page, page_size, PROT_NONE); #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) const size_t page_size = OS::system_page_size(); DWORD old_perms = 0; ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms); BOTAN_UNUSED(old_perms); #else BOTAN_UNUSED(page); #endif } void OS::free_locked_pages(const std::vector& pages) { const size_t page_size = OS::system_page_size(); for(size_t i = 0; i != pages.size(); ++i) { void* ptr = pages[i]; secure_scrub_memory(ptr, page_size); // ptr points to the data page, guard pages are before and after page_allow_access(static_cast(ptr) - page_size); page_allow_access(static_cast(ptr) + page_size); #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) ::munlock(ptr, page_size); ::munmap(static_cast(ptr) - page_size, 3*page_size); #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) ::VirtualUnlock(ptr, page_size); ::VirtualFree(static_cast(ptr) - page_size, 0, MEM_RELEASE); #endif } } #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) namespace { static ::sigjmp_buf g_sigill_jmp_buf; void botan_sigill_handler(int) { siglongjmp(g_sigill_jmp_buf, /*non-zero return value*/1); } } #endif int OS::run_cpu_instruction_probe(std::function probe_fn) { volatile int probe_result = -3; #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) struct sigaction old_sigaction; struct sigaction sigaction; sigaction.sa_handler = botan_sigill_handler; sigemptyset(&sigaction.sa_mask); sigaction.sa_flags = 0; int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction); if(rc != 0) throw System_Error("run_cpu_instruction_probe sigaction failed", errno); rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1); if(rc == 0) { // first call to sigsetjmp probe_result = probe_fn(); } else if(rc == 1) { // non-local return from siglongjmp in signal handler: return error probe_result = -1; } // Restore old SIGILL handler, if any rc = ::sigaction(SIGILL, &old_sigaction, nullptr); if(rc != 0) throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno); #else BOTAN_UNUSED(probe_fn); #endif return probe_result; } std::unique_ptr OS::suppress_echo_on_terminal() { #if defined(BOTAN_TARGET_OS_HAS_POSIX1) class POSIX_Echo_Suppression : public Echo_Suppression { public: POSIX_Echo_Suppression() { m_stdin_fd = fileno(stdin); if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0) throw System_Error("Getting terminal status failed", errno); struct termios noecho_flags = m_old_termios; noecho_flags.c_lflag &= ~ECHO; noecho_flags.c_lflag |= ECHONL; if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0) throw System_Error("Clearing terminal echo bit failed", errno); } void reenable_echo() override { if(m_stdin_fd > 0) { if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0) throw System_Error("Restoring terminal echo bit failed", errno); m_stdin_fd = -1; } } ~POSIX_Echo_Suppression() { try { reenable_echo(); } catch(...) { } } private: int m_stdin_fd; struct termios m_old_termios; }; return std::unique_ptr(new POSIX_Echo_Suppression); #elif defined(BOTAN_TARGET_OS_HAS_WIN32) class Win32_Echo_Suppression : public Echo_Suppression { public: Win32_Echo_Suppression() { m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE); if(::GetConsoleMode(m_input_handle, &m_console_state) == 0) throw System_Error("Getting console mode failed", ::GetLastError()); DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; if(::SetConsoleMode(m_input_handle, new_mode) == 0) throw System_Error("Setting console mode failed", ::GetLastError()); } void reenable_echo() override { if(m_input_handle != INVALID_HANDLE_VALUE) { if(::SetConsoleMode(m_input_handle, m_console_state) == 0) throw System_Error("Setting console mode failed", ::GetLastError()); m_input_handle = INVALID_HANDLE_VALUE; } } ~Win32_Echo_Suppression() { try { reenable_echo(); } catch(...) { } } private: HANDLE m_input_handle; DWORD m_console_state; }; return std::unique_ptr(new Win32_Echo_Suppression); #else // Not supported on this platform, return null return std::unique_ptr(); #endif } } /* * Various string utils and parsing functions * (C) 1999-2007,2013,2014,2015,2018 Jack Lloyd * (C) 2015 Simon Warta (Kullo GmbH) * (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #include #if defined(BOTAN_HAS_ASN1) #endif namespace Botan { uint16_t to_uint16(const std::string& str) { const uint32_t x = to_u32bit(str); if(x >> 16) throw Invalid_Argument("Integer value exceeds 16 bit range"); return static_cast(x); } uint32_t to_u32bit(const std::string& str) { // std::stoul is not strict enough. Ensure that str is digit only [0-9]* for(const char chr : str) { if(chr < '0' || chr > '9') { std::string chrAsString(1, chr); throw Invalid_Argument("String contains non-digit char: " + chrAsString); } } const unsigned long int x = std::stoul(str); if(sizeof(unsigned long int) > 4) { // x might be uint64 if (x > std::numeric_limits::max()) { throw Invalid_Argument("Integer value of " + str + " exceeds 32 bit range"); } } return static_cast(x); } /* * Convert a string into a time duration */ uint32_t timespec_to_u32bit(const std::string& timespec) { if(timespec.empty()) return 0; const char suffix = timespec[timespec.size()-1]; std::string value = timespec.substr(0, timespec.size()-1); uint32_t scale = 1; if(Charset::is_digit(suffix)) value += suffix; else if(suffix == 's') scale = 1; else if(suffix == 'm') scale = 60; else if(suffix == 'h') scale = 60 * 60; else if(suffix == 'd') scale = 24 * 60 * 60; else if(suffix == 'y') scale = 365 * 24 * 60 * 60; else throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); return scale * to_u32bit(value); } /* * Parse a SCAN-style algorithm name */ std::vector parse_algorithm_name(const std::string& namex) { if(namex.find('(') == std::string::npos && namex.find(')') == std::string::npos) return std::vector(1, namex); std::string name = namex, substring; std::vector elems; size_t level = 0; elems.push_back(name.substr(0, name.find('('))); name = name.substr(name.find('(')); for(auto i = name.begin(); i != name.end(); ++i) { char c = *i; if(c == '(') ++level; if(c == ')') { if(level == 1 && i == name.end() - 1) { if(elems.size() == 1) elems.push_back(substring.substr(1)); else elems.push_back(substring); return elems; } if(level == 0 || (level == 1 && i != name.end() - 1)) throw Invalid_Algorithm_Name(namex); --level; } if(c == ',' && level == 1) { if(elems.size() == 1) elems.push_back(substring.substr(1)); else elems.push_back(substring); substring.clear(); } else substring += c; } if(!substring.empty()) throw Invalid_Algorithm_Name(namex); return elems; } std::vector split_on(const std::string& str, char delim) { return split_on_pred(str, [delim](char c) { return c == delim; }); } std::vector split_on_pred(const std::string& str, std::function pred) { std::vector elems; if(str.empty()) return elems; std::string substr; for(auto i = str.begin(); i != str.end(); ++i) { if(pred(*i)) { if(!substr.empty()) elems.push_back(substr); substr.clear(); } else substr += *i; } if(substr.empty()) throw Invalid_Argument("Unable to split string: " + str); elems.push_back(substr); return elems; } /* * Join a string */ std::string string_join(const std::vector& strs, char delim) { std::string out = ""; for(size_t i = 0; i != strs.size(); ++i) { if(i != 0) out += delim; out += strs[i]; } return out; } /* * Parse an ASN.1 OID string */ std::vector parse_asn1_oid(const std::string& oid) { #if defined(BOTAN_HAS_ASN1) return OID(oid).get_components(); #else BOTAN_UNUSED(oid); throw Not_Implemented("ASN1 support not available"); #endif } /* * X.500 String Comparison */ bool x500_name_cmp(const std::string& name1, const std::string& name2) { auto p1 = name1.begin(); auto p2 = name2.begin(); while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; while(p1 != name1.end() && p2 != name2.end()) { if(Charset::is_space(*p1)) { if(!Charset::is_space(*p2)) return false; while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; if(p1 == name1.end() && p2 == name2.end()) return true; if(p1 == name1.end() || p2 == name2.end()) return false; } if(!Charset::caseless_cmp(*p1, *p2)) return false; ++p1; ++p2; } while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; if((p1 != name1.end()) || (p2 != name2.end())) return false; return true; } /* * Convert a decimal-dotted string to binary IP */ uint32_t string_to_ipv4(const std::string& str) { std::vector parts = split_on(str, '.'); if(parts.size() != 4) throw Decoding_Error("Invalid IP string " + str); uint32_t ip = 0; for(auto part = parts.begin(); part != parts.end(); ++part) { uint32_t octet = to_u32bit(*part); if(octet > 255) throw Decoding_Error("Invalid IP string " + str); ip = (ip << 8) | (octet & 0xFF); } return ip; } /* * Convert an IP address to decimal-dotted string */ std::string ipv4_to_string(uint32_t ip) { std::string str; for(size_t i = 0; i != sizeof(ip); ++i) { if(i) str += "."; str += std::to_string(get_byte(i, ip)); } return str; } std::string erase_chars(const std::string& str, const std::set& chars) { std::string out; for(auto c: str) if(chars.count(c) == 0) out += c; return out; } std::string replace_chars(const std::string& str, const std::set& chars, char to_char) { std::string out = str; for(size_t i = 0; i != out.size(); ++i) if(chars.count(out[i])) out[i] = to_char; return out; } std::string replace_char(const std::string& str, char from_char, char to_char) { std::string out = str; for(size_t i = 0; i != out.size(); ++i) if(out[i] == from_char) out[i] = to_char; return out; } std::string tolower_string(const std::string& in) { std::string s = in; for(size_t i = 0; i != s.size(); ++i) { const int cu = static_cast(s[i]); if(std::isalpha(cu)) s[i] = static_cast(std::tolower(cu)); } return s; } bool host_wildcard_match(const std::string& issued_, const std::string& host_) { const std::string issued = tolower_string(issued_); const std::string host = tolower_string(host_); if(host.empty() || issued.empty()) return false; /* If there are embedded nulls in your issued name Well I feel bad for you son */ if(std::count(issued.begin(), issued.end(), char(0)) > 0) return false; // If more than one wildcard, then issued name is invalid const size_t stars = std::count(issued.begin(), issued.end(), '*'); if(stars > 1) return false; // '*' is not a valid character in DNS names so should not appear on the host side if(std::count(host.begin(), host.end(), '*') != 0) return false; // Similarly a DNS name can't end in . if(host[host.size() - 1] == '.') return false; // And a host can't have an empty name component, so reject that if(host.find("..") != std::string::npos) return false; // Exact match: accept if(issued == host) { return true; } /* Otherwise it might be a wildcard If the issued size is strictly longer than the hostname size it couldn't possibly be a match, even if the issued value is a wildcard. The only exception is when the wildcard ends up empty (eg www.example.com matches www*.example.com) */ if(issued.size() > host.size() + 1) { return false; } // If no * at all then not a wildcard, and so not a match if(stars != 1) { return false; } /* Now walk through the issued string, making sure every character matches. When we come to the (singular) '*', jump forward in the hostname by the corresponding amount. We know exactly how much space the wildcard takes because it must be exactly `len(host) - len(issued) + 1 chars`. We also verify that the '*' comes in the leftmost component, and doesn't skip over any '.' in the hostname. */ size_t dots_seen = 0; size_t host_idx = 0; for(size_t i = 0; i != issued.size(); ++i) { dots_seen += (issued[i] == '.'); if(issued[i] == '*') { // Fail: wildcard can only come in leftmost component if(dots_seen > 0) { return false; } /* Since there is only one * we know the tail of the issued and hostname must be an exact match. In this case advance host_idx to match. */ const size_t advance = (host.size() - issued.size() + 1); if(host_idx + advance > host.size()) // shouldn't happen return false; // Can't be any intervening .s that we would have skipped if(std::count(host.begin() + host_idx, host.begin() + host_idx + advance, '.') != 0) return false; host_idx += advance; } else { if(issued[i] != host[host_idx]) { return false; } host_idx += 1; } } // Wildcard issued name must have at least 3 components if(dots_seen < 2) { return false; } return true; } } /* * Simple config/test file reader * (C) 2013,2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string clean_ws(const std::string& s) { const char* ws = " \t\n"; auto start = s.find_first_not_of(ws); auto end = s.find_last_not_of(ws); if(start == std::string::npos) return ""; if(end == std::string::npos) return s.substr(start, end); else return s.substr(start, start + end + 1); } std::map read_cfg(std::istream& is) { std::map kv; size_t line = 0; while(is.good()) { std::string s; std::getline(is, s); ++line; if(s.empty() || s[0] == '#') continue; s = clean_ws(s.substr(0, s.find('#'))); if(s.empty()) continue; auto eq = s.find("="); if(eq == std::string::npos || eq == 0 || eq == s.size() - 1) throw Decoding_Error("Bad read_cfg input '" + s + "' on line " + std::to_string(line)); const std::string key = clean_ws(s.substr(0, eq)); const std::string val = clean_ws(s.substr(eq + 1, std::string::npos)); kv[key] = val; } return kv; } } /* * (C) 2018 Ribose Inc * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::map read_kv(const std::string& kv) { std::map m; if(kv == "") return m; std::vector parts; try { parts = split_on(kv, ','); } catch(std::exception&) { throw Invalid_Argument("Bad KV spec"); } bool escaped = false; bool reading_key = true; std::string cur_key; std::string cur_val; for(char c : kv) { if(c == '\\' && !escaped) { escaped = true; } else if(c == ',' && !escaped) { if(cur_key.empty()) throw Invalid_Argument("Bad KV spec empty key"); if(m.find(cur_key) != m.end()) throw Invalid_Argument("Bad KV spec duplicated key"); m[cur_key] = cur_val; cur_key = ""; cur_val = ""; reading_key = true; } else if(c == '=' && !escaped) { if(reading_key == false) throw Invalid_Argument("Bad KV spec unexpected equals sign"); reading_key = false; } else { if(reading_key) cur_key += c; else cur_val += c; if(escaped) escaped = false; } } if(!cur_key.empty()) { if(reading_key == false) { if(m.find(cur_key) != m.end()) throw Invalid_Argument("Bad KV spec duplicated key"); m[cur_key] = cur_val; } else throw Invalid_Argument("Bad KV spec incomplete string"); } return m; } } /* * (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { void Timer::start() { stop(); m_timer_start = OS::get_system_timestamp_ns(); m_cpu_cycles_start = OS::get_cpu_cycle_counter(); } void Timer::stop() { if(m_timer_start) { if(m_cpu_cycles_start != 0) { const uint64_t cycles_taken = OS::get_cpu_cycle_counter() - m_cpu_cycles_start; if(cycles_taken > 0) { m_cpu_cycles_used += static_cast(cycles_taken * m_clock_cycle_ratio); } } const uint64_t now = OS::get_system_timestamp_ns(); if(now > m_timer_start) { const uint64_t dur = now - m_timer_start; m_time_used += dur; if(m_event_count == 0) { m_min_time = m_max_time = dur; } else { m_max_time = std::max(m_max_time, dur); m_min_time = std::min(m_min_time, dur); } } m_timer_start = 0; ++m_event_count; } } bool Timer::operator<(const Timer& other) const { if(this->doing() != other.doing()) return (this->doing() < other.doing()); return (this->get_name() < other.get_name()); } std::string Timer::to_string() const { if(m_custom_msg.size() > 0) { return m_custom_msg; } else if(this->buf_size() == 0) { return result_string_ops(); } else { return result_string_bps(); } } std::string Timer::result_string_bps() const { const size_t MiB = 1024 * 1024; const double MiB_total = static_cast(events()) / MiB; const double MiB_per_sec = MiB_total / seconds(); std::ostringstream oss; oss << get_name(); if(!doing().empty()) { oss << " " << doing(); } if(buf_size() > 0) { oss << " buffer size " << buf_size() << " bytes:"; } if(events() == 0) oss << " " << "N/A"; else oss << " " << std::fixed << std::setprecision(3) << MiB_per_sec << " MiB/sec"; if(cycles_consumed() != 0) { const double cycles_per_byte = static_cast(cycles_consumed()) / events(); oss << " " << std::fixed << std::setprecision(2) << cycles_per_byte << " cycles/byte"; } oss << " (" << MiB_total << " MiB in " << milliseconds() << " ms)\n"; return oss.str(); } std::string Timer::result_string_ops() const { std::ostringstream oss; oss << get_name() << " "; if(events() == 0) { oss << "no events\n"; } else { oss << static_cast(events_per_second()) << ' ' << doing() << "/sec; " << std::setprecision(2) << std::fixed << ms_per_event() << " ms/op"; if(cycles_consumed() != 0) { const double cycles_per_op = static_cast(cycles_consumed()) / events(); const int precision = (cycles_per_op < 10000) ? 2 : 0; oss << " " << std::fixed << std::setprecision(precision) << cycles_per_op << " cycles/op"; } oss << " (" << events() << " " << (events() == 1 ? "op" : "ops") << " in " << milliseconds() << " ms)\n"; } return oss.str(); } } /* * Version Information * (C) 1999-2013,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* These are intentionally compiled rather than inlined, so an application running against a shared library can test the true version they are running against. */ #define QUOTE(name) #name #define STR(macro) QUOTE(macro) const char* short_version_cstr() { return STR(BOTAN_VERSION_MAJOR) "." STR(BOTAN_VERSION_MINOR) "." STR(BOTAN_VERSION_PATCH) #if defined(BOTAN_VERSION_SUFFIX) STR(BOTAN_VERSION_SUFFIX) #endif ; } const char* version_cstr() { /* It is intentional that this string is a compile-time constant; it makes it much easier to find in binaries. */ return "Botan " STR(BOTAN_VERSION_MAJOR) "." STR(BOTAN_VERSION_MINOR) "." STR(BOTAN_VERSION_PATCH) #if defined(BOTAN_VERSION_SUFFIX) STR(BOTAN_VERSION_SUFFIX) #endif " (" #if defined(BOTAN_UNSAFE_FUZZER_MODE) "UNSAFE FUZZER MODE BUILD " #endif BOTAN_VERSION_RELEASE_TYPE #if (BOTAN_VERSION_DATESTAMP != 0) ", dated " STR(BOTAN_VERSION_DATESTAMP) #endif ", revision " BOTAN_VERSION_VC_REVISION ", distribution " BOTAN_DISTRIBUTION_INFO ")"; } #undef STR #undef QUOTE /* * Return the version as a string */ std::string version_string() { return std::string(version_cstr()); } std::string short_version_string() { return std::string(short_version_cstr()); } uint32_t version_datestamp() { return BOTAN_VERSION_DATESTAMP; } /* * Return parts of the version as integers */ uint32_t version_major() { return BOTAN_VERSION_MAJOR; } uint32_t version_minor() { return BOTAN_VERSION_MINOR; } uint32_t version_patch() { return BOTAN_VERSION_PATCH; } std::string runtime_version_check(uint32_t major, uint32_t minor, uint32_t patch) { if(major != version_major() || minor != version_minor() || patch != version_patch()) { std::ostringstream oss; oss << "Warning: linked version (" << short_version_string() << ")" << " does not match version built against " << "(" << major << '.' << minor << '.' << patch << ")\n"; return oss.str(); } return ""; } } /* * UUID type * (C) 2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { UUID::UUID(RandomNumberGenerator& rng) { m_uuid.resize(16); rng.randomize(m_uuid.data(), m_uuid.size()); // Mark as a random v4 UUID (RFC 4122 sec 4.4) m_uuid[6] = 0x40 | (m_uuid[6] & 0x0F); // Set reserved bits m_uuid[8] = 0x80 | (m_uuid[8] & 0x3F); } UUID::UUID(const std::vector& blob) { if(blob.size() != 16) { throw Invalid_Argument("Bad UUID blob " + hex_encode(blob)); } m_uuid = blob; } UUID::UUID(const std::string& uuid_str) { if(uuid_str.size() != 36 || uuid_str[8] != '-' || uuid_str[13] != '-' || uuid_str[18] != '-' || uuid_str[23] != '-') { throw Invalid_Argument("Bad UUID '" + uuid_str + "'"); } std::string just_hex; for(size_t i = 0; i != uuid_str.size(); ++i) { char c = uuid_str[i]; if(c == '-') continue; just_hex += c; } m_uuid = hex_decode(just_hex); if(m_uuid.size() != 16) { throw Invalid_Argument("Bad UUID '" + uuid_str + "'"); } } std::string UUID::to_string() const { if(is_valid() == false) throw Invalid_State("UUID object is empty cannot convert to string"); std::string h = hex_encode(m_uuid); h.insert(8, "-"); h.insert(13, "-"); h.insert(18, "-"); h.insert(23, "-"); return h; } } /* * Whirlpool * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::unique_ptr Whirlpool::copy_state() const { return std::unique_ptr(new Whirlpool(*this)); } /* * Whirlpool Compression Function */ void Whirlpool::compress_n(const uint8_t in[], size_t blocks) { static const uint64_t RC[10] = { 0x1823C6E887B8014F, 0x36A6D2F5796F9152, 0x60BC9B8EA30C7B35, 0x1DE0D7C22E4BFE57, 0x157737E59FF04ADA, 0x58C9290AB1A06B85, 0xBD5D10F4CB3E0567, 0xE427418BA77D95D8, 0xFBEE7C66DD17479E, 0xCA2DBF07AD5A8333 }; for(size_t i = 0; i != blocks; ++i) { load_be(m_M.data(), in, m_M.size()); uint64_t K0, K1, K2, K3, K4, K5, K6, K7; K0 = m_digest[0]; K1 = m_digest[1]; K2 = m_digest[2]; K3 = m_digest[3]; K4 = m_digest[4]; K5 = m_digest[5]; K6 = m_digest[6]; K7 = m_digest[7]; uint64_t B0, B1, B2, B3, B4, B5, B6, B7; B0 = K0 ^ m_M[0]; B1 = K1 ^ m_M[1]; B2 = K2 ^ m_M[2]; B3 = K3 ^ m_M[3]; B4 = K4 ^ m_M[4]; B5 = K5 ^ m_M[5]; B6 = K6 ^ m_M[6]; B7 = K7 ^ m_M[7]; for(size_t j = 0; j != 10; ++j) { uint64_t T0, T1, T2, T3, T4, T5, T6, T7; T0 = C0[get_byte(0, K0)] ^ C1[get_byte(1, K7)] ^ C2[get_byte(2, K6)] ^ C3[get_byte(3, K5)] ^ C4[get_byte(4, K4)] ^ C5[get_byte(5, K3)] ^ C6[get_byte(6, K2)] ^ C7[get_byte(7, K1)] ^ RC[j]; T1 = C0[get_byte(0, K1)] ^ C1[get_byte(1, K0)] ^ C2[get_byte(2, K7)] ^ C3[get_byte(3, K6)] ^ C4[get_byte(4, K5)] ^ C5[get_byte(5, K4)] ^ C6[get_byte(6, K3)] ^ C7[get_byte(7, K2)]; T2 = C0[get_byte(0, K2)] ^ C1[get_byte(1, K1)] ^ C2[get_byte(2, K0)] ^ C3[get_byte(3, K7)] ^ C4[get_byte(4, K6)] ^ C5[get_byte(5, K5)] ^ C6[get_byte(6, K4)] ^ C7[get_byte(7, K3)]; T3 = C0[get_byte(0, K3)] ^ C1[get_byte(1, K2)] ^ C2[get_byte(2, K1)] ^ C3[get_byte(3, K0)] ^ C4[get_byte(4, K7)] ^ C5[get_byte(5, K6)] ^ C6[get_byte(6, K5)] ^ C7[get_byte(7, K4)]; T4 = C0[get_byte(0, K4)] ^ C1[get_byte(1, K3)] ^ C2[get_byte(2, K2)] ^ C3[get_byte(3, K1)] ^ C4[get_byte(4, K0)] ^ C5[get_byte(5, K7)] ^ C6[get_byte(6, K6)] ^ C7[get_byte(7, K5)]; T5 = C0[get_byte(0, K5)] ^ C1[get_byte(1, K4)] ^ C2[get_byte(2, K3)] ^ C3[get_byte(3, K2)] ^ C4[get_byte(4, K1)] ^ C5[get_byte(5, K0)] ^ C6[get_byte(6, K7)] ^ C7[get_byte(7, K6)]; T6 = C0[get_byte(0, K6)] ^ C1[get_byte(1, K5)] ^ C2[get_byte(2, K4)] ^ C3[get_byte(3, K3)] ^ C4[get_byte(4, K2)] ^ C5[get_byte(5, K1)] ^ C6[get_byte(6, K0)] ^ C7[get_byte(7, K7)]; T7 = C0[get_byte(0, K7)] ^ C1[get_byte(1, K6)] ^ C2[get_byte(2, K5)] ^ C3[get_byte(3, K4)] ^ C4[get_byte(4, K3)] ^ C5[get_byte(5, K2)] ^ C6[get_byte(6, K1)] ^ C7[get_byte(7, K0)]; K0 = T0; K1 = T1; K2 = T2; K3 = T3; K4 = T4; K5 = T5; K6 = T6; K7 = T7; T0 = C0[get_byte(0, B0)] ^ C1[get_byte(1, B7)] ^ C2[get_byte(2, B6)] ^ C3[get_byte(3, B5)] ^ C4[get_byte(4, B4)] ^ C5[get_byte(5, B3)] ^ C6[get_byte(6, B2)] ^ C7[get_byte(7, B1)] ^ K0; T1 = C0[get_byte(0, B1)] ^ C1[get_byte(1, B0)] ^ C2[get_byte(2, B7)] ^ C3[get_byte(3, B6)] ^ C4[get_byte(4, B5)] ^ C5[get_byte(5, B4)] ^ C6[get_byte(6, B3)] ^ C7[get_byte(7, B2)] ^ K1; T2 = C0[get_byte(0, B2)] ^ C1[get_byte(1, B1)] ^ C2[get_byte(2, B0)] ^ C3[get_byte(3, B7)] ^ C4[get_byte(4, B6)] ^ C5[get_byte(5, B5)] ^ C6[get_byte(6, B4)] ^ C7[get_byte(7, B3)] ^ K2; T3 = C0[get_byte(0, B3)] ^ C1[get_byte(1, B2)] ^ C2[get_byte(2, B1)] ^ C3[get_byte(3, B0)] ^ C4[get_byte(4, B7)] ^ C5[get_byte(5, B6)] ^ C6[get_byte(6, B5)] ^ C7[get_byte(7, B4)] ^ K3; T4 = C0[get_byte(0, B4)] ^ C1[get_byte(1, B3)] ^ C2[get_byte(2, B2)] ^ C3[get_byte(3, B1)] ^ C4[get_byte(4, B0)] ^ C5[get_byte(5, B7)] ^ C6[get_byte(6, B6)] ^ C7[get_byte(7, B5)] ^ K4; T5 = C0[get_byte(0, B5)] ^ C1[get_byte(1, B4)] ^ C2[get_byte(2, B3)] ^ C3[get_byte(3, B2)] ^ C4[get_byte(4, B1)] ^ C5[get_byte(5, B0)] ^ C6[get_byte(6, B7)] ^ C7[get_byte(7, B6)] ^ K5; T6 = C0[get_byte(0, B6)] ^ C1[get_byte(1, B5)] ^ C2[get_byte(2, B4)] ^ C3[get_byte(3, B3)] ^ C4[get_byte(4, B2)] ^ C5[get_byte(5, B1)] ^ C6[get_byte(6, B0)] ^ C7[get_byte(7, B7)] ^ K6; T7 = C0[get_byte(0, B7)] ^ C1[get_byte(1, B6)] ^ C2[get_byte(2, B5)] ^ C3[get_byte(3, B4)] ^ C4[get_byte(4, B3)] ^ C5[get_byte(5, B2)] ^ C6[get_byte(6, B1)] ^ C7[get_byte(7, B0)] ^ K7; B0 = T0; B1 = T1; B2 = T2; B3 = T3; B4 = T4; B5 = T5; B6 = T6; B7 = T7; } m_digest[0] ^= B0 ^ m_M[0]; m_digest[1] ^= B1 ^ m_M[1]; m_digest[2] ^= B2 ^ m_M[2]; m_digest[3] ^= B3 ^ m_M[3]; m_digest[4] ^= B4 ^ m_M[4]; m_digest[5] ^= B5 ^ m_M[5]; m_digest[6] ^= B6 ^ m_M[6]; m_digest[7] ^= B7 ^ m_M[7]; in += hash_block_size(); } } /* * Copy out the digest */ void Whirlpool::copy_out(uint8_t output[]) { copy_out_vec_be(output, output_length(), m_digest); } /* * Clear memory of sensitive data */ void Whirlpool::clear() { MDx_HashFunction::clear(); zeroise(m_M); zeroise(m_digest); } } /* * Diffusion Tables for Whirlpool * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { alignas(64) const uint64_t Whirlpool::C0[256] = { 0x18186018C07830D8, 0x23238C2305AF4626, 0xC6C63FC67EF991B8, 0xE8E887E8136FCDFB, 0x878726874CA113CB, 0xB8B8DAB8A9626D11, 0x0101040108050209, 0x4F4F214F426E9E0D, 0x3636D836ADEE6C9B, 0xA6A6A2A6590451FF, 0xD2D26FD2DEBDB90C, 0xF5F5F3F5FB06F70E, 0x7979F979EF80F296, 0x6F6FA16F5FCEDE30, 0x91917E91FCEF3F6D, 0x52525552AA07A4F8, 0x60609D6027FDC047, 0xBCBCCABC89766535, 0x9B9B569BACCD2B37, 0x8E8E028E048C018A, 0xA3A3B6A371155BD2, 0x0C0C300C603C186C, 0x7B7BF17BFF8AF684, 0x3535D435B5E16A80, 0x1D1D741DE8693AF5, 0xE0E0A7E05347DDB3, 0xD7D77BD7F6ACB321, 0xC2C22FC25EED999C, 0x2E2EB82E6D965C43, 0x4B4B314B627A9629, 0xFEFEDFFEA321E15D, 0x575741578216AED5, 0x15155415A8412ABD, 0x7777C1779FB6EEE8, 0x3737DC37A5EB6E92, 0xE5E5B3E57B56D79E, 0x9F9F469F8CD92313, 0xF0F0E7F0D317FD23, 0x4A4A354A6A7F9420, 0xDADA4FDA9E95A944, 0x58587D58FA25B0A2, 0xC9C903C906CA8FCF, 0x2929A429558D527C, 0x0A0A280A5022145A, 0xB1B1FEB1E14F7F50, 0xA0A0BAA0691A5DC9, 0x6B6BB16B7FDAD614, 0x85852E855CAB17D9, 0xBDBDCEBD8173673C, 0x5D5D695DD234BA8F, 0x1010401080502090, 0xF4F4F7F4F303F507, 0xCBCB0BCB16C08BDD, 0x3E3EF83EEDC67CD3, 0x0505140528110A2D, 0x676781671FE6CE78, 0xE4E4B7E47353D597, 0x27279C2725BB4E02, 0x4141194132588273, 0x8B8B168B2C9D0BA7, 0xA7A7A6A7510153F6, 0x7D7DE97DCF94FAB2, 0x95956E95DCFB3749, 0xD8D847D88E9FAD56, 0xFBFBCBFB8B30EB70, 0xEEEE9FEE2371C1CD, 0x7C7CED7CC791F8BB, 0x6666856617E3CC71, 0xDDDD53DDA68EA77B, 0x17175C17B84B2EAF, 0x4747014702468E45, 0x9E9E429E84DC211A, 0xCACA0FCA1EC589D4, 0x2D2DB42D75995A58, 0xBFBFC6BF9179632E, 0x07071C07381B0E3F, 0xADAD8EAD012347AC, 0x5A5A755AEA2FB4B0, 0x838336836CB51BEF, 0x3333CC3385FF66B6, 0x636391633FF2C65C, 0x02020802100A0412, 0xAAAA92AA39384993, 0x7171D971AFA8E2DE, 0xC8C807C80ECF8DC6, 0x19196419C87D32D1, 0x494939497270923B, 0xD9D943D9869AAF5F, 0xF2F2EFF2C31DF931, 0xE3E3ABE34B48DBA8, 0x5B5B715BE22AB6B9, 0x88881A8834920DBC, 0x9A9A529AA4C8293E, 0x262698262DBE4C0B, 0x3232C8328DFA64BF, 0xB0B0FAB0E94A7D59, 0xE9E983E91B6ACFF2, 0x0F0F3C0F78331E77, 0xD5D573D5E6A6B733, 0x80803A8074BA1DF4, 0xBEBEC2BE997C6127, 0xCDCD13CD26DE87EB, 0x3434D034BDE46889, 0x48483D487A759032, 0xFFFFDBFFAB24E354, 0x7A7AF57AF78FF48D, 0x90907A90F4EA3D64, 0x5F5F615FC23EBE9D, 0x202080201DA0403D, 0x6868BD6867D5D00F, 0x1A1A681AD07234CA, 0xAEAE82AE192C41B7, 0xB4B4EAB4C95E757D, 0x54544D549A19A8CE, 0x93937693ECE53B7F, 0x222288220DAA442F, 0x64648D6407E9C863, 0xF1F1E3F1DB12FF2A, 0x7373D173BFA2E6CC, 0x12124812905A2482, 0x40401D403A5D807A, 0x0808200840281048, 0xC3C32BC356E89B95, 0xECEC97EC337BC5DF, 0xDBDB4BDB9690AB4D, 0xA1A1BEA1611F5FC0, 0x8D8D0E8D1C830791, 0x3D3DF43DF5C97AC8, 0x97976697CCF1335B, 0x0000000000000000, 0xCFCF1BCF36D483F9, 0x2B2BAC2B4587566E, 0x7676C57697B3ECE1, 0x8282328264B019E6, 0xD6D67FD6FEA9B128, 0x1B1B6C1BD87736C3, 0xB5B5EEB5C15B7774, 0xAFAF86AF112943BE, 0x6A6AB56A77DFD41D, 0x50505D50BA0DA0EA, 0x45450945124C8A57, 0xF3F3EBF3CB18FB38, 0x3030C0309DF060AD, 0xEFEF9BEF2B74C3C4, 0x3F3FFC3FE5C37EDA, 0x55554955921CAAC7, 0xA2A2B2A2791059DB, 0xEAEA8FEA0365C9E9, 0x656589650FECCA6A, 0xBABAD2BAB9686903, 0x2F2FBC2F65935E4A, 0xC0C027C04EE79D8E, 0xDEDE5FDEBE81A160, 0x1C1C701CE06C38FC, 0xFDFDD3FDBB2EE746, 0x4D4D294D52649A1F, 0x92927292E4E03976, 0x7575C9758FBCEAFA, 0x06061806301E0C36, 0x8A8A128A249809AE, 0xB2B2F2B2F940794B, 0xE6E6BFE66359D185, 0x0E0E380E70361C7E, 0x1F1F7C1FF8633EE7, 0x6262956237F7C455, 0xD4D477D4EEA3B53A, 0xA8A89AA829324D81, 0x96966296C4F43152, 0xF9F9C3F99B3AEF62, 0xC5C533C566F697A3, 0x2525942535B14A10, 0x59597959F220B2AB, 0x84842A8454AE15D0, 0x7272D572B7A7E4C5, 0x3939E439D5DD72EC, 0x4C4C2D4C5A619816, 0x5E5E655ECA3BBC94, 0x7878FD78E785F09F, 0x3838E038DDD870E5, 0x8C8C0A8C14860598, 0xD1D163D1C6B2BF17, 0xA5A5AEA5410B57E4, 0xE2E2AFE2434DD9A1, 0x616199612FF8C24E, 0xB3B3F6B3F1457B42, 0x2121842115A54234, 0x9C9C4A9C94D62508, 0x1E1E781EF0663CEE, 0x4343114322528661, 0xC7C73BC776FC93B1, 0xFCFCD7FCB32BE54F, 0x0404100420140824, 0x51515951B208A2E3, 0x99995E99BCC72F25, 0x6D6DA96D4FC4DA22, 0x0D0D340D68391A65, 0xFAFACFFA8335E979, 0xDFDF5BDFB684A369, 0x7E7EE57ED79BFCA9, 0x242490243DB44819, 0x3B3BEC3BC5D776FE, 0xABAB96AB313D4B9A, 0xCECE1FCE3ED181F0, 0x1111441188552299, 0x8F8F068F0C890383, 0x4E4E254E4A6B9C04, 0xB7B7E6B7D1517366, 0xEBEB8BEB0B60CBE0, 0x3C3CF03CFDCC78C1, 0x81813E817CBF1FFD, 0x94946A94D4FE3540, 0xF7F7FBF7EB0CF31C, 0xB9B9DEB9A1676F18, 0x13134C13985F268B, 0x2C2CB02C7D9C5851, 0xD3D36BD3D6B8BB05, 0xE7E7BBE76B5CD38C, 0x6E6EA56E57CBDC39, 0xC4C437C46EF395AA, 0x03030C03180F061B, 0x565645568A13ACDC, 0x44440D441A49885E, 0x7F7FE17FDF9EFEA0, 0xA9A99EA921374F88, 0x2A2AA82A4D825467, 0xBBBBD6BBB16D6B0A, 0xC1C123C146E29F87, 0x53535153A202A6F1, 0xDCDC57DCAE8BA572, 0x0B0B2C0B58271653, 0x9D9D4E9D9CD32701, 0x6C6CAD6C47C1D82B, 0x3131C43195F562A4, 0x7474CD7487B9E8F3, 0xF6F6FFF6E309F115, 0x464605460A438C4C, 0xACAC8AAC092645A5, 0x89891E893C970FB5, 0x14145014A04428B4, 0xE1E1A3E15B42DFBA, 0x16165816B04E2CA6, 0x3A3AE83ACDD274F7, 0x6969B9696FD0D206, 0x09092409482D1241, 0x7070DD70A7ADE0D7, 0xB6B6E2B6D954716F, 0xD0D067D0CEB7BD1E, 0xEDED93ED3B7EC7D6, 0xCCCC17CC2EDB85E2, 0x424215422A578468, 0x98985A98B4C22D2C, 0xA4A4AAA4490E55ED, 0x2828A0285D885075, 0x5C5C6D5CDA31B886, 0xF8F8C7F8933FED6B, 0x8686228644A411C2 }; alignas(64) const uint64_t Whirlpool::C1[256] = { 0xD818186018C07830, 0x2623238C2305AF46, 0xB8C6C63FC67EF991, 0xFBE8E887E8136FCD, 0xCB878726874CA113, 0x11B8B8DAB8A9626D, 0x0901010401080502, 0x0D4F4F214F426E9E, 0x9B3636D836ADEE6C, 0xFFA6A6A2A6590451, 0x0CD2D26FD2DEBDB9, 0x0EF5F5F3F5FB06F7, 0x967979F979EF80F2, 0x306F6FA16F5FCEDE, 0x6D91917E91FCEF3F, 0xF852525552AA07A4, 0x4760609D6027FDC0, 0x35BCBCCABC897665, 0x379B9B569BACCD2B, 0x8A8E8E028E048C01, 0xD2A3A3B6A371155B, 0x6C0C0C300C603C18, 0x847B7BF17BFF8AF6, 0x803535D435B5E16A, 0xF51D1D741DE8693A, 0xB3E0E0A7E05347DD, 0x21D7D77BD7F6ACB3, 0x9CC2C22FC25EED99, 0x432E2EB82E6D965C, 0x294B4B314B627A96, 0x5DFEFEDFFEA321E1, 0xD5575741578216AE, 0xBD15155415A8412A, 0xE87777C1779FB6EE, 0x923737DC37A5EB6E, 0x9EE5E5B3E57B56D7, 0x139F9F469F8CD923, 0x23F0F0E7F0D317FD, 0x204A4A354A6A7F94, 0x44DADA4FDA9E95A9, 0xA258587D58FA25B0, 0xCFC9C903C906CA8F, 0x7C2929A429558D52, 0x5A0A0A280A502214, 0x50B1B1FEB1E14F7F, 0xC9A0A0BAA0691A5D, 0x146B6BB16B7FDAD6, 0xD985852E855CAB17, 0x3CBDBDCEBD817367, 0x8F5D5D695DD234BA, 0x9010104010805020, 0x07F4F4F7F4F303F5, 0xDDCBCB0BCB16C08B, 0xD33E3EF83EEDC67C, 0x2D0505140528110A, 0x78676781671FE6CE, 0x97E4E4B7E47353D5, 0x0227279C2725BB4E, 0x7341411941325882, 0xA78B8B168B2C9D0B, 0xF6A7A7A6A7510153, 0xB27D7DE97DCF94FA, 0x4995956E95DCFB37, 0x56D8D847D88E9FAD, 0x70FBFBCBFB8B30EB, 0xCDEEEE9FEE2371C1, 0xBB7C7CED7CC791F8, 0x716666856617E3CC, 0x7BDDDD53DDA68EA7, 0xAF17175C17B84B2E, 0x454747014702468E, 0x1A9E9E429E84DC21, 0xD4CACA0FCA1EC589, 0x582D2DB42D75995A, 0x2EBFBFC6BF917963, 0x3F07071C07381B0E, 0xACADAD8EAD012347, 0xB05A5A755AEA2FB4, 0xEF838336836CB51B, 0xB63333CC3385FF66, 0x5C636391633FF2C6, 0x1202020802100A04, 0x93AAAA92AA393849, 0xDE7171D971AFA8E2, 0xC6C8C807C80ECF8D, 0xD119196419C87D32, 0x3B49493949727092, 0x5FD9D943D9869AAF, 0x31F2F2EFF2C31DF9, 0xA8E3E3ABE34B48DB, 0xB95B5B715BE22AB6, 0xBC88881A8834920D, 0x3E9A9A529AA4C829, 0x0B262698262DBE4C, 0xBF3232C8328DFA64, 0x59B0B0FAB0E94A7D, 0xF2E9E983E91B6ACF, 0x770F0F3C0F78331E, 0x33D5D573D5E6A6B7, 0xF480803A8074BA1D, 0x27BEBEC2BE997C61, 0xEBCDCD13CD26DE87, 0x893434D034BDE468, 0x3248483D487A7590, 0x54FFFFDBFFAB24E3, 0x8D7A7AF57AF78FF4, 0x6490907A90F4EA3D, 0x9D5F5F615FC23EBE, 0x3D202080201DA040, 0x0F6868BD6867D5D0, 0xCA1A1A681AD07234, 0xB7AEAE82AE192C41, 0x7DB4B4EAB4C95E75, 0xCE54544D549A19A8, 0x7F93937693ECE53B, 0x2F222288220DAA44, 0x6364648D6407E9C8, 0x2AF1F1E3F1DB12FF, 0xCC7373D173BFA2E6, 0x8212124812905A24, 0x7A40401D403A5D80, 0x4808082008402810, 0x95C3C32BC356E89B, 0xDFECEC97EC337BC5, 0x4DDBDB4BDB9690AB, 0xC0A1A1BEA1611F5F, 0x918D8D0E8D1C8307, 0xC83D3DF43DF5C97A, 0x5B97976697CCF133, 0x0000000000000000, 0xF9CFCF1BCF36D483, 0x6E2B2BAC2B458756, 0xE17676C57697B3EC, 0xE68282328264B019, 0x28D6D67FD6FEA9B1, 0xC31B1B6C1BD87736, 0x74B5B5EEB5C15B77, 0xBEAFAF86AF112943, 0x1D6A6AB56A77DFD4, 0xEA50505D50BA0DA0, 0x5745450945124C8A, 0x38F3F3EBF3CB18FB, 0xAD3030C0309DF060, 0xC4EFEF9BEF2B74C3, 0xDA3F3FFC3FE5C37E, 0xC755554955921CAA, 0xDBA2A2B2A2791059, 0xE9EAEA8FEA0365C9, 0x6A656589650FECCA, 0x03BABAD2BAB96869, 0x4A2F2FBC2F65935E, 0x8EC0C027C04EE79D, 0x60DEDE5FDEBE81A1, 0xFC1C1C701CE06C38, 0x46FDFDD3FDBB2EE7, 0x1F4D4D294D52649A, 0x7692927292E4E039, 0xFA7575C9758FBCEA, 0x3606061806301E0C, 0xAE8A8A128A249809, 0x4BB2B2F2B2F94079, 0x85E6E6BFE66359D1, 0x7E0E0E380E70361C, 0xE71F1F7C1FF8633E, 0x556262956237F7C4, 0x3AD4D477D4EEA3B5, 0x81A8A89AA829324D, 0x5296966296C4F431, 0x62F9F9C3F99B3AEF, 0xA3C5C533C566F697, 0x102525942535B14A, 0xAB59597959F220B2, 0xD084842A8454AE15, 0xC57272D572B7A7E4, 0xEC3939E439D5DD72, 0x164C4C2D4C5A6198, 0x945E5E655ECA3BBC, 0x9F7878FD78E785F0, 0xE53838E038DDD870, 0x988C8C0A8C148605, 0x17D1D163D1C6B2BF, 0xE4A5A5AEA5410B57, 0xA1E2E2AFE2434DD9, 0x4E616199612FF8C2, 0x42B3B3F6B3F1457B, 0x342121842115A542, 0x089C9C4A9C94D625, 0xEE1E1E781EF0663C, 0x6143431143225286, 0xB1C7C73BC776FC93, 0x4FFCFCD7FCB32BE5, 0x2404041004201408, 0xE351515951B208A2, 0x2599995E99BCC72F, 0x226D6DA96D4FC4DA, 0x650D0D340D68391A, 0x79FAFACFFA8335E9, 0x69DFDF5BDFB684A3, 0xA97E7EE57ED79BFC, 0x19242490243DB448, 0xFE3B3BEC3BC5D776, 0x9AABAB96AB313D4B, 0xF0CECE1FCE3ED181, 0x9911114411885522, 0x838F8F068F0C8903, 0x044E4E254E4A6B9C, 0x66B7B7E6B7D15173, 0xE0EBEB8BEB0B60CB, 0xC13C3CF03CFDCC78, 0xFD81813E817CBF1F, 0x4094946A94D4FE35, 0x1CF7F7FBF7EB0CF3, 0x18B9B9DEB9A1676F, 0x8B13134C13985F26, 0x512C2CB02C7D9C58, 0x05D3D36BD3D6B8BB, 0x8CE7E7BBE76B5CD3, 0x396E6EA56E57CBDC, 0xAAC4C437C46EF395, 0x1B03030C03180F06, 0xDC565645568A13AC, 0x5E44440D441A4988, 0xA07F7FE17FDF9EFE, 0x88A9A99EA921374F, 0x672A2AA82A4D8254, 0x0ABBBBD6BBB16D6B, 0x87C1C123C146E29F, 0xF153535153A202A6, 0x72DCDC57DCAE8BA5, 0x530B0B2C0B582716, 0x019D9D4E9D9CD327, 0x2B6C6CAD6C47C1D8, 0xA43131C43195F562, 0xF37474CD7487B9E8, 0x15F6F6FFF6E309F1, 0x4C464605460A438C, 0xA5ACAC8AAC092645, 0xB589891E893C970F, 0xB414145014A04428, 0xBAE1E1A3E15B42DF, 0xA616165816B04E2C, 0xF73A3AE83ACDD274, 0x066969B9696FD0D2, 0x4109092409482D12, 0xD77070DD70A7ADE0, 0x6FB6B6E2B6D95471, 0x1ED0D067D0CEB7BD, 0xD6EDED93ED3B7EC7, 0xE2CCCC17CC2EDB85, 0x68424215422A5784, 0x2C98985A98B4C22D, 0xEDA4A4AAA4490E55, 0x752828A0285D8850, 0x865C5C6D5CDA31B8, 0x6BF8F8C7F8933FED, 0xC28686228644A411 }; alignas(64) const uint64_t Whirlpool::C2[256] = { 0x30D818186018C078, 0x462623238C2305AF, 0x91B8C6C63FC67EF9, 0xCDFBE8E887E8136F, 0x13CB878726874CA1, 0x6D11B8B8DAB8A962, 0x0209010104010805, 0x9E0D4F4F214F426E, 0x6C9B3636D836ADEE, 0x51FFA6A6A2A65904, 0xB90CD2D26FD2DEBD, 0xF70EF5F5F3F5FB06, 0xF2967979F979EF80, 0xDE306F6FA16F5FCE, 0x3F6D91917E91FCEF, 0xA4F852525552AA07, 0xC04760609D6027FD, 0x6535BCBCCABC8976, 0x2B379B9B569BACCD, 0x018A8E8E028E048C, 0x5BD2A3A3B6A37115, 0x186C0C0C300C603C, 0xF6847B7BF17BFF8A, 0x6A803535D435B5E1, 0x3AF51D1D741DE869, 0xDDB3E0E0A7E05347, 0xB321D7D77BD7F6AC, 0x999CC2C22FC25EED, 0x5C432E2EB82E6D96, 0x96294B4B314B627A, 0xE15DFEFEDFFEA321, 0xAED5575741578216, 0x2ABD15155415A841, 0xEEE87777C1779FB6, 0x6E923737DC37A5EB, 0xD79EE5E5B3E57B56, 0x23139F9F469F8CD9, 0xFD23F0F0E7F0D317, 0x94204A4A354A6A7F, 0xA944DADA4FDA9E95, 0xB0A258587D58FA25, 0x8FCFC9C903C906CA, 0x527C2929A429558D, 0x145A0A0A280A5022, 0x7F50B1B1FEB1E14F, 0x5DC9A0A0BAA0691A, 0xD6146B6BB16B7FDA, 0x17D985852E855CAB, 0x673CBDBDCEBD8173, 0xBA8F5D5D695DD234, 0x2090101040108050, 0xF507F4F4F7F4F303, 0x8BDDCBCB0BCB16C0, 0x7CD33E3EF83EEDC6, 0x0A2D050514052811, 0xCE78676781671FE6, 0xD597E4E4B7E47353, 0x4E0227279C2725BB, 0x8273414119413258, 0x0BA78B8B168B2C9D, 0x53F6A7A7A6A75101, 0xFAB27D7DE97DCF94, 0x374995956E95DCFB, 0xAD56D8D847D88E9F, 0xEB70FBFBCBFB8B30, 0xC1CDEEEE9FEE2371, 0xF8BB7C7CED7CC791, 0xCC716666856617E3, 0xA77BDDDD53DDA68E, 0x2EAF17175C17B84B, 0x8E45474701470246, 0x211A9E9E429E84DC, 0x89D4CACA0FCA1EC5, 0x5A582D2DB42D7599, 0x632EBFBFC6BF9179, 0x0E3F07071C07381B, 0x47ACADAD8EAD0123, 0xB4B05A5A755AEA2F, 0x1BEF838336836CB5, 0x66B63333CC3385FF, 0xC65C636391633FF2, 0x041202020802100A, 0x4993AAAA92AA3938, 0xE2DE7171D971AFA8, 0x8DC6C8C807C80ECF, 0x32D119196419C87D, 0x923B494939497270, 0xAF5FD9D943D9869A, 0xF931F2F2EFF2C31D, 0xDBA8E3E3ABE34B48, 0xB6B95B5B715BE22A, 0x0DBC88881A883492, 0x293E9A9A529AA4C8, 0x4C0B262698262DBE, 0x64BF3232C8328DFA, 0x7D59B0B0FAB0E94A, 0xCFF2E9E983E91B6A, 0x1E770F0F3C0F7833, 0xB733D5D573D5E6A6, 0x1DF480803A8074BA, 0x6127BEBEC2BE997C, 0x87EBCDCD13CD26DE, 0x68893434D034BDE4, 0x903248483D487A75, 0xE354FFFFDBFFAB24, 0xF48D7A7AF57AF78F, 0x3D6490907A90F4EA, 0xBE9D5F5F615FC23E, 0x403D202080201DA0, 0xD00F6868BD6867D5, 0x34CA1A1A681AD072, 0x41B7AEAE82AE192C, 0x757DB4B4EAB4C95E, 0xA8CE54544D549A19, 0x3B7F93937693ECE5, 0x442F222288220DAA, 0xC86364648D6407E9, 0xFF2AF1F1E3F1DB12, 0xE6CC7373D173BFA2, 0x248212124812905A, 0x807A40401D403A5D, 0x1048080820084028, 0x9B95C3C32BC356E8, 0xC5DFECEC97EC337B, 0xAB4DDBDB4BDB9690, 0x5FC0A1A1BEA1611F, 0x07918D8D0E8D1C83, 0x7AC83D3DF43DF5C9, 0x335B97976697CCF1, 0x0000000000000000, 0x83F9CFCF1BCF36D4, 0x566E2B2BAC2B4587, 0xECE17676C57697B3, 0x19E68282328264B0, 0xB128D6D67FD6FEA9, 0x36C31B1B6C1BD877, 0x7774B5B5EEB5C15B, 0x43BEAFAF86AF1129, 0xD41D6A6AB56A77DF, 0xA0EA50505D50BA0D, 0x8A5745450945124C, 0xFB38F3F3EBF3CB18, 0x60AD3030C0309DF0, 0xC3C4EFEF9BEF2B74, 0x7EDA3F3FFC3FE5C3, 0xAAC755554955921C, 0x59DBA2A2B2A27910, 0xC9E9EAEA8FEA0365, 0xCA6A656589650FEC, 0x6903BABAD2BAB968, 0x5E4A2F2FBC2F6593, 0x9D8EC0C027C04EE7, 0xA160DEDE5FDEBE81, 0x38FC1C1C701CE06C, 0xE746FDFDD3FDBB2E, 0x9A1F4D4D294D5264, 0x397692927292E4E0, 0xEAFA7575C9758FBC, 0x0C3606061806301E, 0x09AE8A8A128A2498, 0x794BB2B2F2B2F940, 0xD185E6E6BFE66359, 0x1C7E0E0E380E7036, 0x3EE71F1F7C1FF863, 0xC4556262956237F7, 0xB53AD4D477D4EEA3, 0x4D81A8A89AA82932, 0x315296966296C4F4, 0xEF62F9F9C3F99B3A, 0x97A3C5C533C566F6, 0x4A102525942535B1, 0xB2AB59597959F220, 0x15D084842A8454AE, 0xE4C57272D572B7A7, 0x72EC3939E439D5DD, 0x98164C4C2D4C5A61, 0xBC945E5E655ECA3B, 0xF09F7878FD78E785, 0x70E53838E038DDD8, 0x05988C8C0A8C1486, 0xBF17D1D163D1C6B2, 0x57E4A5A5AEA5410B, 0xD9A1E2E2AFE2434D, 0xC24E616199612FF8, 0x7B42B3B3F6B3F145, 0x42342121842115A5, 0x25089C9C4A9C94D6, 0x3CEE1E1E781EF066, 0x8661434311432252, 0x93B1C7C73BC776FC, 0xE54FFCFCD7FCB32B, 0x0824040410042014, 0xA2E351515951B208, 0x2F2599995E99BCC7, 0xDA226D6DA96D4FC4, 0x1A650D0D340D6839, 0xE979FAFACFFA8335, 0xA369DFDF5BDFB684, 0xFCA97E7EE57ED79B, 0x4819242490243DB4, 0x76FE3B3BEC3BC5D7, 0x4B9AABAB96AB313D, 0x81F0CECE1FCE3ED1, 0x2299111144118855, 0x03838F8F068F0C89, 0x9C044E4E254E4A6B, 0x7366B7B7E6B7D151, 0xCBE0EBEB8BEB0B60, 0x78C13C3CF03CFDCC, 0x1FFD81813E817CBF, 0x354094946A94D4FE, 0xF31CF7F7FBF7EB0C, 0x6F18B9B9DEB9A167, 0x268B13134C13985F, 0x58512C2CB02C7D9C, 0xBB05D3D36BD3D6B8, 0xD38CE7E7BBE76B5C, 0xDC396E6EA56E57CB, 0x95AAC4C437C46EF3, 0x061B03030C03180F, 0xACDC565645568A13, 0x885E44440D441A49, 0xFEA07F7FE17FDF9E, 0x4F88A9A99EA92137, 0x54672A2AA82A4D82, 0x6B0ABBBBD6BBB16D, 0x9F87C1C123C146E2, 0xA6F153535153A202, 0xA572DCDC57DCAE8B, 0x16530B0B2C0B5827, 0x27019D9D4E9D9CD3, 0xD82B6C6CAD6C47C1, 0x62A43131C43195F5, 0xE8F37474CD7487B9, 0xF115F6F6FFF6E309, 0x8C4C464605460A43, 0x45A5ACAC8AAC0926, 0x0FB589891E893C97, 0x28B414145014A044, 0xDFBAE1E1A3E15B42, 0x2CA616165816B04E, 0x74F73A3AE83ACDD2, 0xD2066969B9696FD0, 0x124109092409482D, 0xE0D77070DD70A7AD, 0x716FB6B6E2B6D954, 0xBD1ED0D067D0CEB7, 0xC7D6EDED93ED3B7E, 0x85E2CCCC17CC2EDB, 0x8468424215422A57, 0x2D2C98985A98B4C2, 0x55EDA4A4AAA4490E, 0x50752828A0285D88, 0xB8865C5C6D5CDA31, 0xED6BF8F8C7F8933F, 0x11C28686228644A4 }; alignas(64) const uint64_t Whirlpool::C3[256] = { 0x7830D818186018C0, 0xAF462623238C2305, 0xF991B8C6C63FC67E, 0x6FCDFBE8E887E813, 0xA113CB878726874C, 0x626D11B8B8DAB8A9, 0x0502090101040108, 0x6E9E0D4F4F214F42, 0xEE6C9B3636D836AD, 0x0451FFA6A6A2A659, 0xBDB90CD2D26FD2DE, 0x06F70EF5F5F3F5FB, 0x80F2967979F979EF, 0xCEDE306F6FA16F5F, 0xEF3F6D91917E91FC, 0x07A4F852525552AA, 0xFDC04760609D6027, 0x766535BCBCCABC89, 0xCD2B379B9B569BAC, 0x8C018A8E8E028E04, 0x155BD2A3A3B6A371, 0x3C186C0C0C300C60, 0x8AF6847B7BF17BFF, 0xE16A803535D435B5, 0x693AF51D1D741DE8, 0x47DDB3E0E0A7E053, 0xACB321D7D77BD7F6, 0xED999CC2C22FC25E, 0x965C432E2EB82E6D, 0x7A96294B4B314B62, 0x21E15DFEFEDFFEA3, 0x16AED55757415782, 0x412ABD15155415A8, 0xB6EEE87777C1779F, 0xEB6E923737DC37A5, 0x56D79EE5E5B3E57B, 0xD923139F9F469F8C, 0x17FD23F0F0E7F0D3, 0x7F94204A4A354A6A, 0x95A944DADA4FDA9E, 0x25B0A258587D58FA, 0xCA8FCFC9C903C906, 0x8D527C2929A42955, 0x22145A0A0A280A50, 0x4F7F50B1B1FEB1E1, 0x1A5DC9A0A0BAA069, 0xDAD6146B6BB16B7F, 0xAB17D985852E855C, 0x73673CBDBDCEBD81, 0x34BA8F5D5D695DD2, 0x5020901010401080, 0x03F507F4F4F7F4F3, 0xC08BDDCBCB0BCB16, 0xC67CD33E3EF83EED, 0x110A2D0505140528, 0xE6CE78676781671F, 0x53D597E4E4B7E473, 0xBB4E0227279C2725, 0x5882734141194132, 0x9D0BA78B8B168B2C, 0x0153F6A7A7A6A751, 0x94FAB27D7DE97DCF, 0xFB374995956E95DC, 0x9FAD56D8D847D88E, 0x30EB70FBFBCBFB8B, 0x71C1CDEEEE9FEE23, 0x91F8BB7C7CED7CC7, 0xE3CC716666856617, 0x8EA77BDDDD53DDA6, 0x4B2EAF17175C17B8, 0x468E454747014702, 0xDC211A9E9E429E84, 0xC589D4CACA0FCA1E, 0x995A582D2DB42D75, 0x79632EBFBFC6BF91, 0x1B0E3F07071C0738, 0x2347ACADAD8EAD01, 0x2FB4B05A5A755AEA, 0xB51BEF838336836C, 0xFF66B63333CC3385, 0xF2C65C636391633F, 0x0A04120202080210, 0x384993AAAA92AA39, 0xA8E2DE7171D971AF, 0xCF8DC6C8C807C80E, 0x7D32D119196419C8, 0x70923B4949394972, 0x9AAF5FD9D943D986, 0x1DF931F2F2EFF2C3, 0x48DBA8E3E3ABE34B, 0x2AB6B95B5B715BE2, 0x920DBC88881A8834, 0xC8293E9A9A529AA4, 0xBE4C0B262698262D, 0xFA64BF3232C8328D, 0x4A7D59B0B0FAB0E9, 0x6ACFF2E9E983E91B, 0x331E770F0F3C0F78, 0xA6B733D5D573D5E6, 0xBA1DF480803A8074, 0x7C6127BEBEC2BE99, 0xDE87EBCDCD13CD26, 0xE468893434D034BD, 0x75903248483D487A, 0x24E354FFFFDBFFAB, 0x8FF48D7A7AF57AF7, 0xEA3D6490907A90F4, 0x3EBE9D5F5F615FC2, 0xA0403D202080201D, 0xD5D00F6868BD6867, 0x7234CA1A1A681AD0, 0x2C41B7AEAE82AE19, 0x5E757DB4B4EAB4C9, 0x19A8CE54544D549A, 0xE53B7F93937693EC, 0xAA442F222288220D, 0xE9C86364648D6407, 0x12FF2AF1F1E3F1DB, 0xA2E6CC7373D173BF, 0x5A24821212481290, 0x5D807A40401D403A, 0x2810480808200840, 0xE89B95C3C32BC356, 0x7BC5DFECEC97EC33, 0x90AB4DDBDB4BDB96, 0x1F5FC0A1A1BEA161, 0x8307918D8D0E8D1C, 0xC97AC83D3DF43DF5, 0xF1335B97976697CC, 0x0000000000000000, 0xD483F9CFCF1BCF36, 0x87566E2B2BAC2B45, 0xB3ECE17676C57697, 0xB019E68282328264, 0xA9B128D6D67FD6FE, 0x7736C31B1B6C1BD8, 0x5B7774B5B5EEB5C1, 0x2943BEAFAF86AF11, 0xDFD41D6A6AB56A77, 0x0DA0EA50505D50BA, 0x4C8A574545094512, 0x18FB38F3F3EBF3CB, 0xF060AD3030C0309D, 0x74C3C4EFEF9BEF2B, 0xC37EDA3F3FFC3FE5, 0x1CAAC75555495592, 0x1059DBA2A2B2A279, 0x65C9E9EAEA8FEA03, 0xECCA6A656589650F, 0x686903BABAD2BAB9, 0x935E4A2F2FBC2F65, 0xE79D8EC0C027C04E, 0x81A160DEDE5FDEBE, 0x6C38FC1C1C701CE0, 0x2EE746FDFDD3FDBB, 0x649A1F4D4D294D52, 0xE0397692927292E4, 0xBCEAFA7575C9758F, 0x1E0C360606180630, 0x9809AE8A8A128A24, 0x40794BB2B2F2B2F9, 0x59D185E6E6BFE663, 0x361C7E0E0E380E70, 0x633EE71F1F7C1FF8, 0xF7C4556262956237, 0xA3B53AD4D477D4EE, 0x324D81A8A89AA829, 0xF4315296966296C4, 0x3AEF62F9F9C3F99B, 0xF697A3C5C533C566, 0xB14A102525942535, 0x20B2AB59597959F2, 0xAE15D084842A8454, 0xA7E4C57272D572B7, 0xDD72EC3939E439D5, 0x6198164C4C2D4C5A, 0x3BBC945E5E655ECA, 0x85F09F7878FD78E7, 0xD870E53838E038DD, 0x8605988C8C0A8C14, 0xB2BF17D1D163D1C6, 0x0B57E4A5A5AEA541, 0x4DD9A1E2E2AFE243, 0xF8C24E616199612F, 0x457B42B3B3F6B3F1, 0xA542342121842115, 0xD625089C9C4A9C94, 0x663CEE1E1E781EF0, 0x5286614343114322, 0xFC93B1C7C73BC776, 0x2BE54FFCFCD7FCB3, 0x1408240404100420, 0x08A2E351515951B2, 0xC72F2599995E99BC, 0xC4DA226D6DA96D4F, 0x391A650D0D340D68, 0x35E979FAFACFFA83, 0x84A369DFDF5BDFB6, 0x9BFCA97E7EE57ED7, 0xB44819242490243D, 0xD776FE3B3BEC3BC5, 0x3D4B9AABAB96AB31, 0xD181F0CECE1FCE3E, 0x5522991111441188, 0x8903838F8F068F0C, 0x6B9C044E4E254E4A, 0x517366B7B7E6B7D1, 0x60CBE0EBEB8BEB0B, 0xCC78C13C3CF03CFD, 0xBF1FFD81813E817C, 0xFE354094946A94D4, 0x0CF31CF7F7FBF7EB, 0x676F18B9B9DEB9A1, 0x5F268B13134C1398, 0x9C58512C2CB02C7D, 0xB8BB05D3D36BD3D6, 0x5CD38CE7E7BBE76B, 0xCBDC396E6EA56E57, 0xF395AAC4C437C46E, 0x0F061B03030C0318, 0x13ACDC565645568A, 0x49885E44440D441A, 0x9EFEA07F7FE17FDF, 0x374F88A9A99EA921, 0x8254672A2AA82A4D, 0x6D6B0ABBBBD6BBB1, 0xE29F87C1C123C146, 0x02A6F153535153A2, 0x8BA572DCDC57DCAE, 0x2716530B0B2C0B58, 0xD327019D9D4E9D9C, 0xC1D82B6C6CAD6C47, 0xF562A43131C43195, 0xB9E8F37474CD7487, 0x09F115F6F6FFF6E3, 0x438C4C464605460A, 0x2645A5ACAC8AAC09, 0x970FB589891E893C, 0x4428B414145014A0, 0x42DFBAE1E1A3E15B, 0x4E2CA616165816B0, 0xD274F73A3AE83ACD, 0xD0D2066969B9696F, 0x2D12410909240948, 0xADE0D77070DD70A7, 0x54716FB6B6E2B6D9, 0xB7BD1ED0D067D0CE, 0x7EC7D6EDED93ED3B, 0xDB85E2CCCC17CC2E, 0x578468424215422A, 0xC22D2C98985A98B4, 0x0E55EDA4A4AAA449, 0x8850752828A0285D, 0x31B8865C5C6D5CDA, 0x3FED6BF8F8C7F893, 0xA411C28686228644 }; alignas(64) const uint64_t Whirlpool::C4[256] = { 0xC07830D818186018, 0x05AF462623238C23, 0x7EF991B8C6C63FC6, 0x136FCDFBE8E887E8, 0x4CA113CB87872687, 0xA9626D11B8B8DAB8, 0x0805020901010401, 0x426E9E0D4F4F214F, 0xADEE6C9B3636D836, 0x590451FFA6A6A2A6, 0xDEBDB90CD2D26FD2, 0xFB06F70EF5F5F3F5, 0xEF80F2967979F979, 0x5FCEDE306F6FA16F, 0xFCEF3F6D91917E91, 0xAA07A4F852525552, 0x27FDC04760609D60, 0x89766535BCBCCABC, 0xACCD2B379B9B569B, 0x048C018A8E8E028E, 0x71155BD2A3A3B6A3, 0x603C186C0C0C300C, 0xFF8AF6847B7BF17B, 0xB5E16A803535D435, 0xE8693AF51D1D741D, 0x5347DDB3E0E0A7E0, 0xF6ACB321D7D77BD7, 0x5EED999CC2C22FC2, 0x6D965C432E2EB82E, 0x627A96294B4B314B, 0xA321E15DFEFEDFFE, 0x8216AED557574157, 0xA8412ABD15155415, 0x9FB6EEE87777C177, 0xA5EB6E923737DC37, 0x7B56D79EE5E5B3E5, 0x8CD923139F9F469F, 0xD317FD23F0F0E7F0, 0x6A7F94204A4A354A, 0x9E95A944DADA4FDA, 0xFA25B0A258587D58, 0x06CA8FCFC9C903C9, 0x558D527C2929A429, 0x5022145A0A0A280A, 0xE14F7F50B1B1FEB1, 0x691A5DC9A0A0BAA0, 0x7FDAD6146B6BB16B, 0x5CAB17D985852E85, 0x8173673CBDBDCEBD, 0xD234BA8F5D5D695D, 0x8050209010104010, 0xF303F507F4F4F7F4, 0x16C08BDDCBCB0BCB, 0xEDC67CD33E3EF83E, 0x28110A2D05051405, 0x1FE6CE7867678167, 0x7353D597E4E4B7E4, 0x25BB4E0227279C27, 0x3258827341411941, 0x2C9D0BA78B8B168B, 0x510153F6A7A7A6A7, 0xCF94FAB27D7DE97D, 0xDCFB374995956E95, 0x8E9FAD56D8D847D8, 0x8B30EB70FBFBCBFB, 0x2371C1CDEEEE9FEE, 0xC791F8BB7C7CED7C, 0x17E3CC7166668566, 0xA68EA77BDDDD53DD, 0xB84B2EAF17175C17, 0x02468E4547470147, 0x84DC211A9E9E429E, 0x1EC589D4CACA0FCA, 0x75995A582D2DB42D, 0x9179632EBFBFC6BF, 0x381B0E3F07071C07, 0x012347ACADAD8EAD, 0xEA2FB4B05A5A755A, 0x6CB51BEF83833683, 0x85FF66B63333CC33, 0x3FF2C65C63639163, 0x100A041202020802, 0x39384993AAAA92AA, 0xAFA8E2DE7171D971, 0x0ECF8DC6C8C807C8, 0xC87D32D119196419, 0x7270923B49493949, 0x869AAF5FD9D943D9, 0xC31DF931F2F2EFF2, 0x4B48DBA8E3E3ABE3, 0xE22AB6B95B5B715B, 0x34920DBC88881A88, 0xA4C8293E9A9A529A, 0x2DBE4C0B26269826, 0x8DFA64BF3232C832, 0xE94A7D59B0B0FAB0, 0x1B6ACFF2E9E983E9, 0x78331E770F0F3C0F, 0xE6A6B733D5D573D5, 0x74BA1DF480803A80, 0x997C6127BEBEC2BE, 0x26DE87EBCDCD13CD, 0xBDE468893434D034, 0x7A75903248483D48, 0xAB24E354FFFFDBFF, 0xF78FF48D7A7AF57A, 0xF4EA3D6490907A90, 0xC23EBE9D5F5F615F, 0x1DA0403D20208020, 0x67D5D00F6868BD68, 0xD07234CA1A1A681A, 0x192C41B7AEAE82AE, 0xC95E757DB4B4EAB4, 0x9A19A8CE54544D54, 0xECE53B7F93937693, 0x0DAA442F22228822, 0x07E9C86364648D64, 0xDB12FF2AF1F1E3F1, 0xBFA2E6CC7373D173, 0x905A248212124812, 0x3A5D807A40401D40, 0x4028104808082008, 0x56E89B95C3C32BC3, 0x337BC5DFECEC97EC, 0x9690AB4DDBDB4BDB, 0x611F5FC0A1A1BEA1, 0x1C8307918D8D0E8D, 0xF5C97AC83D3DF43D, 0xCCF1335B97976697, 0x0000000000000000, 0x36D483F9CFCF1BCF, 0x4587566E2B2BAC2B, 0x97B3ECE17676C576, 0x64B019E682823282, 0xFEA9B128D6D67FD6, 0xD87736C31B1B6C1B, 0xC15B7774B5B5EEB5, 0x112943BEAFAF86AF, 0x77DFD41D6A6AB56A, 0xBA0DA0EA50505D50, 0x124C8A5745450945, 0xCB18FB38F3F3EBF3, 0x9DF060AD3030C030, 0x2B74C3C4EFEF9BEF, 0xE5C37EDA3F3FFC3F, 0x921CAAC755554955, 0x791059DBA2A2B2A2, 0x0365C9E9EAEA8FEA, 0x0FECCA6A65658965, 0xB9686903BABAD2BA, 0x65935E4A2F2FBC2F, 0x4EE79D8EC0C027C0, 0xBE81A160DEDE5FDE, 0xE06C38FC1C1C701C, 0xBB2EE746FDFDD3FD, 0x52649A1F4D4D294D, 0xE4E0397692927292, 0x8FBCEAFA7575C975, 0x301E0C3606061806, 0x249809AE8A8A128A, 0xF940794BB2B2F2B2, 0x6359D185E6E6BFE6, 0x70361C7E0E0E380E, 0xF8633EE71F1F7C1F, 0x37F7C45562629562, 0xEEA3B53AD4D477D4, 0x29324D81A8A89AA8, 0xC4F4315296966296, 0x9B3AEF62F9F9C3F9, 0x66F697A3C5C533C5, 0x35B14A1025259425, 0xF220B2AB59597959, 0x54AE15D084842A84, 0xB7A7E4C57272D572, 0xD5DD72EC3939E439, 0x5A6198164C4C2D4C, 0xCA3BBC945E5E655E, 0xE785F09F7878FD78, 0xDDD870E53838E038, 0x148605988C8C0A8C, 0xC6B2BF17D1D163D1, 0x410B57E4A5A5AEA5, 0x434DD9A1E2E2AFE2, 0x2FF8C24E61619961, 0xF1457B42B3B3F6B3, 0x15A5423421218421, 0x94D625089C9C4A9C, 0xF0663CEE1E1E781E, 0x2252866143431143, 0x76FC93B1C7C73BC7, 0xB32BE54FFCFCD7FC, 0x2014082404041004, 0xB208A2E351515951, 0xBCC72F2599995E99, 0x4FC4DA226D6DA96D, 0x68391A650D0D340D, 0x8335E979FAFACFFA, 0xB684A369DFDF5BDF, 0xD79BFCA97E7EE57E, 0x3DB4481924249024, 0xC5D776FE3B3BEC3B, 0x313D4B9AABAB96AB, 0x3ED181F0CECE1FCE, 0x8855229911114411, 0x0C8903838F8F068F, 0x4A6B9C044E4E254E, 0xD1517366B7B7E6B7, 0x0B60CBE0EBEB8BEB, 0xFDCC78C13C3CF03C, 0x7CBF1FFD81813E81, 0xD4FE354094946A94, 0xEB0CF31CF7F7FBF7, 0xA1676F18B9B9DEB9, 0x985F268B13134C13, 0x7D9C58512C2CB02C, 0xD6B8BB05D3D36BD3, 0x6B5CD38CE7E7BBE7, 0x57CBDC396E6EA56E, 0x6EF395AAC4C437C4, 0x180F061B03030C03, 0x8A13ACDC56564556, 0x1A49885E44440D44, 0xDF9EFEA07F7FE17F, 0x21374F88A9A99EA9, 0x4D8254672A2AA82A, 0xB16D6B0ABBBBD6BB, 0x46E29F87C1C123C1, 0xA202A6F153535153, 0xAE8BA572DCDC57DC, 0x582716530B0B2C0B, 0x9CD327019D9D4E9D, 0x47C1D82B6C6CAD6C, 0x95F562A43131C431, 0x87B9E8F37474CD74, 0xE309F115F6F6FFF6, 0x0A438C4C46460546, 0x092645A5ACAC8AAC, 0x3C970FB589891E89, 0xA04428B414145014, 0x5B42DFBAE1E1A3E1, 0xB04E2CA616165816, 0xCDD274F73A3AE83A, 0x6FD0D2066969B969, 0x482D124109092409, 0xA7ADE0D77070DD70, 0xD954716FB6B6E2B6, 0xCEB7BD1ED0D067D0, 0x3B7EC7D6EDED93ED, 0x2EDB85E2CCCC17CC, 0x2A57846842421542, 0xB4C22D2C98985A98, 0x490E55EDA4A4AAA4, 0x5D8850752828A028, 0xDA31B8865C5C6D5C, 0x933FED6BF8F8C7F8, 0x44A411C286862286 }; alignas(64) const uint64_t Whirlpool::C5[256] = { 0x18C07830D8181860, 0x2305AF462623238C, 0xC67EF991B8C6C63F, 0xE8136FCDFBE8E887, 0x874CA113CB878726, 0xB8A9626D11B8B8DA, 0x0108050209010104, 0x4F426E9E0D4F4F21, 0x36ADEE6C9B3636D8, 0xA6590451FFA6A6A2, 0xD2DEBDB90CD2D26F, 0xF5FB06F70EF5F5F3, 0x79EF80F2967979F9, 0x6F5FCEDE306F6FA1, 0x91FCEF3F6D91917E, 0x52AA07A4F8525255, 0x6027FDC04760609D, 0xBC89766535BCBCCA, 0x9BACCD2B379B9B56, 0x8E048C018A8E8E02, 0xA371155BD2A3A3B6, 0x0C603C186C0C0C30, 0x7BFF8AF6847B7BF1, 0x35B5E16A803535D4, 0x1DE8693AF51D1D74, 0xE05347DDB3E0E0A7, 0xD7F6ACB321D7D77B, 0xC25EED999CC2C22F, 0x2E6D965C432E2EB8, 0x4B627A96294B4B31, 0xFEA321E15DFEFEDF, 0x578216AED5575741, 0x15A8412ABD151554, 0x779FB6EEE87777C1, 0x37A5EB6E923737DC, 0xE57B56D79EE5E5B3, 0x9F8CD923139F9F46, 0xF0D317FD23F0F0E7, 0x4A6A7F94204A4A35, 0xDA9E95A944DADA4F, 0x58FA25B0A258587D, 0xC906CA8FCFC9C903, 0x29558D527C2929A4, 0x0A5022145A0A0A28, 0xB1E14F7F50B1B1FE, 0xA0691A5DC9A0A0BA, 0x6B7FDAD6146B6BB1, 0x855CAB17D985852E, 0xBD8173673CBDBDCE, 0x5DD234BA8F5D5D69, 0x1080502090101040, 0xF4F303F507F4F4F7, 0xCB16C08BDDCBCB0B, 0x3EEDC67CD33E3EF8, 0x0528110A2D050514, 0x671FE6CE78676781, 0xE47353D597E4E4B7, 0x2725BB4E0227279C, 0x4132588273414119, 0x8B2C9D0BA78B8B16, 0xA7510153F6A7A7A6, 0x7DCF94FAB27D7DE9, 0x95DCFB374995956E, 0xD88E9FAD56D8D847, 0xFB8B30EB70FBFBCB, 0xEE2371C1CDEEEE9F, 0x7CC791F8BB7C7CED, 0x6617E3CC71666685, 0xDDA68EA77BDDDD53, 0x17B84B2EAF17175C, 0x4702468E45474701, 0x9E84DC211A9E9E42, 0xCA1EC589D4CACA0F, 0x2D75995A582D2DB4, 0xBF9179632EBFBFC6, 0x07381B0E3F07071C, 0xAD012347ACADAD8E, 0x5AEA2FB4B05A5A75, 0x836CB51BEF838336, 0x3385FF66B63333CC, 0x633FF2C65C636391, 0x02100A0412020208, 0xAA39384993AAAA92, 0x71AFA8E2DE7171D9, 0xC80ECF8DC6C8C807, 0x19C87D32D1191964, 0x497270923B494939, 0xD9869AAF5FD9D943, 0xF2C31DF931F2F2EF, 0xE34B48DBA8E3E3AB, 0x5BE22AB6B95B5B71, 0x8834920DBC88881A, 0x9AA4C8293E9A9A52, 0x262DBE4C0B262698, 0x328DFA64BF3232C8, 0xB0E94A7D59B0B0FA, 0xE91B6ACFF2E9E983, 0x0F78331E770F0F3C, 0xD5E6A6B733D5D573, 0x8074BA1DF480803A, 0xBE997C6127BEBEC2, 0xCD26DE87EBCDCD13, 0x34BDE468893434D0, 0x487A75903248483D, 0xFFAB24E354FFFFDB, 0x7AF78FF48D7A7AF5, 0x90F4EA3D6490907A, 0x5FC23EBE9D5F5F61, 0x201DA0403D202080, 0x6867D5D00F6868BD, 0x1AD07234CA1A1A68, 0xAE192C41B7AEAE82, 0xB4C95E757DB4B4EA, 0x549A19A8CE54544D, 0x93ECE53B7F939376, 0x220DAA442F222288, 0x6407E9C86364648D, 0xF1DB12FF2AF1F1E3, 0x73BFA2E6CC7373D1, 0x12905A2482121248, 0x403A5D807A40401D, 0x0840281048080820, 0xC356E89B95C3C32B, 0xEC337BC5DFECEC97, 0xDB9690AB4DDBDB4B, 0xA1611F5FC0A1A1BE, 0x8D1C8307918D8D0E, 0x3DF5C97AC83D3DF4, 0x97CCF1335B979766, 0x0000000000000000, 0xCF36D483F9CFCF1B, 0x2B4587566E2B2BAC, 0x7697B3ECE17676C5, 0x8264B019E6828232, 0xD6FEA9B128D6D67F, 0x1BD87736C31B1B6C, 0xB5C15B7774B5B5EE, 0xAF112943BEAFAF86, 0x6A77DFD41D6A6AB5, 0x50BA0DA0EA50505D, 0x45124C8A57454509, 0xF3CB18FB38F3F3EB, 0x309DF060AD3030C0, 0xEF2B74C3C4EFEF9B, 0x3FE5C37EDA3F3FFC, 0x55921CAAC7555549, 0xA2791059DBA2A2B2, 0xEA0365C9E9EAEA8F, 0x650FECCA6A656589, 0xBAB9686903BABAD2, 0x2F65935E4A2F2FBC, 0xC04EE79D8EC0C027, 0xDEBE81A160DEDE5F, 0x1CE06C38FC1C1C70, 0xFDBB2EE746FDFDD3, 0x4D52649A1F4D4D29, 0x92E4E03976929272, 0x758FBCEAFA7575C9, 0x06301E0C36060618, 0x8A249809AE8A8A12, 0xB2F940794BB2B2F2, 0xE66359D185E6E6BF, 0x0E70361C7E0E0E38, 0x1FF8633EE71F1F7C, 0x6237F7C455626295, 0xD4EEA3B53AD4D477, 0xA829324D81A8A89A, 0x96C4F43152969662, 0xF99B3AEF62F9F9C3, 0xC566F697A3C5C533, 0x2535B14A10252594, 0x59F220B2AB595979, 0x8454AE15D084842A, 0x72B7A7E4C57272D5, 0x39D5DD72EC3939E4, 0x4C5A6198164C4C2D, 0x5ECA3BBC945E5E65, 0x78E785F09F7878FD, 0x38DDD870E53838E0, 0x8C148605988C8C0A, 0xD1C6B2BF17D1D163, 0xA5410B57E4A5A5AE, 0xE2434DD9A1E2E2AF, 0x612FF8C24E616199, 0xB3F1457B42B3B3F6, 0x2115A54234212184, 0x9C94D625089C9C4A, 0x1EF0663CEE1E1E78, 0x4322528661434311, 0xC776FC93B1C7C73B, 0xFCB32BE54FFCFCD7, 0x0420140824040410, 0x51B208A2E3515159, 0x99BCC72F2599995E, 0x6D4FC4DA226D6DA9, 0x0D68391A650D0D34, 0xFA8335E979FAFACF, 0xDFB684A369DFDF5B, 0x7ED79BFCA97E7EE5, 0x243DB44819242490, 0x3BC5D776FE3B3BEC, 0xAB313D4B9AABAB96, 0xCE3ED181F0CECE1F, 0x1188552299111144, 0x8F0C8903838F8F06, 0x4E4A6B9C044E4E25, 0xB7D1517366B7B7E6, 0xEB0B60CBE0EBEB8B, 0x3CFDCC78C13C3CF0, 0x817CBF1FFD81813E, 0x94D4FE354094946A, 0xF7EB0CF31CF7F7FB, 0xB9A1676F18B9B9DE, 0x13985F268B13134C, 0x2C7D9C58512C2CB0, 0xD3D6B8BB05D3D36B, 0xE76B5CD38CE7E7BB, 0x6E57CBDC396E6EA5, 0xC46EF395AAC4C437, 0x03180F061B03030C, 0x568A13ACDC565645, 0x441A49885E44440D, 0x7FDF9EFEA07F7FE1, 0xA921374F88A9A99E, 0x2A4D8254672A2AA8, 0xBBB16D6B0ABBBBD6, 0xC146E29F87C1C123, 0x53A202A6F1535351, 0xDCAE8BA572DCDC57, 0x0B582716530B0B2C, 0x9D9CD327019D9D4E, 0x6C47C1D82B6C6CAD, 0x3195F562A43131C4, 0x7487B9E8F37474CD, 0xF6E309F115F6F6FF, 0x460A438C4C464605, 0xAC092645A5ACAC8A, 0x893C970FB589891E, 0x14A04428B4141450, 0xE15B42DFBAE1E1A3, 0x16B04E2CA6161658, 0x3ACDD274F73A3AE8, 0x696FD0D2066969B9, 0x09482D1241090924, 0x70A7ADE0D77070DD, 0xB6D954716FB6B6E2, 0xD0CEB7BD1ED0D067, 0xED3B7EC7D6EDED93, 0xCC2EDB85E2CCCC17, 0x422A578468424215, 0x98B4C22D2C98985A, 0xA4490E55EDA4A4AA, 0x285D8850752828A0, 0x5CDA31B8865C5C6D, 0xF8933FED6BF8F8C7, 0x8644A411C2868622 }; alignas(64) const uint64_t Whirlpool::C6[256] = { 0x6018C07830D81818, 0x8C2305AF46262323, 0x3FC67EF991B8C6C6, 0x87E8136FCDFBE8E8, 0x26874CA113CB8787, 0xDAB8A9626D11B8B8, 0x0401080502090101, 0x214F426E9E0D4F4F, 0xD836ADEE6C9B3636, 0xA2A6590451FFA6A6, 0x6FD2DEBDB90CD2D2, 0xF3F5FB06F70EF5F5, 0xF979EF80F2967979, 0xA16F5FCEDE306F6F, 0x7E91FCEF3F6D9191, 0x5552AA07A4F85252, 0x9D6027FDC0476060, 0xCABC89766535BCBC, 0x569BACCD2B379B9B, 0x028E048C018A8E8E, 0xB6A371155BD2A3A3, 0x300C603C186C0C0C, 0xF17BFF8AF6847B7B, 0xD435B5E16A803535, 0x741DE8693AF51D1D, 0xA7E05347DDB3E0E0, 0x7BD7F6ACB321D7D7, 0x2FC25EED999CC2C2, 0xB82E6D965C432E2E, 0x314B627A96294B4B, 0xDFFEA321E15DFEFE, 0x41578216AED55757, 0x5415A8412ABD1515, 0xC1779FB6EEE87777, 0xDC37A5EB6E923737, 0xB3E57B56D79EE5E5, 0x469F8CD923139F9F, 0xE7F0D317FD23F0F0, 0x354A6A7F94204A4A, 0x4FDA9E95A944DADA, 0x7D58FA25B0A25858, 0x03C906CA8FCFC9C9, 0xA429558D527C2929, 0x280A5022145A0A0A, 0xFEB1E14F7F50B1B1, 0xBAA0691A5DC9A0A0, 0xB16B7FDAD6146B6B, 0x2E855CAB17D98585, 0xCEBD8173673CBDBD, 0x695DD234BA8F5D5D, 0x4010805020901010, 0xF7F4F303F507F4F4, 0x0BCB16C08BDDCBCB, 0xF83EEDC67CD33E3E, 0x140528110A2D0505, 0x81671FE6CE786767, 0xB7E47353D597E4E4, 0x9C2725BB4E022727, 0x1941325882734141, 0x168B2C9D0BA78B8B, 0xA6A7510153F6A7A7, 0xE97DCF94FAB27D7D, 0x6E95DCFB37499595, 0x47D88E9FAD56D8D8, 0xCBFB8B30EB70FBFB, 0x9FEE2371C1CDEEEE, 0xED7CC791F8BB7C7C, 0x856617E3CC716666, 0x53DDA68EA77BDDDD, 0x5C17B84B2EAF1717, 0x014702468E454747, 0x429E84DC211A9E9E, 0x0FCA1EC589D4CACA, 0xB42D75995A582D2D, 0xC6BF9179632EBFBF, 0x1C07381B0E3F0707, 0x8EAD012347ACADAD, 0x755AEA2FB4B05A5A, 0x36836CB51BEF8383, 0xCC3385FF66B63333, 0x91633FF2C65C6363, 0x0802100A04120202, 0x92AA39384993AAAA, 0xD971AFA8E2DE7171, 0x07C80ECF8DC6C8C8, 0x6419C87D32D11919, 0x39497270923B4949, 0x43D9869AAF5FD9D9, 0xEFF2C31DF931F2F2, 0xABE34B48DBA8E3E3, 0x715BE22AB6B95B5B, 0x1A8834920DBC8888, 0x529AA4C8293E9A9A, 0x98262DBE4C0B2626, 0xC8328DFA64BF3232, 0xFAB0E94A7D59B0B0, 0x83E91B6ACFF2E9E9, 0x3C0F78331E770F0F, 0x73D5E6A6B733D5D5, 0x3A8074BA1DF48080, 0xC2BE997C6127BEBE, 0x13CD26DE87EBCDCD, 0xD034BDE468893434, 0x3D487A7590324848, 0xDBFFAB24E354FFFF, 0xF57AF78FF48D7A7A, 0x7A90F4EA3D649090, 0x615FC23EBE9D5F5F, 0x80201DA0403D2020, 0xBD6867D5D00F6868, 0x681AD07234CA1A1A, 0x82AE192C41B7AEAE, 0xEAB4C95E757DB4B4, 0x4D549A19A8CE5454, 0x7693ECE53B7F9393, 0x88220DAA442F2222, 0x8D6407E9C8636464, 0xE3F1DB12FF2AF1F1, 0xD173BFA2E6CC7373, 0x4812905A24821212, 0x1D403A5D807A4040, 0x2008402810480808, 0x2BC356E89B95C3C3, 0x97EC337BC5DFECEC, 0x4BDB9690AB4DDBDB, 0xBEA1611F5FC0A1A1, 0x0E8D1C8307918D8D, 0xF43DF5C97AC83D3D, 0x6697CCF1335B9797, 0x0000000000000000, 0x1BCF36D483F9CFCF, 0xAC2B4587566E2B2B, 0xC57697B3ECE17676, 0x328264B019E68282, 0x7FD6FEA9B128D6D6, 0x6C1BD87736C31B1B, 0xEEB5C15B7774B5B5, 0x86AF112943BEAFAF, 0xB56A77DFD41D6A6A, 0x5D50BA0DA0EA5050, 0x0945124C8A574545, 0xEBF3CB18FB38F3F3, 0xC0309DF060AD3030, 0x9BEF2B74C3C4EFEF, 0xFC3FE5C37EDA3F3F, 0x4955921CAAC75555, 0xB2A2791059DBA2A2, 0x8FEA0365C9E9EAEA, 0x89650FECCA6A6565, 0xD2BAB9686903BABA, 0xBC2F65935E4A2F2F, 0x27C04EE79D8EC0C0, 0x5FDEBE81A160DEDE, 0x701CE06C38FC1C1C, 0xD3FDBB2EE746FDFD, 0x294D52649A1F4D4D, 0x7292E4E039769292, 0xC9758FBCEAFA7575, 0x1806301E0C360606, 0x128A249809AE8A8A, 0xF2B2F940794BB2B2, 0xBFE66359D185E6E6, 0x380E70361C7E0E0E, 0x7C1FF8633EE71F1F, 0x956237F7C4556262, 0x77D4EEA3B53AD4D4, 0x9AA829324D81A8A8, 0x6296C4F431529696, 0xC3F99B3AEF62F9F9, 0x33C566F697A3C5C5, 0x942535B14A102525, 0x7959F220B2AB5959, 0x2A8454AE15D08484, 0xD572B7A7E4C57272, 0xE439D5DD72EC3939, 0x2D4C5A6198164C4C, 0x655ECA3BBC945E5E, 0xFD78E785F09F7878, 0xE038DDD870E53838, 0x0A8C148605988C8C, 0x63D1C6B2BF17D1D1, 0xAEA5410B57E4A5A5, 0xAFE2434DD9A1E2E2, 0x99612FF8C24E6161, 0xF6B3F1457B42B3B3, 0x842115A542342121, 0x4A9C94D625089C9C, 0x781EF0663CEE1E1E, 0x1143225286614343, 0x3BC776FC93B1C7C7, 0xD7FCB32BE54FFCFC, 0x1004201408240404, 0x5951B208A2E35151, 0x5E99BCC72F259999, 0xA96D4FC4DA226D6D, 0x340D68391A650D0D, 0xCFFA8335E979FAFA, 0x5BDFB684A369DFDF, 0xE57ED79BFCA97E7E, 0x90243DB448192424, 0xEC3BC5D776FE3B3B, 0x96AB313D4B9AABAB, 0x1FCE3ED181F0CECE, 0x4411885522991111, 0x068F0C8903838F8F, 0x254E4A6B9C044E4E, 0xE6B7D1517366B7B7, 0x8BEB0B60CBE0EBEB, 0xF03CFDCC78C13C3C, 0x3E817CBF1FFD8181, 0x6A94D4FE35409494, 0xFBF7EB0CF31CF7F7, 0xDEB9A1676F18B9B9, 0x4C13985F268B1313, 0xB02C7D9C58512C2C, 0x6BD3D6B8BB05D3D3, 0xBBE76B5CD38CE7E7, 0xA56E57CBDC396E6E, 0x37C46EF395AAC4C4, 0x0C03180F061B0303, 0x45568A13ACDC5656, 0x0D441A49885E4444, 0xE17FDF9EFEA07F7F, 0x9EA921374F88A9A9, 0xA82A4D8254672A2A, 0xD6BBB16D6B0ABBBB, 0x23C146E29F87C1C1, 0x5153A202A6F15353, 0x57DCAE8BA572DCDC, 0x2C0B582716530B0B, 0x4E9D9CD327019D9D, 0xAD6C47C1D82B6C6C, 0xC43195F562A43131, 0xCD7487B9E8F37474, 0xFFF6E309F115F6F6, 0x05460A438C4C4646, 0x8AAC092645A5ACAC, 0x1E893C970FB58989, 0x5014A04428B41414, 0xA3E15B42DFBAE1E1, 0x5816B04E2CA61616, 0xE83ACDD274F73A3A, 0xB9696FD0D2066969, 0x2409482D12410909, 0xDD70A7ADE0D77070, 0xE2B6D954716FB6B6, 0x67D0CEB7BD1ED0D0, 0x93ED3B7EC7D6EDED, 0x17CC2EDB85E2CCCC, 0x15422A5784684242, 0x5A98B4C22D2C9898, 0xAAA4490E55EDA4A4, 0xA0285D8850752828, 0x6D5CDA31B8865C5C, 0xC7F8933FED6BF8F8, 0x228644A411C28686 }; alignas(64) const uint64_t Whirlpool::C7[256] = { 0x186018C07830D818, 0x238C2305AF462623, 0xC63FC67EF991B8C6, 0xE887E8136FCDFBE8, 0x8726874CA113CB87, 0xB8DAB8A9626D11B8, 0x0104010805020901, 0x4F214F426E9E0D4F, 0x36D836ADEE6C9B36, 0xA6A2A6590451FFA6, 0xD26FD2DEBDB90CD2, 0xF5F3F5FB06F70EF5, 0x79F979EF80F29679, 0x6FA16F5FCEDE306F, 0x917E91FCEF3F6D91, 0x525552AA07A4F852, 0x609D6027FDC04760, 0xBCCABC89766535BC, 0x9B569BACCD2B379B, 0x8E028E048C018A8E, 0xA3B6A371155BD2A3, 0x0C300C603C186C0C, 0x7BF17BFF8AF6847B, 0x35D435B5E16A8035, 0x1D741DE8693AF51D, 0xE0A7E05347DDB3E0, 0xD77BD7F6ACB321D7, 0xC22FC25EED999CC2, 0x2EB82E6D965C432E, 0x4B314B627A96294B, 0xFEDFFEA321E15DFE, 0x5741578216AED557, 0x155415A8412ABD15, 0x77C1779FB6EEE877, 0x37DC37A5EB6E9237, 0xE5B3E57B56D79EE5, 0x9F469F8CD923139F, 0xF0E7F0D317FD23F0, 0x4A354A6A7F94204A, 0xDA4FDA9E95A944DA, 0x587D58FA25B0A258, 0xC903C906CA8FCFC9, 0x29A429558D527C29, 0x0A280A5022145A0A, 0xB1FEB1E14F7F50B1, 0xA0BAA0691A5DC9A0, 0x6BB16B7FDAD6146B, 0x852E855CAB17D985, 0xBDCEBD8173673CBD, 0x5D695DD234BA8F5D, 0x1040108050209010, 0xF4F7F4F303F507F4, 0xCB0BCB16C08BDDCB, 0x3EF83EEDC67CD33E, 0x05140528110A2D05, 0x6781671FE6CE7867, 0xE4B7E47353D597E4, 0x279C2725BB4E0227, 0x4119413258827341, 0x8B168B2C9D0BA78B, 0xA7A6A7510153F6A7, 0x7DE97DCF94FAB27D, 0x956E95DCFB374995, 0xD847D88E9FAD56D8, 0xFBCBFB8B30EB70FB, 0xEE9FEE2371C1CDEE, 0x7CED7CC791F8BB7C, 0x66856617E3CC7166, 0xDD53DDA68EA77BDD, 0x175C17B84B2EAF17, 0x47014702468E4547, 0x9E429E84DC211A9E, 0xCA0FCA1EC589D4CA, 0x2DB42D75995A582D, 0xBFC6BF9179632EBF, 0x071C07381B0E3F07, 0xAD8EAD012347ACAD, 0x5A755AEA2FB4B05A, 0x8336836CB51BEF83, 0x33CC3385FF66B633, 0x6391633FF2C65C63, 0x020802100A041202, 0xAA92AA39384993AA, 0x71D971AFA8E2DE71, 0xC807C80ECF8DC6C8, 0x196419C87D32D119, 0x4939497270923B49, 0xD943D9869AAF5FD9, 0xF2EFF2C31DF931F2, 0xE3ABE34B48DBA8E3, 0x5B715BE22AB6B95B, 0x881A8834920DBC88, 0x9A529AA4C8293E9A, 0x2698262DBE4C0B26, 0x32C8328DFA64BF32, 0xB0FAB0E94A7D59B0, 0xE983E91B6ACFF2E9, 0x0F3C0F78331E770F, 0xD573D5E6A6B733D5, 0x803A8074BA1DF480, 0xBEC2BE997C6127BE, 0xCD13CD26DE87EBCD, 0x34D034BDE4688934, 0x483D487A75903248, 0xFFDBFFAB24E354FF, 0x7AF57AF78FF48D7A, 0x907A90F4EA3D6490, 0x5F615FC23EBE9D5F, 0x2080201DA0403D20, 0x68BD6867D5D00F68, 0x1A681AD07234CA1A, 0xAE82AE192C41B7AE, 0xB4EAB4C95E757DB4, 0x544D549A19A8CE54, 0x937693ECE53B7F93, 0x2288220DAA442F22, 0x648D6407E9C86364, 0xF1E3F1DB12FF2AF1, 0x73D173BFA2E6CC73, 0x124812905A248212, 0x401D403A5D807A40, 0x0820084028104808, 0xC32BC356E89B95C3, 0xEC97EC337BC5DFEC, 0xDB4BDB9690AB4DDB, 0xA1BEA1611F5FC0A1, 0x8D0E8D1C8307918D, 0x3DF43DF5C97AC83D, 0x976697CCF1335B97, 0x0000000000000000, 0xCF1BCF36D483F9CF, 0x2BAC2B4587566E2B, 0x76C57697B3ECE176, 0x82328264B019E682, 0xD67FD6FEA9B128D6, 0x1B6C1BD87736C31B, 0xB5EEB5C15B7774B5, 0xAF86AF112943BEAF, 0x6AB56A77DFD41D6A, 0x505D50BA0DA0EA50, 0x450945124C8A5745, 0xF3EBF3CB18FB38F3, 0x30C0309DF060AD30, 0xEF9BEF2B74C3C4EF, 0x3FFC3FE5C37EDA3F, 0x554955921CAAC755, 0xA2B2A2791059DBA2, 0xEA8FEA0365C9E9EA, 0x6589650FECCA6A65, 0xBAD2BAB9686903BA, 0x2FBC2F65935E4A2F, 0xC027C04EE79D8EC0, 0xDE5FDEBE81A160DE, 0x1C701CE06C38FC1C, 0xFDD3FDBB2EE746FD, 0x4D294D52649A1F4D, 0x927292E4E0397692, 0x75C9758FBCEAFA75, 0x061806301E0C3606, 0x8A128A249809AE8A, 0xB2F2B2F940794BB2, 0xE6BFE66359D185E6, 0x0E380E70361C7E0E, 0x1F7C1FF8633EE71F, 0x62956237F7C45562, 0xD477D4EEA3B53AD4, 0xA89AA829324D81A8, 0x966296C4F4315296, 0xF9C3F99B3AEF62F9, 0xC533C566F697A3C5, 0x25942535B14A1025, 0x597959F220B2AB59, 0x842A8454AE15D084, 0x72D572B7A7E4C572, 0x39E439D5DD72EC39, 0x4C2D4C5A6198164C, 0x5E655ECA3BBC945E, 0x78FD78E785F09F78, 0x38E038DDD870E538, 0x8C0A8C148605988C, 0xD163D1C6B2BF17D1, 0xA5AEA5410B57E4A5, 0xE2AFE2434DD9A1E2, 0x6199612FF8C24E61, 0xB3F6B3F1457B42B3, 0x21842115A5423421, 0x9C4A9C94D625089C, 0x1E781EF0663CEE1E, 0x4311432252866143, 0xC73BC776FC93B1C7, 0xFCD7FCB32BE54FFC, 0x0410042014082404, 0x515951B208A2E351, 0x995E99BCC72F2599, 0x6DA96D4FC4DA226D, 0x0D340D68391A650D, 0xFACFFA8335E979FA, 0xDF5BDFB684A369DF, 0x7EE57ED79BFCA97E, 0x2490243DB4481924, 0x3BEC3BC5D776FE3B, 0xAB96AB313D4B9AAB, 0xCE1FCE3ED181F0CE, 0x1144118855229911, 0x8F068F0C8903838F, 0x4E254E4A6B9C044E, 0xB7E6B7D1517366B7, 0xEB8BEB0B60CBE0EB, 0x3CF03CFDCC78C13C, 0x813E817CBF1FFD81, 0x946A94D4FE354094, 0xF7FBF7EB0CF31CF7, 0xB9DEB9A1676F18B9, 0x134C13985F268B13, 0x2CB02C7D9C58512C, 0xD36BD3D6B8BB05D3, 0xE7BBE76B5CD38CE7, 0x6EA56E57CBDC396E, 0xC437C46EF395AAC4, 0x030C03180F061B03, 0x5645568A13ACDC56, 0x440D441A49885E44, 0x7FE17FDF9EFEA07F, 0xA99EA921374F88A9, 0x2AA82A4D8254672A, 0xBBD6BBB16D6B0ABB, 0xC123C146E29F87C1, 0x535153A202A6F153, 0xDC57DCAE8BA572DC, 0x0B2C0B582716530B, 0x9D4E9D9CD327019D, 0x6CAD6C47C1D82B6C, 0x31C43195F562A431, 0x74CD7487B9E8F374, 0xF6FFF6E309F115F6, 0x4605460A438C4C46, 0xAC8AAC092645A5AC, 0x891E893C970FB589, 0x145014A04428B414, 0xE1A3E15B42DFBAE1, 0x165816B04E2CA616, 0x3AE83ACDD274F73A, 0x69B9696FD0D20669, 0x092409482D124109, 0x70DD70A7ADE0D770, 0xB6E2B6D954716FB6, 0xD067D0CEB7BD1ED0, 0xED93ED3B7EC7D6ED, 0xCC17CC2EDB85E2CC, 0x4215422A57846842, 0x985A98B4C22D2C98, 0xA4AAA4490E55EDA4, 0x28A0285D88507528, 0x5C6D5CDA31B8865C, 0xF8C7F8933FED6BF8, 0x86228644A411C286 }; } /* * (C) 1999-2009,2016,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #define NOMINMAX 1 #define _WINSOCKAPI_ // stop windows.h including winsock.h namespace Botan { size_t Win32_EntropySource::poll(RandomNumberGenerator& rng) { rng.add_entropy_T(::GetTickCount()); rng.add_entropy_T(::GetMessagePos()); rng.add_entropy_T(::GetMessageTime()); rng.add_entropy_T(::GetInputState()); rng.add_entropy_T(::GetCurrentProcessId()); rng.add_entropy_T(::GetCurrentThreadId()); SYSTEM_INFO sys_info; ::GetSystemInfo(&sys_info); rng.add_entropy_T(sys_info); MEMORYSTATUSEX mem_info; ::GlobalMemoryStatusEx(&mem_info); rng.add_entropy_T(mem_info); POINT point; ::GetCursorPos(&point); rng.add_entropy_T(point); ::GetCaretPos(&point); rng.add_entropy_T(point); /* Potential other sources to investigate GetProductInfo GetComputerNameExA GetSystemFirmwareTable GetVersionExA GetProcessorSystemCycleTime GetProcessHandleCount(GetCurrentProcess()) GetThreadTimes(GetCurrentThread()) QueryThreadCycleTime QueryIdleProcessorCycleTime QueryUnbiasedInterruptTime */ // We assume all of the above is basically junk return 0; } } /* * AlternativeName * (C) 1999-2007 Jack Lloyd * 2007 Yves Jerschow * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Create an AlternativeName */ AlternativeName::AlternativeName(const std::string& email_addr, const std::string& uri, const std::string& dns, const std::string& ip) { add_attribute("RFC822", email_addr); add_attribute("DNS", dns); add_attribute("URI", uri); add_attribute("IP", ip); } /* * Add an attribute to an alternative name */ void AlternativeName::add_attribute(const std::string& type, const std::string& value) { if(type.empty() || value.empty()) return; auto range = m_alt_info.equal_range(type); for(auto j = range.first; j != range.second; ++j) if(j->second == value) return; multimap_insert(m_alt_info, type, value); } /* * Add an OtherName field */ void AlternativeName::add_othername(const OID& oid, const std::string& value, ASN1_Tag type) { if(value.empty()) return; multimap_insert(m_othernames, oid, ASN1_String(value, type)); } /* * Return all of the alternative names */ std::multimap AlternativeName::contents() const { std::multimap names; for(auto i = m_alt_info.begin(); i != m_alt_info.end(); ++i) { multimap_insert(names, i->first, i->second); } for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i) { multimap_insert(names, i->first.to_formatted_string(), i->second.value()); } return names; } bool AlternativeName::has_field(const std::string& attr) const { auto range = m_alt_info.equal_range(attr); return (range.first != range.second); } std::string AlternativeName::get_first_attribute(const std::string& attr) const { auto i = m_alt_info.lower_bound(attr); if(i != m_alt_info.end() && i->first == attr) return i->second; return ""; } std::vector AlternativeName::get_attribute(const std::string& attr) const { std::vector results; auto range = m_alt_info.equal_range(attr); for(auto i = range.first; i != range.second; ++i) results.push_back(i->second); return results; } X509_DN AlternativeName::dn() const { X509_DN dn; auto range = m_alt_info.equal_range("DN"); for(auto i = range.first; i != range.second; ++i) { std::istringstream strm(i->second); strm >> dn; } return dn; } /* * Return if this object has anything useful */ bool AlternativeName::has_items() const { return (m_alt_info.size() > 0 || m_othernames.size() > 0); } namespace { /* * DER encode an AlternativeName entry */ void encode_entries(DER_Encoder& encoder, const std::multimap& attr, const std::string& type, ASN1_Tag tagging) { auto range = attr.equal_range(type); for(auto i = range.first; i != range.second; ++i) { if(type == "RFC822" || type == "DNS" || type == "URI") { ASN1_String asn1_string(i->second, IA5_STRING); encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.value()); } else if(type == "IP") { const uint32_t ip = string_to_ipv4(i->second); uint8_t ip_buf[4] = { 0 }; store_be(ip, ip_buf); encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4); } else if (type == "DN") { std::stringstream ss(i->second); X509_DN dn; ss >> dn; encoder.encode(dn); } } } } /* * DER encode an AlternativeName extension */ void AlternativeName::encode_into(DER_Encoder& der) const { der.start_cons(SEQUENCE); encode_entries(der, m_alt_info, "RFC822", ASN1_Tag(1)); encode_entries(der, m_alt_info, "DNS", ASN1_Tag(2)); encode_entries(der, m_alt_info, "DN", ASN1_Tag(4)); encode_entries(der, m_alt_info, "URI", ASN1_Tag(6)); encode_entries(der, m_alt_info, "IP", ASN1_Tag(7)); for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i) { der.start_explicit(0) .encode(i->first) .start_explicit(0) .encode(i->second) .end_explicit() .end_explicit(); } der.end_cons(); } /* * Decode a BER encoded AlternativeName */ void AlternativeName::decode_from(BER_Decoder& source) { BER_Decoder names = source.start_cons(SEQUENCE); // FIXME this is largely a duplication of GeneralName::decode_from while(names.more_items()) { BER_Object obj = names.get_next_object(); if(obj.is_a(0, CONTEXT_SPECIFIC)) { BER_Decoder othername(obj); OID oid; othername.decode(oid); if(othername.more_items()) { BER_Object othername_value_outer = othername.get_next_object(); othername.verify_end(); if(othername_value_outer.is_a(0, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) throw Decoding_Error("Invalid tags on otherName value"); BER_Decoder othername_value_inner(othername_value_outer); BER_Object value = othername_value_inner.get_next_object(); othername_value_inner.verify_end(); if(ASN1_String::is_string_type(value.type()) && value.get_class() == UNIVERSAL) { add_othername(oid, ASN1::to_string(value), value.type()); } } } if(obj.is_a(1, CONTEXT_SPECIFIC)) { add_attribute("RFC822", ASN1::to_string(obj)); } else if(obj.is_a(2, CONTEXT_SPECIFIC)) { add_attribute("DNS", ASN1::to_string(obj)); } else if(obj.is_a(6, CONTEXT_SPECIFIC)) { add_attribute("URI", ASN1::to_string(obj)); } else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) { BER_Decoder dec(obj); X509_DN dn; std::stringstream ss; dec.decode(dn); ss << dn; add_attribute("DN", ss.str()); } else if(obj.is_a(7, CONTEXT_SPECIFIC)) { if(obj.length() == 4) { const uint32_t ip = load_be(obj.bits(), 0); add_attribute("IP", ipv4_to_string(ip)); } } } } } /* * (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { const char* to_string(Certificate_Status_Code code) { switch(code) { case Certificate_Status_Code::VERIFIED: return "Verified"; case Certificate_Status_Code::OCSP_RESPONSE_GOOD: return "OCSP response accepted as affirming unrevoked status for certificate"; case Certificate_Status_Code::OCSP_SIGNATURE_OK: return "Signature on OCSP response was found valid"; case Certificate_Status_Code::VALID_CRL_CHECKED: return "Valid CRL examined"; case Certificate_Status_Code::CERT_SERIAL_NEGATIVE: return "Certificate serial number is negative"; case Certificate_Status_Code::DN_TOO_LONG: return "Distinguished name too long"; case Certificate_Status_Code::OCSP_NO_REVOCATION_URL: return "OCSP URL not available"; case Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE: return "OCSP server not available"; case Certificate_Status_Code::NO_REVOCATION_DATA: return "No revocation data"; case Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK: return "Signature method too weak"; case Certificate_Status_Code::UNTRUSTED_HASH: return "Hash function used is considered too weak for security"; case Certificate_Status_Code::CERT_NOT_YET_VALID: return "Certificate is not yet valid"; case Certificate_Status_Code::CERT_HAS_EXPIRED: return "Certificate has expired"; case Certificate_Status_Code::OCSP_NOT_YET_VALID: return "OCSP is not yet valid"; case Certificate_Status_Code::OCSP_HAS_EXPIRED: return "OCSP response has expired"; case Certificate_Status_Code::OCSP_IS_TOO_OLD: return "OCSP response is too old"; case Certificate_Status_Code::CRL_NOT_YET_VALID: return "CRL response is not yet valid"; case Certificate_Status_Code::CRL_HAS_EXPIRED: return "CRL has expired"; case Certificate_Status_Code::CERT_ISSUER_NOT_FOUND: return "Certificate issuer not found"; case Certificate_Status_Code::CANNOT_ESTABLISH_TRUST: return "Cannot establish trust"; case Certificate_Status_Code::CERT_CHAIN_LOOP: return "Loop in certificate chain"; case Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT: return "Certificate chain does not end in a CA certificate"; case Certificate_Status_Code::CHAIN_NAME_MISMATCH: return "Certificate issuer does not match subject of issuing cert"; case Certificate_Status_Code::POLICY_ERROR: return "Certificate policy error"; case Certificate_Status_Code::DUPLICATE_CERT_POLICY: return "Certificate contains duplicate policy"; case Certificate_Status_Code::INVALID_USAGE: return "Certificate does not allow the requested usage"; case Certificate_Status_Code::CERT_CHAIN_TOO_LONG: return "Certificate chain too long"; case Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER: return "CA certificate not allowed to issue certs"; case Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER: return "CA certificate not allowed to issue CRLs"; case Certificate_Status_Code::NO_MATCHING_CRLDP: return "No CRL with matching distribution point for certificate"; case Certificate_Status_Code::OCSP_CERT_NOT_LISTED: return "OCSP cert not listed"; case Certificate_Status_Code::OCSP_BAD_STATUS: return "OCSP bad status"; case Certificate_Status_Code::CERT_NAME_NOMATCH: return "Certificate does not match provided name"; case Certificate_Status_Code::NAME_CONSTRAINT_ERROR: return "Certificate does not pass name constraint"; case Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION: return "Unknown critical extension encountered"; case Certificate_Status_Code::DUPLICATE_CERT_EXTENSION: return "Duplicate certificate extension encountered"; case Certificate_Status_Code::EXT_IN_V1_V2_CERT: return "Encountered extension in certificate with version that does not allow it"; case Certificate_Status_Code::V2_IDENTIFIERS_IN_V1_CERT: return "Encountered v2 identifiers in v1 certificate"; case Certificate_Status_Code::OCSP_SIGNATURE_ERROR: return "OCSP signature error"; case Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND: return "Unable to find certificate issusing OCSP response"; case Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE: return "OCSP issuer's keyusage prohibits OCSP"; case Certificate_Status_Code::OCSP_RESPONSE_INVALID: return "OCSP parsing valid"; case Certificate_Status_Code::OCSP_NO_HTTP: return "OCSP requests not available, no HTTP support compiled in"; case Certificate_Status_Code::CERT_IS_REVOKED: return "Certificate is revoked"; case Certificate_Status_Code::CRL_BAD_SIGNATURE: return "CRL bad signature"; case Certificate_Status_Code::SIGNATURE_ERROR: return "Signature error"; case Certificate_Status_Code::CERT_PUBKEY_INVALID: return "Certificate public key invalid"; case Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN: return "Certificate signed with unknown/unavailable algorithm"; case Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS: return "Certificate signature has invalid parameters"; // intentionally no default so we are warned if new enum values are added } return nullptr; } } /* * Certificate Store * (C) 1999-2010,2013 Jack Lloyd * (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { Certificate_Store::~Certificate_Store() {} std::shared_ptr Certificate_Store::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const { const auto certs = find_all_certs(subject_dn, key_id); if(certs.empty()) { return nullptr; // certificate not found } // `count` might be greater than 1, but we'll just select the first match return certs.front(); } std::shared_ptr Certificate_Store::find_crl_for(const X509_Certificate&) const { return {}; } void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) { for(const auto& c : m_certs) if(*c == cert) return; m_certs.push_back(std::make_shared(cert)); } void Certificate_Store_In_Memory::add_certificate(std::shared_ptr cert) { for(const auto& c : m_certs) if(*c == *cert) return; m_certs.push_back(cert); } std::vector Certificate_Store_In_Memory::all_subjects() const { std::vector subjects; for(const auto& cert : m_certs) subjects.push_back(cert->subject_dn()); return subjects; } std::shared_ptr Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const { for(const auto& cert : m_certs) { // Only compare key ids if set in both call and in the cert if(key_id.size()) { std::vector skid = cert->subject_key_id(); if(skid.size() && skid != key_id) // no match continue; } if(cert->subject_dn() == subject_dn) return cert; } return nullptr; } std::vector> Certificate_Store_In_Memory::find_all_certs( const X509_DN& subject_dn, const std::vector& key_id) const { std::vector> matches; for(const auto& cert : m_certs) { if(key_id.size()) { std::vector skid = cert->subject_key_id(); if(skid.size() && skid != key_id) // no match continue; } if(cert->subject_dn() == subject_dn) matches.push_back(cert); } return matches; } std::shared_ptr Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector& key_hash) const { if(key_hash.size() != 20) throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash"); std::unique_ptr hash(HashFunction::create("SHA-1")); for(const auto& cert : m_certs){ hash->update(cert->subject_public_key_bitstring()); if(key_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state return cert; } return nullptr; } std::shared_ptr Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const { if(subject_hash.size() != 32) throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256 invalid hash"); std::unique_ptr hash(HashFunction::create("SHA-256")); for(const auto& cert : m_certs){ hash->update(cert->raw_subject_dn()); if(subject_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state return cert; } return nullptr; } void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) { std::shared_ptr crl_s = std::make_shared(crl); return add_crl(crl_s); } void Certificate_Store_In_Memory::add_crl(std::shared_ptr crl) { X509_DN crl_issuer = crl->issuer_dn(); for(auto& c : m_crls) { // Found an update of a previously existing one; replace it if(c->issuer_dn() == crl_issuer) { if(c->this_update() <= crl->this_update()) c = crl; return; } } // Totally new CRL, add to the list m_crls.push_back(crl); } std::shared_ptr Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const { const std::vector& key_id = subject.authority_key_id(); for(const auto& c : m_crls) { // Only compare key ids if set in both call and in the CRL if(key_id.size()) { std::vector akid = c->authority_key_id(); if(akid.size() && akid != key_id) // no match continue; } if(c->issuer_dn() == subject.issuer_dn()) return c; } return {}; } Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert) { add_certificate(cert); } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir) { if(dir.empty()) return; std::vector maybe_certs = get_files_recursive(dir); if(maybe_certs.empty()) { maybe_certs.push_back(dir); } for(auto&& cert_file : maybe_certs) { try { DataSource_Stream src(cert_file, true); while(!src.end_of_data()) { try { m_certs.push_back(std::make_shared(src)); } catch(std::exception&) { // stop searching for other certificate at first exception break; } } } catch(std::exception&) { } } } #endif } /* * CRL Entry * (C) 1999-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { struct CRL_Entry_Data { std::vector m_serial; X509_Time m_time; CRL_Code m_reason = UNSPECIFIED; Extensions m_extensions; }; /* * Create a CRL_Entry */ CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) { m_data.reset(new CRL_Entry_Data); m_data->m_serial = cert.serial_number(); m_data->m_time = X509_Time(std::chrono::system_clock::now()); m_data->m_reason = why; if(why != UNSPECIFIED) { m_data->m_extensions.add(new Cert_Extension::CRL_ReasonCode(why)); } } /* * Compare two CRL_Entrys for equality */ bool operator==(const CRL_Entry& a1, const CRL_Entry& a2) { if(a1.serial_number() != a2.serial_number()) return false; if(a1.expire_time() != a2.expire_time()) return false; if(a1.reason_code() != a2.reason_code()) return false; return true; } /* * Compare two CRL_Entrys for inequality */ bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2) { return !(a1 == a2); } /* * DER encode a CRL_Entry */ void CRL_Entry::encode_into(DER_Encoder& der) const { der.start_cons(SEQUENCE) .encode(BigInt::decode(serial_number())) .encode(expire_time()) .start_cons(SEQUENCE) .encode(extensions()) .end_cons() .end_cons(); } /* * Decode a BER encoded CRL_Entry */ void CRL_Entry::decode_from(BER_Decoder& source) { BigInt serial_number_bn; std::unique_ptr data(new CRL_Entry_Data); BER_Decoder entry = source.start_cons(SEQUENCE); entry.decode(serial_number_bn).decode(data->m_time); data->m_serial = BigInt::encode(serial_number_bn); if(entry.more_items()) { entry.decode(data->m_extensions); if(auto ext = data->m_extensions.get_extension_object_as()) { data->m_reason = ext->get_reason(); } else { data->m_reason = UNSPECIFIED; } } entry.end_cons(); m_data.reset(data.release()); } const CRL_Entry_Data& CRL_Entry::data() const { if(!m_data) { throw Invalid_State("CRL_Entry_Data uninitialized"); } return *m_data.get(); } const std::vector& CRL_Entry::serial_number() const { return data().m_serial; } const X509_Time& CRL_Entry::expire_time() const { return data().m_time; } CRL_Code CRL_Entry::reason_code() const { return data().m_reason; } const Extensions& CRL_Entry::extensions() const { return data().m_extensions; } } /* * Data Store * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Data_Store Equality Comparison */ bool Data_Store::operator==(const Data_Store& other) const { return (m_contents == other.m_contents); } /* * Check if this key has at least one value */ bool Data_Store::has_value(const std::string& key) const { return (m_contents.lower_bound(key) != m_contents.end()); } /* * Search based on an arbitrary predicate */ std::multimap Data_Store::search_for( std::function predicate) const { std::multimap out; for(auto i = m_contents.begin(); i != m_contents.end(); ++i) if(predicate(i->first, i->second)) out.insert(std::make_pair(i->first, i->second)); return out; } /* * Search based on key equality */ std::vector Data_Store::get(const std::string& looking_for) const { std::vector out; auto range = m_contents.equal_range(looking_for); for(auto i = range.first; i != range.second; ++i) out.push_back(i->second); return out; } /* * Get a single atom */ std::string Data_Store::get1(const std::string& key) const { std::vector vals = get(key); if(vals.empty()) throw Invalid_State("Data_Store::get1: No values set for " + key); if(vals.size() > 1) throw Invalid_State("Data_Store::get1: More than one value for " + key); return vals[0]; } std::string Data_Store::get1(const std::string& key, const std::string& default_value) const { std::vector vals = get(key); if(vals.size() > 1) throw Invalid_State("Data_Store::get1: More than one value for " + key); if(vals.empty()) return default_value; return vals[0]; } /* * Get a single std::vector atom */ std::vector Data_Store::get1_memvec(const std::string& key) const { std::vector vals = get(key); if(vals.empty()) return std::vector(); if(vals.size() > 1) throw Invalid_State("Data_Store::get1_memvec: Multiple values for " + key); return hex_decode(vals[0]); } /* * Get a single uint32_t atom */ uint32_t Data_Store::get1_uint32(const std::string& key, uint32_t default_val) const { std::vector vals = get(key); if(vals.empty()) return default_val; else if(vals.size() > 1) throw Invalid_State("Data_Store::get1_uint32: Multiple values for " + key); return to_u32bit(vals[0]); } /* * Insert a single key and value */ void Data_Store::add(const std::string& key, const std::string& val) { multimap_insert(m_contents, key, val); } /* * Insert a single key and value */ void Data_Store::add(const std::string& key, uint32_t val) { add(key, std::to_string(val)); } /* * Insert a single key and value */ void Data_Store::add(const std::string& key, const secure_vector& val) { add(key, hex_encode(val.data(), val.size())); } void Data_Store::add(const std::string& key, const std::vector& val) { add(key, hex_encode(val.data(), val.size())); } /* * Insert a mapping of key/value pairs */ void Data_Store::add(const std::multimap& in) { std::multimap::const_iterator i = in.begin(); while(i != in.end()) { m_contents.insert(*i); ++i; } } /* * Create and populate a X509_DN */ X509_DN create_dn(const Data_Store& info) { auto names = info.search_for( [](const std::string& key, const std::string&) { return (key.find("X520.") != std::string::npos); }); X509_DN dn; for(auto i = names.begin(); i != names.end(); ++i) dn.add_attribute(i->first, i->second); return dn; } /* * Create and populate an AlternativeName */ AlternativeName create_alt_name(const Data_Store& info) { auto names = info.search_for( [](const std::string& key, const std::string&) { return (key == "RFC822" || key == "DNS" || key == "URI" || key == "IP"); }); AlternativeName alt_name; for(auto i = names.begin(); i != names.end(); ++i) alt_name.add_attribute(i->first, i->second); return alt_name; } } /* * KeyUsage * (C) 1999-2007,2016 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { std::string key_constraints_to_string(Key_Constraints constraints) { std::vector str; if(constraints == NO_CONSTRAINTS) return "no_constraints"; if(constraints & DIGITAL_SIGNATURE) str.push_back("digital_signature"); if(constraints & NON_REPUDIATION) str.push_back("non_repudiation"); if(constraints & KEY_ENCIPHERMENT) str.push_back("key_encipherment"); if(constraints & DATA_ENCIPHERMENT) str.push_back("data_encipherment"); if(constraints & KEY_AGREEMENT) str.push_back("key_agreement"); if(constraints & KEY_CERT_SIGN) str.push_back("key_cert_sign"); if(constraints & CRL_SIGN) str.push_back("crl_sign"); if(constraints & ENCIPHER_ONLY) str.push_back("encipher_only"); if(constraints & DECIPHER_ONLY) str.push_back("decipher_only"); // Not 0 (checked at start) but nothing matched above! if(str.empty()) return "other_unknown_constraints"; if(str.size() == 1) return str[0]; std::string out; for(size_t i = 0; i < str.size() - 1; ++i) { out += str[i]; out += ','; } out += str[str.size() - 1]; return out; } /* * Make sure the given key constraints are permitted for the given key type */ void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, Key_Constraints constraints) { const std::string name = pub_key.algo_name(); size_t permitted = 0; const bool can_agree = (name == "DH" || name == "ECDH"); const bool can_encrypt = (name == "RSA" || name == "ElGamal"); const bool can_sign = (name == "RSA" || name == "DSA" || name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA" || name == "Ed25519" || name == "GOST-34.10" || name == "GOST-34.10-2012-256" || name == "GOST-34.10-2012-512"); if(can_agree) { permitted |= KEY_AGREEMENT | ENCIPHER_ONLY | DECIPHER_ONLY; } if(can_encrypt) { permitted |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; } if(can_sign) { permitted |= DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_CERT_SIGN | CRL_SIGN; } if(Key_Constraints(constraints & permitted) != constraints) { throw Invalid_Argument("Invalid " + name + " constraints " + key_constraints_to_string(constraints)); } } } /* * X.509 Name Constraint * (C) 2015 Kai Michaelis * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { class DER_Encoder; GeneralName::GeneralName(const std::string& str) : GeneralName() { size_t p = str.find(':'); if(p != std::string::npos) { m_type = str.substr(0, p); m_name = str.substr(p + 1, std::string::npos); } else { throw Invalid_Argument("Failed to decode Name Constraint"); } } void GeneralName::encode_into(DER_Encoder&) const { throw Not_Implemented("GeneralName encoding"); } void GeneralName::decode_from(class BER_Decoder& ber) { BER_Object obj = ber.get_next_object(); if(obj.is_a(1, CONTEXT_SPECIFIC)) { m_type = "RFC822"; m_name = ASN1::to_string(obj); } else if(obj.is_a(2, CONTEXT_SPECIFIC)) { m_type = "DNS"; m_name = ASN1::to_string(obj); } else if(obj.is_a(6, CONTEXT_SPECIFIC)) { m_type = "URI"; m_name = ASN1::to_string(obj); } else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) { m_type = "DN"; X509_DN dn; BER_Decoder dec(obj); std::stringstream ss; dn.decode_from(dec); ss << dn; m_name = ss.str(); } else if(obj.is_a(7, CONTEXT_SPECIFIC)) { if(obj.length() == 8) { m_type = "IP"; m_name = ipv4_to_string(load_be(obj.bits(), 0)) + "/" + ipv4_to_string(load_be(obj.bits(), 1)); } else if(obj.length() == 32) { throw Decoding_Error("Unsupported IPv6 name constraint"); } else { throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length())); } } else { throw Decoding_Error("Found unknown GeneralName type"); } } GeneralName::MatchResult GeneralName::matches(const X509_Certificate& cert) const { std::vector nam; std::function match_fn; const X509_DN& dn = cert.subject_dn(); const AlternativeName& alt_name = cert.subject_alt_name(); if(type() == "DNS") { match_fn = std::mem_fn(&GeneralName::matches_dns); nam = alt_name.get_attribute("DNS"); if(nam.empty()) { nam = dn.get_attribute("CN"); } } else if(type() == "DN") { match_fn = std::mem_fn(&GeneralName::matches_dn); nam.push_back(dn.to_string()); const auto alt_dn = alt_name.dn(); if(alt_dn.empty() == false) { nam.push_back(alt_dn.to_string()); } } else if(type() == "IP") { match_fn = std::mem_fn(&GeneralName::matches_ip); nam = alt_name.get_attribute("IP"); } else { return MatchResult::UnknownType; } if(nam.empty()) { return MatchResult::NotFound; } bool some = false; bool all = true; for(const std::string& n: nam) { bool m = match_fn(this, n); some |= m; all &= m; } if(all) { return MatchResult::All; } else if(some) { return MatchResult::Some; } else { return MatchResult::None; } } bool GeneralName::matches_dns(const std::string& nam) const { if(nam.size() == name().size()) { return tolower_string(nam) == tolower_string(name()); } else if(name().size() > nam.size()) { // The constraint is longer than the issued name: not possibly a match return false; } else // name.size() < nam.size() { // constr is suffix of nam const std::string constr = name().front() == '.' ? name() : "." + name(); const std::string substr = nam.substr(nam.size() - constr.size(), constr.size()); return tolower_string(constr) == tolower_string(substr); } } bool GeneralName::matches_dn(const std::string& nam) const { std::stringstream ss(nam); std::stringstream tt(name()); X509_DN nam_dn, my_dn; ss >> nam_dn; tt >> my_dn; auto attr = nam_dn.get_attributes(); bool ret = true; size_t trys = 0; for(const auto& c: my_dn.dn_info()) { auto i = attr.equal_range(c.first); if(i.first != i.second) { trys += 1; ret = ret && (i.first->second == c.second.value()); } } return trys > 0 && ret; } bool GeneralName::matches_ip(const std::string& nam) const { uint32_t ip = string_to_ipv4(nam); std::vector p = split_on(name(), '/'); if(p.size() != 2) throw Decoding_Error("failed to parse IPv4 address"); uint32_t net = string_to_ipv4(p.at(0)); uint32_t mask = string_to_ipv4(p.at(1)); return (ip & mask) == net; } std::ostream& operator<<(std::ostream& os, const GeneralName& gn) { os << gn.type() << ":" << gn.name(); return os; } GeneralSubtree::GeneralSubtree(const std::string& str) : GeneralSubtree() { size_t p0, p1; const auto min = std::stoull(str, &p0, 10); const auto max = std::stoull(str.substr(p0 + 1), &p1, 10); GeneralName gn(str.substr(p0 + p1 + 2)); if(p0 > 0 && p1 > 0) { m_minimum = static_cast(min); m_maximum = static_cast(max); m_base = gn; } else { throw Invalid_Argument("Failed to decode Name Constraint"); } } void GeneralSubtree::encode_into(DER_Encoder&) const { throw Not_Implemented("General Subtree encoding"); } void GeneralSubtree::decode_from(class BER_Decoder& ber) { ber.start_cons(SEQUENCE) .decode(m_base) .decode_optional(m_minimum,ASN1_Tag(0), CONTEXT_SPECIFIC,size_t(0)) .end_cons(); if(m_minimum != 0) throw Decoding_Error("GeneralSubtree minimum must be 0"); m_maximum = std::numeric_limits::max(); } std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs) { os << gs.minimum() << "," << gs.maximum() << "," << gs.base(); return os; } } /* * OCSP * (C) 2012,2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_HTTP_UTIL) #endif namespace Botan { namespace OCSP { namespace { // TODO: should this be in a header somewhere? void decode_optional_list(BER_Decoder& ber, ASN1_Tag tag, std::vector& output) { BER_Object obj = ber.get_next_object(); if(obj.is_a(tag, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) { ber.push_back(obj); return; } BER_Decoder list(obj); while(list.more_items()) { BER_Object certbits = list.get_next_object(); X509_Certificate cert(certbits.bits(), certbits.length()); output.push_back(std::move(cert)); } } } Request::Request(const X509_Certificate& issuer_cert, const X509_Certificate& subject_cert) : m_issuer(issuer_cert), m_certid(m_issuer, BigInt::decode(subject_cert.serial_number())) { if(subject_cert.issuer_dn() != issuer_cert.subject_dn()) throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)"); } Request::Request(const X509_Certificate& issuer_cert, const BigInt& subject_serial) : m_issuer(issuer_cert), m_certid(m_issuer, subject_serial) { } std::vector Request::BER_encode() const { std::vector output; DER_Encoder(output).start_cons(SEQUENCE) .start_cons(SEQUENCE) .start_explicit(0) .encode(static_cast(0)) // version # .end_explicit() .start_cons(SEQUENCE) .start_cons(SEQUENCE) .encode(m_certid) .end_cons() .end_cons() .end_cons() .end_cons(); return output; } std::string Request::base64_encode() const { return Botan::base64_encode(BER_encode()); } Response::Response(Certificate_Status_Code status) { m_status = Response_Status_Code::Successful; m_dummy_response_status = status; } Response::Response(const uint8_t response_bits[], size_t response_bits_len) : m_response_bits(response_bits, response_bits + response_bits_len) { m_dummy_response_status = Certificate_Status_Code::OCSP_RESPONSE_INVALID; BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE); size_t resp_status = 0; response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); m_status = static_cast(resp_status); if(m_status != Response_Status_Code::Successful) { return; } if(response_outer.more_items()) { BER_Decoder response_bytes = response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), "Unknown response type in OCSP response"); BER_Decoder basicresponse = BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); basicresponse.start_cons(SEQUENCE) .raw_bytes(m_tbs_bits) .end_cons() .decode(m_sig_algo) .decode(m_signature, BIT_STRING); decode_optional_list(basicresponse, ASN1_Tag(0), m_certs); size_t responsedata_version = 0; Extensions extensions; BER_Decoder(m_tbs_bits) .decode_optional(responsedata_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode_optional(m_signer_name, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode_optional_string(m_key_hash, OCTET_STRING, 2, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode(m_produced_at) .decode_list(m_responses) .decode_optional(extensions, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); } response_outer.end_cons(); } Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const { if (m_responses.empty()) return m_dummy_response_status; try { std::unique_ptr pub_key(issuer.subject_public_key()); const std::vector sig_info = split_on(m_sig_algo.get_oid().to_formatted_string(), '/'); if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) return Certificate_Status_Code::OCSP_RESPONSE_INVALID; std::string padding = sig_info[1]; const Signature_Format format = pub_key->default_x509_signature_format(); PK_Verifier verifier(*pub_key, padding, format); if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature)) return Certificate_Status_Code::OCSP_SIGNATURE_OK; else return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; } catch(Exception&) { return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; } } Certificate_Status_Code Response::check_signature(const std::vector& trusted_roots, const std::vector>& ee_cert_path) const { if (m_responses.empty()) return m_dummy_response_status; std::shared_ptr signing_cert; for(size_t i = 0; i != trusted_roots.size(); ++i) { if(m_signer_name.empty() && m_key_hash.empty()) return Certificate_Status_Code::OCSP_RESPONSE_INVALID; if(!m_signer_name.empty()) { signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector()); if(signing_cert) { break; } } if(m_key_hash.size() > 0) { signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash); if(signing_cert) { break; } } } if(!signing_cert && ee_cert_path.size() > 1) { // End entity cert is not allowed to sign their own OCSP request :) for(size_t i = 1; i < ee_cert_path.size(); ++i) { // Check all CA certificates in the (assumed validated) EE cert path if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name) { signing_cert = ee_cert_path[i]; break; } if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash) { signing_cert = ee_cert_path[i]; break; } } } if(!signing_cert && m_certs.size() > 0) { for(size_t i = 0; i < m_certs.size(); ++i) { // Check all CA certificates in the (assumed validated) EE cert path if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name) { signing_cert = std::make_shared(m_certs[i]); break; } if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash) { signing_cert = std::make_shared(m_certs[i]); break; } } } if(!signing_cert) return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND; if(!signing_cert->allowed_usage(CRL_SIGN) && !signing_cert->allowed_extended_usage("PKIX.OCSPSigning")) { return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE; } return this->verify_signature(*signing_cert); } Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, const X509_Certificate& subject, std::chrono::system_clock::time_point ref_time, std::chrono::seconds max_age) const { if(m_responses.empty()) { return m_dummy_response_status; } for(const auto& response : m_responses) { if(response.certid().is_id_for(issuer, subject)) { X509_Time x509_ref_time(ref_time); if(response.cert_status() == 1) { return Certificate_Status_Code::CERT_IS_REVOKED; } if(response.this_update() > x509_ref_time) { return Certificate_Status_Code::OCSP_NOT_YET_VALID; } if(response.next_update().time_is_set()) { if(x509_ref_time > response.next_update()) { return Certificate_Status_Code::OCSP_HAS_EXPIRED; } } else if(max_age > std::chrono::seconds::zero() && ref_time - response.this_update().to_std_timepoint() > max_age) { return Certificate_Status_Code::OCSP_IS_TOO_OLD; } if(response.cert_status() == 0) { return Certificate_Status_Code::OCSP_RESPONSE_GOOD; } else { return Certificate_Status_Code::OCSP_BAD_STATUS; } } } return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; } #if defined(BOTAN_HAS_HTTP_UTIL) Response online_check(const X509_Certificate& issuer, const BigInt& subject_serial, const std::string& ocsp_responder, Certificate_Store* trusted_roots, std::chrono::milliseconds timeout) { if(ocsp_responder.empty()) throw Invalid_Argument("No OCSP responder specified"); OCSP::Request req(issuer, subject_serial); auto http = HTTP::POST_sync(ocsp_responder, "application/ocsp-request", req.BER_encode(), 1, timeout); http.throw_unless_ok(); // Check the MIME type? OCSP::Response response(http.body()); std::vector trusted_roots_vec; trusted_roots_vec.push_back(trusted_roots); if(trusted_roots) response.check_signature(trusted_roots_vec); return response; } Response online_check(const X509_Certificate& issuer, const X509_Certificate& subject, Certificate_Store* trusted_roots, std::chrono::milliseconds timeout) { if(subject.issuer_dn() != issuer.subject_dn()) throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)"); return online_check(issuer, BigInt::decode(subject.serial_number()), subject.ocsp_responder(), trusted_roots, timeout); } #endif } } /* * OCSP subtypes * (C) 2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace OCSP { CertID::CertID(const X509_Certificate& issuer, const BigInt& subject_serial) { /* In practice it seems some responders, including, notably, ocsp.verisign.com, will reject anything but SHA-1 here */ std::unique_ptr hash(HashFunction::create_or_throw("SHA-160")); m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); m_issuer_key_hash = unlock(hash->process(issuer.subject_public_key_bitstring())); m_issuer_dn_hash = unlock(hash->process(issuer.raw_subject_dn())); m_subject_serial = subject_serial; } bool CertID::is_id_for(const X509_Certificate& issuer, const X509_Certificate& subject) const { try { if(BigInt::decode(subject.serial_number()) != m_subject_serial) return false; const std::string hash_algo = m_hash_id.get_oid().to_formatted_string(); std::unique_ptr hash = HashFunction::create_or_throw(hash_algo); if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) return false; if(m_issuer_key_hash != unlock(hash->process(issuer.subject_public_key_bitstring()))) return false; } catch(...) { return false; } return true; } void CertID::encode_into(class DER_Encoder& to) const { to.start_cons(SEQUENCE) .encode(m_hash_id) .encode(m_issuer_dn_hash, OCTET_STRING) .encode(m_issuer_key_hash, OCTET_STRING) .encode(m_subject_serial) .end_cons(); } void CertID::decode_from(class BER_Decoder& from) { from.start_cons(SEQUENCE) .decode(m_hash_id) .decode(m_issuer_dn_hash, OCTET_STRING) .decode(m_issuer_key_hash, OCTET_STRING) .decode(m_subject_serial) .end_cons(); } void SingleResponse::encode_into(class DER_Encoder&) const { throw Not_Implemented("SingleResponse::encode_into"); } void SingleResponse::decode_from(class BER_Decoder& from) { BER_Object cert_status; Extensions extensions; from.start_cons(SEQUENCE) .decode(m_certid) .get_next(cert_status) .decode(m_thisupdate) .decode_optional(m_nextupdate, ASN1_Tag(0), ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) .decode_optional(extensions, ASN1_Tag(1), ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) .end_cons(); m_cert_status = cert_status.type(); } } } /* * PKCS #10 * (C) 1999-2007,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { struct PKCS10_Data { X509_DN m_subject_dn; std::vector m_public_key_bits; AlternativeName m_alt_name; std::string m_challenge; Extensions m_extensions; }; std::string PKCS10_Request::PEM_label() const { return "CERTIFICATE REQUEST"; } std::vector PKCS10_Request::alternate_PEM_labels() const { return { "NEW CERTIFICATE REQUEST" }; } PKCS10_Request::PKCS10_Request(DataSource& src) { load_data(src); } PKCS10_Request::PKCS10_Request(const std::vector& vec) { DataSource_Memory src(vec.data(), vec.size()); load_data(src); } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) PKCS10_Request::PKCS10_Request(const std::string& fsname) { DataSource_Stream src(fsname, true); load_data(src); } #endif //static PKCS10_Request PKCS10_Request::create(const Private_Key& key, const X509_DN& subject_dn, const Extensions& extensions, const std::string& hash_fn, RandomNumberGenerator& rng, const std::string& padding_scheme, const std::string& challenge) { AlgorithmIdentifier sig_algo; std::unique_ptr signer = choose_sig_format(sig_algo, key, rng, hash_fn, padding_scheme); const size_t PKCS10_VERSION = 0; DER_Encoder tbs_req; tbs_req.start_cons(SEQUENCE) .encode(PKCS10_VERSION) .encode(subject_dn) .raw_bytes(key.subject_public_key()) .start_explicit(0); if(challenge.empty() == false) { std::vector value; DER_Encoder(value).encode(ASN1_String(challenge, DIRECTORY_STRING)); tbs_req.encode(Attribute("PKCS9.ChallengePassword", value)); } std::vector extension_req; DER_Encoder(extension_req).start_cons(SEQUENCE).encode(extensions).end_cons(); tbs_req.encode(Attribute("PKCS9.ExtensionRequest", extension_req)); // end the start_explicit above tbs_req.end_explicit().end_cons(); const std::vector req = X509_Object::make_signed(signer.get(), rng, sig_algo, tbs_req.get_contents()); return PKCS10_Request(req); } /* * Decode the CertificateRequestInfo */ namespace { std::unique_ptr decode_pkcs10(const std::vector& body) { std::unique_ptr data(new PKCS10_Data); BER_Decoder cert_req_info(body); size_t version; cert_req_info.decode(version); if(version != 0) throw Decoding_Error("Unknown version code in PKCS #10 request: " + std::to_string(version)); cert_req_info.decode(data->m_subject_dn); BER_Object public_key = cert_req_info.get_next_object(); if(public_key.is_a(SEQUENCE, CONSTRUCTED) == false) throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging()); data->m_public_key_bits = ASN1::put_in_sequence(public_key.bits(), public_key.length()); BER_Object attr_bits = cert_req_info.get_next_object(); std::set pkcs9_email; if(attr_bits.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { BER_Decoder attributes(attr_bits); while(attributes.more_items()) { Attribute attr; attributes.decode(attr); const OID& oid = attr.get_oid(); BER_Decoder value(attr.get_parameters()); if(oid == OID::from_string("PKCS9.EmailAddress")) { ASN1_String email; value.decode(email); pkcs9_email.insert(email.value()); } else if(oid == OID::from_string("PKCS9.ChallengePassword")) { ASN1_String challenge_password; value.decode(challenge_password); data->m_challenge = challenge_password.value(); } else if(oid == OID::from_string("PKCS9.ExtensionRequest")) { value.decode(data->m_extensions).verify_end(); } } attributes.verify_end(); } else if(attr_bits.is_set()) throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging()); cert_req_info.verify_end(); if(auto ext = data->m_extensions.get_extension_object_as()) { data->m_alt_name = ext->get_alt_name(); } for(std::string email : pkcs9_email) { data->m_alt_name.add_attribute("RFC882", email); } return data; } } void PKCS10_Request::force_decode() { m_data.reset(); std::unique_ptr data = decode_pkcs10(signed_body()); m_data.reset(data.release()); if(!this->check_signature(subject_public_key())) throw Decoding_Error("PKCS #10 request: Bad signature detected"); } const PKCS10_Data& PKCS10_Request::data() const { if(m_data == nullptr) throw Decoding_Error("PKCS10_Request decoding failed"); return *m_data.get(); } /* * Return the challenge password (if any) */ std::string PKCS10_Request::challenge_password() const { return data().m_challenge; } /* * Return the name of the requestor */ const X509_DN& PKCS10_Request::subject_dn() const { return data().m_subject_dn; } /* * Return the public key of the requestor */ const std::vector& PKCS10_Request::raw_public_key() const { return data().m_public_key_bits; } /* * Return the public key of the requestor */ Public_Key* PKCS10_Request::subject_public_key() const { DataSource_Memory source(raw_public_key()); return X509::load_key(source); } /* * Return the alternative names of the requestor */ const AlternativeName& PKCS10_Request::subject_alt_name() const { return data().m_alt_name; } /* * Return the X509v3 extensions */ const Extensions& PKCS10_Request::extensions() const { return data().m_extensions; } /* * Return the key constraints (if any) */ Key_Constraints PKCS10_Request::constraints() const { if(auto ext = extensions().get(OID::from_string("X509v3.KeyUsage"))) { return dynamic_cast(*ext).get_constraints(); } return NO_CONSTRAINTS; } /* * Return the extendend key constraints (if any) */ std::vector PKCS10_Request::ex_constraints() const { if(auto ext = extensions().get(OID::from_string("X509v3.ExtendedKeyUsage"))) { return dynamic_cast(*ext).get_oids(); } return {}; } /* * Return is a CA certificate is requested */ bool PKCS10_Request::is_CA() const { if(auto ext = extensions().get(OID::from_string("X509v3.BasicConstraints"))) { return dynamic_cast(*ext).get_is_ca(); } return false; } /* * Return the desired path limit (if any) */ size_t PKCS10_Request::path_limit() const { if(auto ext = extensions().get(OID::from_string("X509v3.BasicConstraints"))) { Cert_Extension::Basic_Constraints& basic_constraints = dynamic_cast(*ext); if(basic_constraints.get_is_ca()) { return basic_constraints.get_path_limit(); } } return 0; } } /* * Attribute * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Create an Attribute */ Attribute::Attribute(const OID& attr_oid, const std::vector& attr_value) : oid(attr_oid), parameters(attr_value) {} /* * Create an Attribute */ Attribute::Attribute(const std::string& attr_oid, const std::vector& attr_value) : oid(OID::from_string(attr_oid)), parameters(attr_value) {} /* * DER encode a Attribute */ void Attribute::encode_into(DER_Encoder& codec) const { codec.start_cons(SEQUENCE) .encode(oid) .start_cons(SET) .raw_bytes(parameters) .end_cons() .end_cons(); } /* * Decode a BER encoded Attribute */ void Attribute::decode_from(BER_Decoder& codec) { codec.start_cons(SEQUENCE) .decode(oid) .start_cons(SET) .raw_bytes(parameters) .end_cons() .end_cons(); } } /* * X.509 Certificate Authority * (C) 1999-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Load the certificate and private key */ X509_CA::X509_CA(const X509_Certificate& c, const Private_Key& key, const std::string& hash_fn, RandomNumberGenerator& rng) : m_ca_cert(c), m_hash_fn(hash_fn) { if(!m_ca_cert.is_CA_cert()) throw Invalid_Argument("X509_CA: This certificate is not for a CA"); std::map opts; // constructor without additional options: use the padding used in the CA certificate // sig_oid_str = /, so padding with all its options will look // like a cipher mode to the scanner std::string sig_oid_str = OIDS::oid2str_or_throw(c.signature_algorithm().get_oid()); SCAN_Name scanner(sig_oid_str); std::string pad = scanner.cipher_mode(); if(!pad.empty()) opts.insert({"padding",pad}); m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo)); } /* * Load the certificate and private key, and additional options */ X509_CA::X509_CA(const X509_Certificate& ca_certificate, const Private_Key& key, const std::map& opts, const std::string& hash_fn, RandomNumberGenerator& rng) : m_ca_cert(ca_certificate), m_hash_fn(hash_fn) { if(!m_ca_cert.is_CA_cert()) throw Invalid_Argument("X509_CA: This certificate is not for a CA"); m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo)); } /* * X509_CA Destructor */ X509_CA::~X509_CA() { /* for unique_ptr */ } namespace { Extensions choose_extensions(const PKCS10_Request& req, const X509_Certificate& ca_cert, const std::string& hash_fn) { Key_Constraints constraints; if(req.is_CA()) { constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); } else { std::unique_ptr key(req.subject_public_key()); verify_cert_constraints_valid_for_key_type(*key, req.constraints()); constraints = req.constraints(); } Extensions extensions = req.extensions(); extensions.replace( new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), true); if(constraints != NO_CONSTRAINTS) { extensions.replace(new Cert_Extension::Key_Usage(constraints), true); } extensions.replace(new Cert_Extension::Authority_Key_ID(ca_cert.subject_key_id())); extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key(), hash_fn)); extensions.replace( new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); extensions.replace( new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); return extensions; } } X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, RandomNumberGenerator& rng, const BigInt& serial_number, const X509_Time& not_before, const X509_Time& not_after) const { auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn); return make_cert(m_signer.get(), rng, serial_number, m_ca_sig_algo, req.raw_public_key(), not_before, not_after, m_ca_cert.subject_dn(), req.subject_dn(), extensions); } /* * Sign a PKCS #10 certificate request */ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, RandomNumberGenerator& rng, const X509_Time& not_before, const X509_Time& not_after) const { auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn); return make_cert(m_signer.get(), rng, m_ca_sig_algo, req.raw_public_key(), not_before, not_after, m_ca_cert.subject_dn(), req.subject_dn(), extensions); } X509_Certificate X509_CA::make_cert(PK_Signer* signer, RandomNumberGenerator& rng, const AlgorithmIdentifier& sig_algo, const std::vector& pub_key, const X509_Time& not_before, const X509_Time& not_after, const X509_DN& issuer_dn, const X509_DN& subject_dn, const Extensions& extensions) { const size_t SERIAL_BITS = 128; BigInt serial_no(rng, SERIAL_BITS); return make_cert(signer, rng, serial_no, sig_algo, pub_key, not_before, not_after, issuer_dn, subject_dn, extensions); } /* * Create a new certificate */ X509_Certificate X509_CA::make_cert(PK_Signer* signer, RandomNumberGenerator& rng, const BigInt& serial_no, const AlgorithmIdentifier& sig_algo, const std::vector& pub_key, const X509_Time& not_before, const X509_Time& not_after, const X509_DN& issuer_dn, const X509_DN& subject_dn, const Extensions& extensions) { const size_t X509_CERT_VERSION = 3; // clang-format off return X509_Certificate(X509_Object::make_signed( signer, rng, sig_algo, DER_Encoder().start_cons(SEQUENCE) .start_explicit(0) .encode(X509_CERT_VERSION-1) .end_explicit() .encode(serial_no) .encode(sig_algo) .encode(issuer_dn) .start_cons(SEQUENCE) .encode(not_before) .encode(not_after) .end_cons() .encode(subject_dn) .raw_bytes(pub_key) .start_explicit(3) .start_cons(SEQUENCE) .encode(extensions) .end_cons() .end_explicit() .end_cons() .get_contents() )); // clang-format on } /* * Create a new, empty CRL */ X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, uint32_t next_update) const { return new_crl(rng, std::chrono::system_clock::now(), std::chrono::seconds(next_update)); } /* * Update a CRL with new entries */ X509_CRL X509_CA::update_crl(const X509_CRL& crl, const std::vector& new_revoked, RandomNumberGenerator& rng, uint32_t next_update) const { return update_crl(crl, new_revoked, rng, std::chrono::system_clock::now(), std::chrono::seconds(next_update)); } X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const { std::vector empty; return make_crl(empty, 1, rng, issue_time, next_update); } X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, const std::vector& new_revoked, RandomNumberGenerator& rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const { std::vector revoked = last_crl.get_revoked(); std::copy(new_revoked.begin(), new_revoked.end(), std::back_inserter(revoked)); return make_crl(revoked, last_crl.crl_number() + 1, rng, issue_time, next_update); } /* * Create a CRL */ X509_CRL X509_CA::make_crl(const std::vector& revoked, uint32_t crl_number, RandomNumberGenerator& rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const { const size_t X509_CRL_VERSION = 2; auto expire_time = issue_time + next_update; Extensions extensions; extensions.add(new Cert_Extension::Authority_Key_ID(m_ca_cert.subject_key_id())); extensions.add(new Cert_Extension::CRL_Number(crl_number)); // clang-format off const std::vector crl = X509_Object::make_signed( m_signer.get(), rng, m_ca_sig_algo, DER_Encoder().start_cons(SEQUENCE) .encode(X509_CRL_VERSION-1) .encode(m_ca_sig_algo) .encode(m_ca_cert.subject_dn()) .encode(X509_Time(issue_time)) .encode(X509_Time(expire_time)) .encode_if(revoked.size() > 0, DER_Encoder() .start_cons(SEQUENCE) .encode_list(revoked) .end_cons() ) .start_explicit(0) .start_cons(SEQUENCE) .encode(extensions) .end_cons() .end_explicit() .end_cons() .get_contents()); // clang-format on return X509_CRL(crl); } /* * Return the CA's certificate */ X509_Certificate X509_CA::ca_certificate() const { return m_ca_cert; } /* * Choose a signing format for the key */ PK_Signer* choose_sig_format(const Private_Key& key, RandomNumberGenerator& rng, const std::string& hash_fn, AlgorithmIdentifier& sig_algo) { return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, "").release(); } PK_Signer* choose_sig_format(const Private_Key& key, const std::map& opts, RandomNumberGenerator& rng, const std::string& hash_fn, AlgorithmIdentifier& sig_algo) { std::string padding; if(opts.count("padding")) padding = opts.at("padding"); return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, padding).release(); } } /* * X.509 CRL * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { struct CRL_Data { X509_DN m_issuer; X509_Time m_this_update; X509_Time m_next_update; std::vector m_entries; Extensions m_extensions; // cached values from extensions size_t m_crl_number = 0; std::vector m_auth_key_id; std::string m_issuing_distribution_point; }; std::string X509_CRL::PEM_label() const { return "X509 CRL"; } std::vector X509_CRL::alternate_PEM_labels() const { return { "CRL" }; } X509_CRL::X509_CRL(DataSource& src) { load_data(src); } X509_CRL::X509_CRL(const std::vector& vec) { DataSource_Memory src(vec.data(), vec.size()); load_data(src); } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) X509_CRL::X509_CRL(const std::string& fsname) { DataSource_Stream src(fsname, true); load_data(src); } #endif X509_CRL::X509_CRL(const X509_DN& issuer, const X509_Time& this_update, const X509_Time& next_update, const std::vector& revoked) : X509_Object() { m_data.reset(new CRL_Data); m_data->m_issuer = issuer; m_data->m_this_update = this_update; m_data->m_next_update = next_update; m_data->m_entries = revoked; } /** * Check if this particular certificate is listed in the CRL */ bool X509_CRL::is_revoked(const X509_Certificate& cert) const { /* If the cert wasn't issued by the CRL issuer, it's possible the cert is revoked, but not by this CRL. Maybe throw an exception instead? */ if(cert.issuer_dn() != issuer_dn()) return false; std::vector crl_akid = authority_key_id(); std::vector cert_akid = cert.authority_key_id(); if(!crl_akid.empty() && !cert_akid.empty()) { if(crl_akid != cert_akid) return false; } std::vector cert_serial = cert.serial_number(); bool is_revoked = false; // FIXME would be nice to avoid a linear scan here - maybe sort the entries? for(const CRL_Entry& entry : get_revoked()) { if(cert_serial == entry.serial_number()) { if(entry.reason_code() == REMOVE_FROM_CRL) is_revoked = false; else is_revoked = true; } } return is_revoked; } /* * Decode the TBSCertList data */ namespace { std::unique_ptr decode_crl_body(const std::vector& body, const AlgorithmIdentifier& sig_algo) { std::unique_ptr data(new CRL_Data); BER_Decoder tbs_crl(body); size_t version; tbs_crl.decode_optional(version, INTEGER, UNIVERSAL); if(version != 0 && version != 1) throw X509_CRL::X509_CRL_Error("Unknown X.509 CRL version " + std::to_string(version+1)); AlgorithmIdentifier sig_algo_inner; tbs_crl.decode(sig_algo_inner); if(sig_algo != sig_algo_inner) throw X509_CRL::X509_CRL_Error("Algorithm identifier mismatch"); tbs_crl.decode(data->m_issuer) .decode(data->m_this_update) .decode(data->m_next_update); BER_Object next = tbs_crl.get_next_object(); if(next.is_a(SEQUENCE, CONSTRUCTED)) { BER_Decoder cert_list(std::move(next)); while(cert_list.more_items()) { CRL_Entry entry; cert_list.decode(entry); data->m_entries.push_back(entry); } next = tbs_crl.get_next_object(); } if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { BER_Decoder crl_options(std::move(next)); crl_options.decode(data->m_extensions).verify_end(); next = tbs_crl.get_next_object(); } if(next.is_set()) throw X509_CRL::X509_CRL_Error("Unknown tag in CRL"); tbs_crl.verify_end(); // Now cache some fields from the extensions if(auto ext = data->m_extensions.get_extension_object_as()) { data->m_crl_number = ext->get_crl_number(); } if(auto ext = data->m_extensions.get_extension_object_as()) { data->m_auth_key_id = ext->get_key_id(); } if(auto ext = data->m_extensions.get_extension_object_as()) { std::stringstream ss; for(const auto& pair : ext->get_point().contents()) { ss << pair.first << ": " << pair.second << " "; } data->m_issuing_distribution_point = ss.str(); } return data; } } void X509_CRL::force_decode() { m_data.reset(decode_crl_body(signed_body(), signature_algorithm()).release()); } const CRL_Data& X509_CRL::data() const { if(!m_data) { throw Invalid_State("X509_CRL uninitialized"); } return *m_data.get(); } const Extensions& X509_CRL::extensions() const { return data().m_extensions; } /* * Return the list of revoked certificates */ const std::vector& X509_CRL::get_revoked() const { return data().m_entries; } /* * Return the distinguished name of the issuer */ const X509_DN& X509_CRL::issuer_dn() const { return data().m_issuer; } /* * Return the key identifier of the issuer */ const std::vector& X509_CRL::authority_key_id() const { return data().m_auth_key_id; } /* * Return the CRL number of this CRL */ uint32_t X509_CRL::crl_number() const { return static_cast(data().m_crl_number); } /* * Return the issue data of the CRL */ const X509_Time& X509_CRL::this_update() const { return data().m_this_update; } /* * Return the date when a new CRL will be issued */ const X509_Time& X509_CRL::next_update() const { return data().m_next_update; } /* * Return the CRL's distribution point */ std::string X509_CRL::crl_issuing_distribution_point() const { return data().m_issuing_distribution_point; } } /* * X509_DN * (C) 1999-2007,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Add an attribute to a X509_DN */ void X509_DN::add_attribute(const std::string& type, const std::string& str) { add_attribute(OID::from_string(type), str); } /* * Add an attribute to a X509_DN */ void X509_DN::add_attribute(const OID& oid, const ASN1_String& str) { if(str.empty()) return; m_rdn.push_back(std::make_pair(oid, str)); m_dn_bits.clear(); } /* * Get the attributes of this X509_DN */ std::multimap X509_DN::get_attributes() const { std::multimap retval; for(auto& i : m_rdn) multimap_insert(retval, i.first, i.second.value()); return retval; } /* * Get the contents of this X.500 Name */ std::multimap X509_DN::contents() const { std::multimap retval; for(auto& i : m_rdn) { multimap_insert(retval, i.first.to_formatted_string(), i.second.value()); } return retval; } bool X509_DN::has_field(const std::string& attr) const { const OID o = OIDS::str2oid_or_empty(deref_info_field(attr)); if(o.has_value()) return has_field(o); else return false; } bool X509_DN::has_field(const OID& oid) const { for(auto& i : m_rdn) { if(i.first == oid) return true; } return false; } std::string X509_DN::get_first_attribute(const std::string& attr) const { const OID oid = OID::from_string(deref_info_field(attr)); return get_first_attribute(oid).value(); } ASN1_String X509_DN::get_first_attribute(const OID& oid) const { for(auto& i : m_rdn) { if(i.first == oid) { return i.second; } } return ASN1_String(); } /* * Get a single attribute type */ std::vector X509_DN::get_attribute(const std::string& attr) const { const OID oid = OID::from_string(deref_info_field(attr)); std::vector values; for(auto& i : m_rdn) { if(i.first == oid) { values.push_back(i.second.value()); } } return values; } /* * Deref aliases in a subject/issuer info request */ std::string X509_DN::deref_info_field(const std::string& info) { if(info == "Name" || info == "CommonName" || info == "CN") return "X520.CommonName"; if(info == "SerialNumber" || info == "SN") return "X520.SerialNumber"; if(info == "Country" || info == "C") return "X520.Country"; if(info == "Organization" || info == "O") return "X520.Organization"; if(info == "Organizational Unit" || info == "OrgUnit" || info == "OU") return "X520.OrganizationalUnit"; if(info == "Locality" || info == "L") return "X520.Locality"; if(info == "State" || info == "Province" || info == "ST") return "X520.State"; if(info == "Email") return "RFC822"; return info; } /* * Compare two X509_DNs for equality */ bool operator==(const X509_DN& dn1, const X509_DN& dn2) { auto attr1 = dn1.get_attributes(); auto attr2 = dn2.get_attributes(); if(attr1.size() != attr2.size()) return false; auto p1 = attr1.begin(); auto p2 = attr2.begin(); while(true) { if(p1 == attr1.end() && p2 == attr2.end()) break; if(p1 == attr1.end()) return false; if(p2 == attr2.end()) return false; if(p1->first != p2->first) return false; if(!x500_name_cmp(p1->second, p2->second)) return false; ++p1; ++p2; } return true; } /* * Compare two X509_DNs for inequality */ bool operator!=(const X509_DN& dn1, const X509_DN& dn2) { return !(dn1 == dn2); } /* * Induce an arbitrary ordering on DNs */ bool operator<(const X509_DN& dn1, const X509_DN& dn2) { auto attr1 = dn1.get_attributes(); auto attr2 = dn2.get_attributes(); // If they are not the same size, choose the smaller as the "lessor" if(attr1.size() < attr2.size()) return true; if(attr1.size() > attr2.size()) return false; // We know they are the same # of elements, now compare the OIDs: auto p1 = attr1.begin(); auto p2 = attr2.begin(); while(p1 != attr1.end() && p2 != attr2.end()) { if(p1->first != p2->first) { return (p1->first < p2->first); } ++p1; ++p2; } // We know this is true because maps have the same size BOTAN_ASSERT_NOMSG(p1 == attr1.end()); BOTAN_ASSERT_NOMSG(p2 == attr2.end()); // Now we know all elements have the same OIDs, compare // their string values: p1 = attr1.begin(); p2 = attr2.begin(); while(p1 != attr1.end() && p2 != attr2.end()) { BOTAN_DEBUG_ASSERT(p1->first == p2->first); // They may be binary different but same by X.500 rules, check this if(!x500_name_cmp(p1->second, p2->second)) { // If they are not (by X.500) the same string, pick the // lexicographic first as the lessor return (p1->second < p2->second); } ++p1; ++p2; } // if we reach here, then the DNs should be identical BOTAN_DEBUG_ASSERT(dn1 == dn2); return false; } /* * DER encode a DistinguishedName */ void X509_DN::encode_into(DER_Encoder& der) const { der.start_cons(SEQUENCE); if(!m_dn_bits.empty()) { /* If we decoded this from somewhere, encode it back exactly as we received it */ der.raw_bytes(m_dn_bits); } else { for(const auto& dn : m_rdn) { der.start_cons(SET) .start_cons(SEQUENCE) .encode(dn.first) .encode(dn.second) .end_cons() .end_cons(); } } der.end_cons(); } /* * Decode a BER encoded DistinguishedName */ void X509_DN::decode_from(BER_Decoder& source) { std::vector bits; source.start_cons(SEQUENCE) .raw_bytes(bits) .end_cons(); BER_Decoder sequence(bits); while(sequence.more_items()) { BER_Decoder rdn = sequence.start_cons(SET); while(rdn.more_items()) { OID oid; ASN1_String str; rdn.start_cons(SEQUENCE) .decode(oid) .decode(str) // TODO support Any .end_cons(); add_attribute(oid, str); } } m_dn_bits = bits; } namespace { std::string to_short_form(const OID& oid) { const std::string long_id = oid.to_formatted_string(); if(long_id == "X520.CommonName") return "CN"; if(long_id == "X520.Country") return "C"; if(long_id == "X520.Organization") return "O"; if(long_id == "X520.OrganizationalUnit") return "OU"; return long_id; } } std::string X509_DN::to_string() const { std::ostringstream out; out << *this; return out.str(); } std::ostream& operator<<(std::ostream& out, const X509_DN& dn) { auto info = dn.dn_info(); for(size_t i = 0; i != info.size(); ++i) { out << to_short_form(info[i].first) << "=\""; for(char c : info[i].second.value()) { if(c == '\\' || c == '\"') { out << "\\"; } out << c; } out << "\""; if(i + 1 < info.size()) { out << ","; } } return out; } std::istream& operator>>(std::istream& in, X509_DN& dn) { in >> std::noskipws; do { std::string key; std::string val; char c; while(in.good()) { in >> c; if(std::isspace(c) && key.empty()) continue; else if(!std::isspace(c)) { key.push_back(c); break; } else break; } while(in.good()) { in >> c; if(!std::isspace(c) && c != '=') key.push_back(c); else if(c == '=') break; else throw Invalid_Argument("Ill-formed X.509 DN"); } bool in_quotes = false; while(in.good()) { in >> c; if(std::isspace(c)) { if(!in_quotes && !val.empty()) break; else if(in_quotes) val.push_back(' '); } else if(c == '"') in_quotes = !in_quotes; else if(c == '\\') { if(in.good()) in >> c; val.push_back(c); } else if(c == ',' && !in_quotes) break; else val.push_back(c); } if(!key.empty() && !val.empty()) dn.add_attribute(X509_DN::deref_info_field(key),val); else break; } while(in.good()); return in; } } /* * DN_UB maps: Upper bounds on the length of DN strings * * This file was automatically generated by ./src/scripts/oids.py on 2019-10-21 * * All manual edits to this file will be lost. Edit the script * then regenerate this source file. * * Botan is released under the Simplified BSD License (see license.txt) */ namespace { /** * Upper bounds for the length of distinguished name fields as given in RFC 5280, Appendix A. * Only OIDS recognized by botan are considered, so far. * Maps OID string representations instead of human readable strings in order * to avoid an additional lookup. */ static const std::map DN_UB = { { Botan::OID({2,5,4,10}), 64 }, // X520.Organization { Botan::OID({2,5,4,11}), 64 }, // X520.OrganizationalUnit { Botan::OID({2,5,4,12}), 64 }, // X520.Title { Botan::OID({2,5,4,3}), 64 }, // X520.CommonName { Botan::OID({2,5,4,4}), 40 }, // X520.Surname { Botan::OID({2,5,4,42}), 32768 }, // X520.GivenName { Botan::OID({2,5,4,43}), 32768 }, // X520.Initials { Botan::OID({2,5,4,44}), 32768 }, // X520.GenerationalQualifier { Botan::OID({2,5,4,46}), 64 }, // X520.DNQualifier { Botan::OID({2,5,4,5}), 64 }, // X520.SerialNumber { Botan::OID({2,5,4,6}), 3 }, // X520.Country { Botan::OID({2,5,4,65}), 128 }, // X520.Pseudonym { Botan::OID({2,5,4,7}), 128 }, // X520.Locality { Botan::OID({2,5,4,8}), 128 }, // X520.State { Botan::OID({2,5,4,9}), 128 } // X520.StreetAddress }; } namespace Botan { //static size_t X509_DN::lookup_ub(const OID& oid) { auto ub_entry = DN_UB.find(oid); if(ub_entry != DN_UB.end()) { return ub_entry->second; } else { return 0; } } } /* * X.509 Certificate Extensions * (C) 1999-2010,2012 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Create a Certificate_Extension object of some kind to handle */ std::unique_ptr Extensions::create_extn_obj(const OID& oid, bool critical, const std::vector& body) { const std::string oid_str = oid.to_string(); std::unique_ptr extn; if(oid == Cert_Extension::Subject_Key_ID::static_oid()) { extn.reset(new Cert_Extension::Subject_Key_ID); } else if(oid == Cert_Extension::Key_Usage::static_oid()) { extn.reset(new Cert_Extension::Key_Usage); } else if(oid == Cert_Extension::Subject_Alternative_Name::static_oid()) { extn.reset(new Cert_Extension::Subject_Alternative_Name); } else if(oid == Cert_Extension::Issuer_Alternative_Name::static_oid()) { extn.reset(new Cert_Extension::Issuer_Alternative_Name); } else if(oid == Cert_Extension::Basic_Constraints::static_oid()) { extn.reset(new Cert_Extension::Basic_Constraints); } else if(oid == Cert_Extension::CRL_Number::static_oid()) { extn.reset(new Cert_Extension::CRL_Number); } else if(oid == Cert_Extension::CRL_ReasonCode::static_oid()) { extn.reset(new Cert_Extension::CRL_ReasonCode); } else if(oid == Cert_Extension::Authority_Key_ID::static_oid()) { extn.reset(new Cert_Extension::Authority_Key_ID); } else if(oid == Cert_Extension::Name_Constraints::static_oid()) { extn.reset(new Cert_Extension::Name_Constraints); } else if(oid == Cert_Extension::CRL_Distribution_Points::static_oid()) { extn.reset(new Cert_Extension::CRL_Distribution_Points); } else if(oid == Cert_Extension::CRL_Issuing_Distribution_Point::static_oid()) { extn.reset(new Cert_Extension::CRL_Issuing_Distribution_Point); } else if(oid == Cert_Extension::Certificate_Policies::static_oid()) { extn.reset(new Cert_Extension::Certificate_Policies); } else if(oid == Cert_Extension::Extended_Key_Usage::static_oid()) { extn.reset(new Cert_Extension::Extended_Key_Usage); } else if(oid == Cert_Extension::Authority_Information_Access::static_oid()) { extn.reset(new Cert_Extension::Authority_Information_Access); } else { // some other unknown extension type extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); } try { extn->decode_inner(body); } catch(Decoding_Error&) { extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); extn->decode_inner(body); } return extn; } /* * Validate the extension (the default implementation is a NOP) */ void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&, const std::vector>&, std::vector>&, size_t) { } /* * Add a new cert */ void Extensions::add(Certificate_Extension* extn, bool critical) { // sanity check: we don't want to have the same extension more than once if(m_extension_info.count(extn->oid_of()) > 0) { const std::string name = extn->oid_name(); delete extn; throw Invalid_Argument("Extension " + name + " already present in Extensions::add"); } const OID oid = extn->oid_of(); Extensions_Info info(critical, extn); m_extension_oids.push_back(oid); m_extension_info.emplace(oid, info); } bool Extensions::add_new(Certificate_Extension* extn, bool critical) { if(m_extension_info.count(extn->oid_of()) > 0) { delete extn; return false; // already exists } const OID oid = extn->oid_of(); Extensions_Info info(critical, extn); m_extension_oids.push_back(oid); m_extension_info.emplace(oid, info); return true; } bool Extensions::remove(const OID& oid) { const bool erased = m_extension_info.erase(oid) > 0; if(erased) { m_extension_oids.erase(std::find(m_extension_oids.begin(), m_extension_oids.end(), oid)); } return erased; } void Extensions::replace(Certificate_Extension* extn, bool critical) { // Remove it if it existed remove(extn->oid_of()); const OID oid = extn->oid_of(); Extensions_Info info(critical, extn); m_extension_oids.push_back(oid); m_extension_info.emplace(oid, info); } bool Extensions::extension_set(const OID& oid) const { return (m_extension_info.find(oid) != m_extension_info.end()); } bool Extensions::critical_extension_set(const OID& oid) const { auto i = m_extension_info.find(oid); if(i != m_extension_info.end()) return i->second.is_critical(); return false; } std::vector Extensions::get_extension_bits(const OID& oid) const { auto i = m_extension_info.find(oid); if(i == m_extension_info.end()) throw Invalid_Argument("Extensions::get_extension_bits no such extension set"); return i->second.bits(); } const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const { auto extn = m_extension_info.find(oid); if(extn == m_extension_info.end()) return nullptr; return &extn->second.obj(); } std::unique_ptr Extensions::get(const OID& oid) const { if(const Certificate_Extension* ext = this->get_extension_object(oid)) { return std::unique_ptr(ext->copy()); } return nullptr; } std::vector, bool>> Extensions::extensions() const { std::vector, bool>> exts; for(auto&& ext : m_extension_info) { exts.push_back( std::make_pair( std::unique_ptr(ext.second.obj().copy()), ext.second.is_critical()) ); } return exts; } std::map, bool>> Extensions::extensions_raw() const { std::map, bool>> out; for(auto&& ext : m_extension_info) { out.emplace(ext.first, std::make_pair(ext.second.bits(), ext.second.is_critical())); } return out; } /* * Encode an Extensions list */ void Extensions::encode_into(DER_Encoder& to_object) const { for(auto ext_info : m_extension_info) { const OID& oid = ext_info.first; const bool should_encode = ext_info.second.obj().should_encode(); if(should_encode) { const bool is_critical = ext_info.second.is_critical(); const std::vector& ext_value = ext_info.second.bits(); to_object.start_cons(SEQUENCE) .encode(oid) .encode_optional(is_critical, false) .encode(ext_value, OCTET_STRING) .end_cons(); } } } /* * Decode a list of Extensions */ void Extensions::decode_from(BER_Decoder& from_source) { m_extension_oids.clear(); m_extension_info.clear(); BER_Decoder sequence = from_source.start_cons(SEQUENCE); while(sequence.more_items()) { OID oid; bool critical; std::vector bits; sequence.start_cons(SEQUENCE) .decode(oid) .decode_optional(critical, BOOLEAN, UNIVERSAL, false) .decode(bits, OCTET_STRING) .end_cons(); std::unique_ptr obj = create_extn_obj(oid, critical, bits); Extensions_Info info(critical, bits, obj.release()); m_extension_oids.push_back(oid); m_extension_info.emplace(oid, info); } sequence.verify_end(); } /* * Write the extensions to an info store */ void Extensions::contents_to(Data_Store& subject_info, Data_Store& issuer_info) const { for(auto&& m_extn_info : m_extension_info) { m_extn_info.second.obj().contents_to(subject_info, issuer_info); subject_info.add(m_extn_info.second.obj().oid_name() + ".is_critical", m_extn_info.second.is_critical()); } } namespace Cert_Extension { /* * Checked accessor for the path_limit member */ size_t Basic_Constraints::get_path_limit() const { if(!m_is_ca) throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); return m_path_limit; } /* * Encode the extension */ std::vector Basic_Constraints::encode_inner() const { std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .encode_if(m_is_ca, DER_Encoder() .encode(m_is_ca) .encode_optional(m_path_limit, NO_CERT_PATH_LIMIT) ) .end_cons(); return output; } /* * Decode the extension */ void Basic_Constraints::decode_inner(const std::vector& in) { BER_Decoder(in) .start_cons(SEQUENCE) .decode_optional(m_is_ca, BOOLEAN, UNIVERSAL, false) .decode_optional(m_path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT) .end_cons(); if(m_is_ca == false) m_path_limit = 0; } /* * Return a textual representation */ void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const { subject.add("X509v3.BasicConstraints.is_ca", (m_is_ca ? 1 : 0)); subject.add("X509v3.BasicConstraints.path_constraint", static_cast(m_path_limit)); } /* * Encode the extension */ std::vector Key_Usage::encode_inner() const { if(m_constraints == NO_CONSTRAINTS) throw Encoding_Error("Cannot encode zero usage constraints"); const size_t unused_bits = ctz(static_cast(m_constraints)); std::vector der; der.push_back(BIT_STRING); der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); der.push_back(unused_bits % 8); der.push_back((m_constraints >> 8) & 0xFF); if(m_constraints & 0xFF) der.push_back(m_constraints & 0xFF); return der; } /* * Decode the extension */ void Key_Usage::decode_inner(const std::vector& in) { BER_Decoder ber(in); BER_Object obj = ber.get_next_object(); obj.assert_is_a(BIT_STRING, UNIVERSAL, "usage constraint"); if(obj.length() != 2 && obj.length() != 3) throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); uint16_t usage = 0; const uint8_t* bits = obj.bits(); if(bits[0] >= 8) throw BER_Decoding_Error("Invalid unused bits in usage constraint"); const uint8_t mask = static_cast(0xFF << bits[0]); if(obj.length() == 2) { usage = make_uint16(bits[1] & mask, 0); } else if(obj.length() == 3) { usage = make_uint16(bits[1], bits[2] & mask); } m_constraints = Key_Constraints(usage); } /* * Return a textual representation */ void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const { subject.add("X509v3.KeyUsage", m_constraints); } /* * Encode the extension */ std::vector Subject_Key_ID::encode_inner() const { std::vector output; DER_Encoder(output).encode(m_key_id, OCTET_STRING); return output; } /* * Decode the extension */ void Subject_Key_ID::decode_inner(const std::vector& in) { BER_Decoder(in).decode(m_key_id, OCTET_STRING).verify_end(); } /* * Return a textual representation */ void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const { subject.add("X509v3.SubjectKeyIdentifier", m_key_id); } /* * Subject_Key_ID Constructor */ Subject_Key_ID::Subject_Key_ID(const std::vector& pub_key, const std::string& hash_name) { std::unique_ptr hash(HashFunction::create_or_throw(hash_name)); m_key_id.resize(hash->output_length()); hash->update(pub_key); hash->final(m_key_id.data()); // Truncate longer hashes, 192 bits here seems plenty const size_t max_skid_len = (192 / 8); if(m_key_id.size() > max_skid_len) m_key_id.resize(max_skid_len); } /* * Encode the extension */ std::vector Authority_Key_ID::encode_inner() const { std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .encode(m_key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC) .end_cons(); return output; } /* * Decode the extension */ void Authority_Key_ID::decode_inner(const std::vector& in) { BER_Decoder(in) .start_cons(SEQUENCE) .decode_optional_string(m_key_id, OCTET_STRING, 0); } /* * Return a textual representation */ void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const { if(m_key_id.size()) issuer.add("X509v3.AuthorityKeyIdentifier", m_key_id); } /* * Encode the extension */ std::vector Subject_Alternative_Name::encode_inner() const { std::vector output; DER_Encoder(output).encode(m_alt_name); return output; } /* * Encode the extension */ std::vector Issuer_Alternative_Name::encode_inner() const { std::vector output; DER_Encoder(output).encode(m_alt_name); return output; } /* * Decode the extension */ void Subject_Alternative_Name::decode_inner(const std::vector& in) { BER_Decoder(in).decode(m_alt_name); } /* * Decode the extension */ void Issuer_Alternative_Name::decode_inner(const std::vector& in) { BER_Decoder(in).decode(m_alt_name); } /* * Return a textual representation */ void Subject_Alternative_Name::contents_to(Data_Store& subject_info, Data_Store&) const { subject_info.add(get_alt_name().contents()); } /* * Return a textual representation */ void Issuer_Alternative_Name::contents_to(Data_Store&, Data_Store& issuer_info) const { issuer_info.add(get_alt_name().contents()); } /* * Encode the extension */ std::vector Extended_Key_Usage::encode_inner() const { std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .encode_list(m_oids) .end_cons(); return output; } /* * Decode the extension */ void Extended_Key_Usage::decode_inner(const std::vector& in) { BER_Decoder(in).decode_list(m_oids); } /* * Return a textual representation */ void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const { for(size_t i = 0; i != m_oids.size(); ++i) subject.add("X509v3.ExtendedKeyUsage", m_oids[i].to_string()); } /* * Encode the extension */ std::vector Name_Constraints::encode_inner() const { throw Not_Implemented("Name_Constraints encoding"); } /* * Decode the extension */ void Name_Constraints::decode_inner(const std::vector& in) { std::vector permit, exclude; BER_Decoder ber(in); BER_Decoder ext = ber.start_cons(SEQUENCE); BER_Object per = ext.get_next_object(); ext.push_back(per); if(per.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { ext.decode_list(permit,ASN1_Tag(0),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); if(permit.empty()) throw Encoding_Error("Empty Name Contraint list"); } BER_Object exc = ext.get_next_object(); ext.push_back(exc); if(per.is_a(1, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { ext.decode_list(exclude,ASN1_Tag(1),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); if(exclude.empty()) throw Encoding_Error("Empty Name Contraint list"); } ext.end_cons(); if(permit.empty() && exclude.empty()) throw Encoding_Error("Empty Name Contraint extension"); m_name_constraints = NameConstraints(std::move(permit),std::move(exclude)); } /* * Return a textual representation */ void Name_Constraints::contents_to(Data_Store& subject, Data_Store&) const { std::stringstream ss; for(const GeneralSubtree& gs: m_name_constraints.permitted()) { ss << gs; subject.add("X509v3.NameConstraints.permitted", ss.str()); ss.str(std::string()); } for(const GeneralSubtree& gs: m_name_constraints.excluded()) { ss << gs; subject.add("X509v3.NameConstraints.excluded", ss.str()); ss.str(std::string()); } } void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer, const std::vector>& cert_path, std::vector>& cert_status, size_t pos) { if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) { if(!subject.is_CA_cert()) { cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); } const bool issuer_name_constraint_critical = issuer.is_critical("X509v3.NameConstraints"); // Check that all subordinate certs pass the name constraint for(size_t j = 0; j < pos; ++j) { bool permitted = m_name_constraints.permitted().empty(); bool failed = false; for(auto c: m_name_constraints.permitted()) { switch(c.base().matches(*cert_path.at(j))) { case GeneralName::MatchResult::NotFound: case GeneralName::MatchResult::All: permitted = true; break; case GeneralName::MatchResult::UnknownType: failed = issuer_name_constraint_critical; permitted = true; break; default: break; } } for(auto c: m_name_constraints.excluded()) { switch(c.base().matches(*cert_path.at(j))) { case GeneralName::MatchResult::All: case GeneralName::MatchResult::Some: failed = true; break; case GeneralName::MatchResult::UnknownType: failed = issuer_name_constraint_critical; break; default: break; } } if(failed || !permitted) { cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); } } } } namespace { /* * A policy specifier */ class Policy_Information final : public ASN1_Object { public: Policy_Information() = default; explicit Policy_Information(const OID& oid) : m_oid(oid) {} const OID& oid() const { return m_oid; } void encode_into(DER_Encoder& codec) const override { codec.start_cons(SEQUENCE) .encode(m_oid) .end_cons(); } void decode_from(BER_Decoder& codec) override { codec.start_cons(SEQUENCE) .decode(m_oid) .discard_remaining() .end_cons(); } private: OID m_oid; }; } /* * Encode the extension */ std::vector Certificate_Policies::encode_inner() const { std::vector policies; for(size_t i = 0; i != m_oids.size(); ++i) policies.push_back(Policy_Information(m_oids[i])); std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .encode_list(policies) .end_cons(); return output; } /* * Decode the extension */ void Certificate_Policies::decode_inner(const std::vector& in) { std::vector policies; BER_Decoder(in).decode_list(policies); m_oids.clear(); for(size_t i = 0; i != policies.size(); ++i) m_oids.push_back(policies[i].oid()); } /* * Return a textual representation */ void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const { for(size_t i = 0; i != m_oids.size(); ++i) info.add("X509v3.CertificatePolicies", m_oids[i].to_string()); } void Certificate_Policies::validate( const X509_Certificate& /*subject*/, const X509_Certificate& /*issuer*/, const std::vector>& /*cert_path*/, std::vector>& cert_status, size_t pos) { std::set oid_set(m_oids.begin(), m_oids.end()); if(oid_set.size() != m_oids.size()) { cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY); } } std::vector Authority_Information_Access::encode_inner() const { ASN1_String url(m_ocsp_responder, IA5_STRING); std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .start_cons(SEQUENCE) .encode(OID::from_string("PKIX.OCSP")) .add_object(ASN1_Tag(6), CONTEXT_SPECIFIC, url.value()) .end_cons() .end_cons(); return output; } void Authority_Information_Access::decode_inner(const std::vector& in) { BER_Decoder ber = BER_Decoder(in).start_cons(SEQUENCE); while(ber.more_items()) { OID oid; BER_Decoder info = ber.start_cons(SEQUENCE); info.decode(oid); if(oid == OID::from_string("PKIX.OCSP")) { BER_Object name = info.get_next_object(); if(name.is_a(6, CONTEXT_SPECIFIC)) { m_ocsp_responder = ASN1::to_string(name); } } if(oid == OID::from_string("PKIX.CertificateAuthorityIssuers")) { BER_Object name = info.get_next_object(); if(name.is_a(6, CONTEXT_SPECIFIC)) { m_ca_issuers.push_back(ASN1::to_string(name)); } } } } void Authority_Information_Access::contents_to(Data_Store& subject, Data_Store&) const { if(!m_ocsp_responder.empty()) subject.add("OCSP.responder", m_ocsp_responder); for(const std::string& ca_issuer : m_ca_issuers) subject.add("PKIX.CertificateAuthorityIssuers", ca_issuer); } /* * Checked accessor for the crl_number member */ size_t CRL_Number::get_crl_number() const { if(!m_has_value) throw Invalid_State("CRL_Number::get_crl_number: Not set"); return m_crl_number; } /* * Copy a CRL_Number extension */ CRL_Number* CRL_Number::copy() const { if(!m_has_value) throw Invalid_State("CRL_Number::copy: Not set"); return new CRL_Number(m_crl_number); } /* * Encode the extension */ std::vector CRL_Number::encode_inner() const { std::vector output; DER_Encoder(output).encode(m_crl_number); return output; } /* * Decode the extension */ void CRL_Number::decode_inner(const std::vector& in) { BER_Decoder(in).decode(m_crl_number); m_has_value = true; } /* * Return a textual representation */ void CRL_Number::contents_to(Data_Store& info, Data_Store&) const { info.add("X509v3.CRLNumber", static_cast(m_crl_number)); } /* * Encode the extension */ std::vector CRL_ReasonCode::encode_inner() const { std::vector output; DER_Encoder(output).encode(static_cast(m_reason), ENUMERATED, UNIVERSAL); return output; } /* * Decode the extension */ void CRL_ReasonCode::decode_inner(const std::vector& in) { size_t reason_code = 0; BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL); m_reason = static_cast(reason_code); } /* * Return a textual representation */ void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const { info.add("X509v3.CRLReasonCode", m_reason); } std::vector CRL_Distribution_Points::encode_inner() const { throw Not_Implemented("CRL_Distribution_Points encoding"); } void CRL_Distribution_Points::decode_inner(const std::vector& buf) { BER_Decoder(buf) .decode_list(m_distribution_points) .verify_end(); std::stringstream ss; for(size_t i = 0; i != m_distribution_points.size(); ++i) { auto contents = m_distribution_points[i].point().contents(); for(const auto& pair : contents) { ss << pair.first << ": " << pair.second << " "; } } m_crl_distribution_urls.push_back(ss.str()); } void CRL_Distribution_Points::contents_to(Data_Store& subject, Data_Store&) const { for(const std::string& crl_url : m_crl_distribution_urls) subject.add("CRL.DistributionPoint", crl_url); } void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const { throw Not_Implemented("CRL_Distribution_Points encoding"); } void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) { ber.start_cons(SEQUENCE) .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC) .decode_optional_implicit(m_point, ASN1_Tag(0), ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED), SEQUENCE, CONSTRUCTED) .end_cons().end_cons(); } std::vector CRL_Issuing_Distribution_Point::encode_inner() const { throw Not_Implemented("CRL_Issuing_Distribution_Point encoding"); } void CRL_Issuing_Distribution_Point::decode_inner(const std::vector& buf) { BER_Decoder(buf).decode(m_distribution_point).verify_end(); } void CRL_Issuing_Distribution_Point::contents_to(Data_Store& info, Data_Store&) const { auto contents = m_distribution_point.point().contents(); std::stringstream ss; for(const auto& pair : contents) { ss << pair.first << ": " << pair.second << " "; } info.add("X509v3.CRLIssuingDistributionPoint", ss.str()); } std::vector Unknown_Extension::encode_inner() const { return m_bytes; } void Unknown_Extension::decode_inner(const std::vector& bytes) { // Just treat as an opaque blob at this level m_bytes = bytes; } void Unknown_Extension::contents_to(Data_Store&, Data_Store&) const { // No information store } } } /* * X.509 SIGNED Object * (C) 1999-2007,2020 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { struct Pss_params { AlgorithmIdentifier hash_algo; AlgorithmIdentifier mask_gen_algo; AlgorithmIdentifier mask_gen_hash; // redundant: decoded mask_gen_algo.parameters size_t salt_len; size_t trailer_field; }; Pss_params decode_pss_params(const std::vector& encoded_pss_params) { const AlgorithmIdentifier default_hash("SHA-160", AlgorithmIdentifier::USE_NULL_PARAM); const AlgorithmIdentifier default_mgf("MGF1", default_hash.BER_encode()); Pss_params pss_parameter; BER_Decoder(encoded_pss_params) .start_cons(SEQUENCE) .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, default_hash) .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE, default_mgf) .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20)) .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1)) .end_cons(); BER_Decoder(pss_parameter.mask_gen_algo.get_parameters()).decode(pss_parameter.mask_gen_hash); return pss_parameter; } } /* * Read a PEM or BER X.509 object */ void X509_Object::load_data(DataSource& in) { try { if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) { BER_Decoder dec(in); decode_from(dec); } else { std::string got_label; DataSource_Memory ber(PEM_Code::decode(in, got_label)); if(got_label != PEM_label()) { bool is_alternate = false; for(std::string alt_label : alternate_PEM_labels()) { if(got_label == alt_label) { is_alternate = true; break; } } if(!is_alternate) throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label); } BER_Decoder dec(ber); decode_from(dec); } } catch(Decoding_Error& e) { throw Decoding_Error(PEM_label() + " decoding", e); } } void X509_Object::encode_into(DER_Encoder& to) const { to.start_cons(SEQUENCE) .start_cons(SEQUENCE) .raw_bytes(signed_body()) .end_cons() .encode(signature_algorithm()) .encode(signature(), BIT_STRING) .end_cons(); } /* * Read a BER encoded X.509 object */ void X509_Object::decode_from(BER_Decoder& from) { from.start_cons(SEQUENCE) .start_cons(SEQUENCE) .raw_bytes(m_tbs_bits) .end_cons() .decode(m_sig_algo) .decode(m_sig, BIT_STRING) .end_cons(); force_decode(); } /* * Return a PEM encoded X.509 object */ std::string X509_Object::PEM_encode() const { return PEM_Code::encode(BER_encode(), PEM_label()); } /* * Return the TBS data */ std::vector X509_Object::tbs_data() const { return ASN1::put_in_sequence(m_tbs_bits); } /* * Return the hash used in generating the signature */ std::string X509_Object::hash_used_for_signature() const { const OID& oid = m_sig_algo.get_oid(); const std::vector sig_info = split_on(oid.to_formatted_string(), '/'); if(sig_info.size() == 1 && sig_info[0] == "Ed25519") return "SHA-512"; else if(sig_info.size() != 2) throw Internal_Error("Invalid name format found for " + oid.to_string()); if(sig_info[1] == "EMSA4") { const OID hash_oid = decode_pss_params(signature_algorithm().get_parameters()).hash_algo.get_oid(); return hash_oid.to_formatted_string(); } else { const std::vector pad_and_hash = parse_algorithm_name(sig_info[1]); if(pad_and_hash.size() != 2) { throw Internal_Error("Invalid name format " + sig_info[1]); } return pad_and_hash[1]; } } /* * Check the signature on an object */ bool X509_Object::check_signature(const Public_Key* pub_key) const { if(!pub_key) throw Invalid_Argument("No key provided for " + PEM_label() + " signature check"); std::unique_ptr key(pub_key); return check_signature(*key); } bool X509_Object::check_signature(const Public_Key& pub_key) const { const Certificate_Status_Code code = verify_signature(pub_key); return (code == Certificate_Status_Code::VERIFIED); } Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const { const std::vector sig_info = split_on(m_sig_algo.get_oid().to_formatted_string(), '/'); if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name()) return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; const std::string pub_key_algo = sig_info[0]; std::string padding; if(sig_info.size() == 2) padding = sig_info[1]; else if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS") padding = "Pure"; else return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; const Signature_Format format = pub_key.default_x509_signature_format(); if(padding == "EMSA4") { // "MUST contain RSASSA-PSS-params" if(signature_algorithm().get_parameters().empty()) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } Pss_params pss_parameter = decode_pss_params(signature_algorithm().get_parameters()); // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 const std::string hash_algo = pss_parameter.hash_algo.get_oid().to_formatted_string(); if(hash_algo != "SHA-160" && hash_algo != "SHA-224" && hash_algo != "SHA-256" && hash_algo != "SHA-384" && hash_algo != "SHA-512") { return Certificate_Status_Code::UNTRUSTED_HASH; } const std::string mgf_algo = pss_parameter.mask_gen_algo.get_oid().to_formatted_string(); if(mgf_algo != "MGF1") { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 if(pss_parameter.mask_gen_hash.get_oid() != pss_parameter.hash_algo.get_oid()) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } if(pss_parameter.trailer_field != 1) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")"; } else { /* * For all other signature types the signature parameters should * be either NULL or empty. In theory there is some distinction between * these but in practice they seem to be used somewhat interchangeably. * * The various RFCs all have prescriptions of what is allowed: * RSA - NULL (RFC 3279) * DSA - empty (RFC 3279) * ECDSA - empty (RFC 3279) * GOST - empty (RFC 4491) * Ed25519 - empty (RFC 8410) * XMSS - empty (draft-vangeest-x509-hash-sigs) * * But in practice we find RSA with empty and ECDSA will NULL all * over the place so it's not really possible to enforce. For Ed25519 * and XMSS because they are new we attempt to enforce. */ if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS") { if(!signature_algorithm().parameters_are_empty()) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } } else { if(!signature_algorithm().parameters_are_null_or_empty()) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } } } try { PK_Verifier verifier(pub_key, padding, format); const bool valid = verifier.verify_message(tbs_data(), signature()); if(valid) return Certificate_Status_Code::VERIFIED; else return Certificate_Status_Code::SIGNATURE_ERROR; } catch(Algorithm_Not_Found&) { return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN; } catch(...) { // This shouldn't happen, fallback to generic signature error return Certificate_Status_Code::SIGNATURE_ERROR; } } /* * Apply the X.509 SIGNED macro */ std::vector X509_Object::make_signed(PK_Signer* signer, RandomNumberGenerator& rng, const AlgorithmIdentifier& algo, const secure_vector& tbs_bits) { const std::vector signature = signer->sign_message(tbs_bits, rng); std::vector output; DER_Encoder(output) .start_cons(SEQUENCE) .raw_bytes(tbs_bits) .encode(algo) .encode(signature, BIT_STRING) .end_cons(); return output; } namespace { std::string choose_sig_algo(AlgorithmIdentifier& sig_algo, const Private_Key& key, const std::string& hash_fn, const std::string& user_specified) { const std::string algo_name = key.algo_name(); std::string padding; // check algo_name and set default if(algo_name == "RSA") { // set to EMSA3 for compatibility reasons, originally it was the only option padding = "EMSA3(" + hash_fn + ")"; } else if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA" || algo_name == "GOST-34.10" || algo_name == "GOST-34.10-2012-256" || algo_name == "GOST-34.10-2012-512") { padding = "EMSA1(" + hash_fn + ")"; } else if(algo_name == "Ed25519") { padding = "Pure"; } else if(algo_name == "XMSS") { if(user_specified.empty() == true) { throw Invalid_Argument("XMSS requires padding scheme"); } padding = user_specified; sig_algo = AlgorithmIdentifier(OID::from_string("XMSS"), AlgorithmIdentifier::USE_EMPTY_PARAM); return padding; } else { throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); } if(user_specified.empty() == false) { padding = user_specified; } if(padding != "Pure") { // try to construct an EMSA object from the padding options or default std::unique_ptr emsa; try { emsa.reset(get_emsa(padding)); } /* * get_emsa will throw if opts contains {"padding",} but * does not specify a hash function. * Omitting it is valid since it needs to be identical to hash_fn. * If it still throws, something happened that we cannot repair here, * e.g. the algorithm/padding combination is not supported. */ catch(...) { emsa.reset(get_emsa(padding + "(" + hash_fn + ")")); } if(!emsa) { throw Invalid_Argument("Could not parse padding scheme " + padding); } sig_algo = emsa->config_for_x509(key, hash_fn); return emsa->name(); } else { sig_algo = AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM); return "Pure"; } } } /* * Choose a signing format for the key */ std::unique_ptr X509_Object::choose_sig_format(AlgorithmIdentifier& sig_algo, const Private_Key& key, RandomNumberGenerator& rng, const std::string& hash_fn, const std::string& padding_algo) { const Signature_Format format = key.default_x509_signature_format(); const std::string emsa = choose_sig_algo(sig_algo, key, hash_fn, padding_algo); return std::unique_ptr(new PK_Signer(key, rng, emsa, format)); } } /* * X.509 Certificates * (C) 1999-2010,2015,2017 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { struct X509_Certificate_Data { std::vector m_serial; AlgorithmIdentifier m_sig_algo_inner; X509_DN m_issuer_dn; X509_DN m_subject_dn; std::vector m_issuer_dn_bits; std::vector m_subject_dn_bits; X509_Time m_not_before; X509_Time m_not_after; std::vector m_subject_public_key_bits; std::vector m_subject_public_key_bits_seq; std::vector m_subject_public_key_bitstring; std::vector m_subject_public_key_bitstring_sha1; AlgorithmIdentifier m_subject_public_key_algid; std::vector m_v2_issuer_key_id; std::vector m_v2_subject_key_id; Extensions m_v3_extensions; std::vector m_extended_key_usage; std::vector m_authority_key_id; std::vector m_subject_key_id; std::vector m_cert_policies; std::vector m_crl_distribution_points; std::string m_ocsp_responder; std::vector m_ca_issuers; std::vector m_issuer_dn_bits_sha256; std::vector m_subject_dn_bits_sha256; std::string m_fingerprint_sha1; std::string m_fingerprint_sha256; AlternativeName m_subject_alt_name; AlternativeName m_issuer_alt_name; NameConstraints m_name_constraints; Data_Store m_subject_ds; Data_Store m_issuer_ds; size_t m_version = 0; size_t m_path_len_constraint = 0; Key_Constraints m_key_constraints = NO_CONSTRAINTS; bool m_self_signed = false; bool m_is_ca_certificate = false; bool m_serial_negative = false; }; std::string X509_Certificate::PEM_label() const { return "CERTIFICATE"; } std::vector X509_Certificate::alternate_PEM_labels() const { return { "X509 CERTIFICATE" }; } X509_Certificate::X509_Certificate(DataSource& src) { load_data(src); } X509_Certificate::X509_Certificate(const std::vector& vec) { DataSource_Memory src(vec.data(), vec.size()); load_data(src); } X509_Certificate::X509_Certificate(const uint8_t data[], size_t len) { DataSource_Memory src(data, len); load_data(src); } #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) X509_Certificate::X509_Certificate(const std::string& fsname) { DataSource_Stream src(fsname, true); load_data(src); } #endif namespace { std::unique_ptr parse_x509_cert_body(const X509_Object& obj) { std::unique_ptr data(new X509_Certificate_Data); BigInt serial_bn; BER_Object public_key; BER_Object v3_exts_data; BER_Decoder(obj.signed_body()) .decode_optional(data->m_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode(serial_bn) .decode(data->m_sig_algo_inner) .decode(data->m_issuer_dn) .start_cons(SEQUENCE) .decode(data->m_not_before) .decode(data->m_not_after) .end_cons() .decode(data->m_subject_dn) .get_next(public_key) .decode_optional_string(data->m_v2_issuer_key_id, BIT_STRING, 1) .decode_optional_string(data->m_v2_subject_key_id, BIT_STRING, 2) .get_next(v3_exts_data) .verify_end("TBSCertificate has extra data after extensions block"); if(data->m_version > 2) throw Decoding_Error("Unknown X.509 cert version " + std::to_string(data->m_version)); if(obj.signature_algorithm() != data->m_sig_algo_inner) throw Decoding_Error("X.509 Certificate had differing algorithm identifers in inner and outer ID fields"); public_key.assert_is_a(SEQUENCE, CONSTRUCTED, "X.509 certificate public key"); // crude method to save the serial's sign; will get lost during decoding, otherwise data->m_serial_negative = serial_bn.is_negative(); // for general sanity convert wire version (0 based) to standards version (v1 .. v3) data->m_version += 1; data->m_serial = BigInt::encode(serial_bn); data->m_subject_dn_bits = ASN1::put_in_sequence(data->m_subject_dn.get_bits()); data->m_issuer_dn_bits = ASN1::put_in_sequence(data->m_issuer_dn.get_bits()); // validate_public_key_params(public_key.value); AlgorithmIdentifier public_key_alg_id; BER_Decoder(public_key).decode(public_key_alg_id).discard_remaining(); const std::vector public_key_info = split_on(OIDS::oid2str_or_empty(public_key_alg_id.get_oid()), '/'); if(!public_key_info.empty() && public_key_info[0] == "RSA") { // RFC4055: If PublicKeyAlgo = PSS or OAEP: limit the use of the public key exclusively to either RSASSA - PSS or RSAES - OAEP if(public_key_info.size() >= 2) { if(public_key_info[1] == "EMSA4") { /* When the RSA private key owner wishes to limit the use of the public key exclusively to RSASSA-PSS, then the id-RSASSA-PSS object identifier MUST be used in the algorithm field within the subject public key information, and, if present, the parameters field MUST contain RSASSA-PSS-params. All parameters in the signature structure algorithm identifier MUST match the parameters in the key structure algorithm identifier except the saltLength field. The saltLength field in the signature parameters MUST be greater or equal to that in the key parameters field. ToDo: Allow salt length to be greater */ if(public_key_alg_id != obj.signature_algorithm()) { throw Decoding_Error("Algorithm identifier mismatch"); } } } else { // oid = rsaEncryption -> parameters field MUST contain NULL if(public_key_alg_id != AlgorithmIdentifier(public_key_alg_id.get_oid(), AlgorithmIdentifier::USE_NULL_PARAM)) { throw Decoding_Error("RSA algorithm parameters field MUST contain NULL"); } } } data->m_subject_public_key_bits.assign(public_key.bits(), public_key.bits() + public_key.length()); data->m_subject_public_key_bits_seq = ASN1::put_in_sequence(data->m_subject_public_key_bits); BER_Decoder(data->m_subject_public_key_bits) .decode(data->m_subject_public_key_algid) .decode(data->m_subject_public_key_bitstring, BIT_STRING); if(v3_exts_data.is_a(3, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { // Path validation will reject a v1/v2 cert with v3 extensions BER_Decoder(v3_exts_data).decode(data->m_v3_extensions).verify_end(); } else if(v3_exts_data.is_set()) { throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging()); } // Now cache some fields from the extensions if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_key_constraints = ext->get_constraints(); /* RFC 5280: When the keyUsage extension appears in a certificate, at least one of the bits MUST be set to 1. */ if(data->m_key_constraints == NO_CONSTRAINTS) { throw Decoding_Error("Certificate has invalid encoding for KeyUsage"); } } else { data->m_key_constraints = NO_CONSTRAINTS; } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_subject_key_id = ext->get_key_id(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_authority_key_id = ext->get_key_id(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_name_constraints = ext->get_name_constraints(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { if(ext->get_is_ca() == true) { /* * RFC 5280 section 4.2.1.3 requires that CAs include KeyUsage in all * intermediate CA certificates they issue. Currently we accept it being * missing, as do most other implementations. But it may be worth * removing this entirely, or alternately adding a warning level * validation failure for it. */ if(data->m_key_constraints == NO_CONSTRAINTS || (data->m_key_constraints & KEY_CERT_SIGN)) { data->m_is_ca_certificate = true; data->m_path_len_constraint = ext->get_path_limit(); } } } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_issuer_alt_name = ext->get_alt_name(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_subject_alt_name = ext->get_alt_name(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_extended_key_usage = ext->get_oids(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_cert_policies = ext->get_policy_oids(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_ocsp_responder = ext->ocsp_responder(); data->m_ca_issuers = ext->ca_issuers(); } if(auto ext = data->m_v3_extensions.get_extension_object_as()) { data->m_crl_distribution_points = ext->crl_distribution_urls(); } // Check for self-signed vs self-issued certificates if(data->m_subject_dn == data->m_issuer_dn) { if(data->m_subject_key_id.empty() == false && data->m_authority_key_id.empty() == false) { data->m_self_signed = (data->m_subject_key_id == data->m_authority_key_id); } else { /* If a parse error or unknown algorithm is encountered, default to assuming it is self signed. We have no way of being certain but that is usually the default case (self-issued is rare in practice). */ data->m_self_signed = true; try { std::unique_ptr pub_key(X509::load_key(data->m_subject_public_key_bits_seq)); Certificate_Status_Code sig_status = obj.verify_signature(*pub_key); if(sig_status == Certificate_Status_Code::OK || sig_status == Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN) { data->m_self_signed = true; } else { data->m_self_signed = false; } } catch(...) { // ignore errors here to allow parsing to continue } } } const std::vector full_encoding = obj.BER_encode(); std::unique_ptr sha1(HashFunction::create("SHA-1")); if(sha1) { sha1->update(data->m_subject_public_key_bitstring); data->m_subject_public_key_bitstring_sha1 = sha1->final_stdvec(); // otherwise left as empty, and we will throw if subject_public_key_bitstring_sha1 is called data->m_fingerprint_sha1 = create_hex_fingerprint(full_encoding, "SHA-1"); } std::unique_ptr sha256(HashFunction::create("SHA-256")); if(sha256) { sha256->update(data->m_issuer_dn_bits); data->m_issuer_dn_bits_sha256 = sha256->final_stdvec(); sha256->update(data->m_subject_dn_bits); data->m_subject_dn_bits_sha256 = sha256->final_stdvec(); data->m_fingerprint_sha256 = create_hex_fingerprint(full_encoding, "SHA-256"); } data->m_subject_ds.add(data->m_subject_dn.contents()); data->m_issuer_ds.add(data->m_issuer_dn.contents()); data->m_v3_extensions.contents_to(data->m_subject_ds, data->m_issuer_ds); return data; } } /* * Decode the TBSCertificate data */ void X509_Certificate::force_decode() { m_data.reset(); std::unique_ptr data = parse_x509_cert_body(*this); m_data.reset(data.release()); } const X509_Certificate_Data& X509_Certificate::data() const { if(m_data == nullptr) { throw Invalid_State("X509_Certificate uninitialized"); } return *m_data.get(); } uint32_t X509_Certificate::x509_version() const { return static_cast(data().m_version); } bool X509_Certificate::is_self_signed() const { return data().m_self_signed; } const X509_Time& X509_Certificate::not_before() const { return data().m_not_before; } const X509_Time& X509_Certificate::not_after() const { return data().m_not_after; } const AlgorithmIdentifier& X509_Certificate::subject_public_key_algo() const { return data().m_subject_public_key_algid; } const std::vector& X509_Certificate::v2_issuer_key_id() const { return data().m_v2_issuer_key_id; } const std::vector& X509_Certificate::v2_subject_key_id() const { return data().m_v2_subject_key_id; } const std::vector& X509_Certificate::subject_public_key_bits() const { return data().m_subject_public_key_bits; } const std::vector& X509_Certificate::subject_public_key_info() const { return data().m_subject_public_key_bits_seq; } const std::vector& X509_Certificate::subject_public_key_bitstring() const { return data().m_subject_public_key_bitstring; } const std::vector& X509_Certificate::subject_public_key_bitstring_sha1() const { if(data().m_subject_public_key_bitstring_sha1.empty()) throw Encoding_Error("X509_Certificate::subject_public_key_bitstring_sha1 called but SHA-1 disabled in build"); return data().m_subject_public_key_bitstring_sha1; } const std::vector& X509_Certificate::authority_key_id() const { return data().m_authority_key_id; } const std::vector& X509_Certificate::subject_key_id() const { return data().m_subject_key_id; } const std::vector& X509_Certificate::serial_number() const { return data().m_serial; } bool X509_Certificate::is_serial_negative() const { return data().m_serial_negative; } const X509_DN& X509_Certificate::issuer_dn() const { return data().m_issuer_dn; } const X509_DN& X509_Certificate::subject_dn() const { return data().m_subject_dn; } const std::vector& X509_Certificate::raw_issuer_dn() const { return data().m_issuer_dn_bits; } const std::vector& X509_Certificate::raw_subject_dn() const { return data().m_subject_dn_bits; } bool X509_Certificate::is_CA_cert() const { if(data().m_version < 3 && data().m_self_signed) return true; return data().m_is_ca_certificate; } uint32_t X509_Certificate::path_limit() const { if(data().m_version < 3 && data().m_self_signed) return 32; // in theory infinite, but this is more than enough return static_cast(data().m_path_len_constraint); } Key_Constraints X509_Certificate::constraints() const { return data().m_key_constraints; } const std::vector& X509_Certificate::extended_key_usage() const { return data().m_extended_key_usage; } const std::vector& X509_Certificate::certificate_policy_oids() const { return data().m_cert_policies; } const NameConstraints& X509_Certificate::name_constraints() const { return data().m_name_constraints; } const Extensions& X509_Certificate::v3_extensions() const { return data().m_v3_extensions; } bool X509_Certificate::allowed_usage(Key_Constraints usage) const { if(constraints() == NO_CONSTRAINTS) return true; return ((constraints() & usage) == usage); } bool X509_Certificate::allowed_extended_usage(const std::string& usage) const { return allowed_extended_usage(OID::from_string(usage)); } bool X509_Certificate::allowed_extended_usage(const OID& usage) const { const std::vector& ex = extended_key_usage(); if(ex.empty()) return true; if(std::find(ex.begin(), ex.end(), usage) != ex.end()) return true; return false; } bool X509_Certificate::allowed_usage(Usage_Type usage) const { // These follow suggestions in RFC 5280 4.2.1.12 switch(usage) { case Usage_Type::UNSPECIFIED: return true; case Usage_Type::TLS_SERVER_AUTH: return (allowed_usage(KEY_AGREEMENT) || allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DIGITAL_SIGNATURE)) && allowed_extended_usage("PKIX.ServerAuth"); case Usage_Type::TLS_CLIENT_AUTH: return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(KEY_AGREEMENT)) && allowed_extended_usage("PKIX.ClientAuth"); case Usage_Type::OCSP_RESPONDER: return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(NON_REPUDIATION)) && allowed_extended_usage("PKIX.OCSPSigning"); case Usage_Type::CERTIFICATE_AUTHORITY: return is_CA_cert(); case Usage_Type::ENCRYPTION: return (allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DATA_ENCIPHERMENT)); } return false; } bool X509_Certificate::has_constraints(Key_Constraints constraints) const { if(this->constraints() == NO_CONSTRAINTS) { return false; } return ((this->constraints() & constraints) != 0); } bool X509_Certificate::has_ex_constraint(const std::string& ex_constraint) const { return has_ex_constraint(OID::from_string(ex_constraint)); } bool X509_Certificate::has_ex_constraint(const OID& usage) const { const std::vector& ex = extended_key_usage(); return (std::find(ex.begin(), ex.end(), usage) != ex.end()); } /* * Return if a certificate extension is marked critical */ bool X509_Certificate::is_critical(const std::string& ex_name) const { return v3_extensions().critical_extension_set(OID::from_string(ex_name)); } std::string X509_Certificate::ocsp_responder() const { return data().m_ocsp_responder; } std::vector X509_Certificate::ca_issuers() const { return data().m_ca_issuers; } std::string X509_Certificate::crl_distribution_point() const { // just returns the first (arbitrarily) if(data().m_crl_distribution_points.size() > 0) return data().m_crl_distribution_points[0]; return ""; } const AlternativeName& X509_Certificate::subject_alt_name() const { return data().m_subject_alt_name; } const AlternativeName& X509_Certificate::issuer_alt_name() const { return data().m_issuer_alt_name; } /* * Return information about the subject */ std::vector X509_Certificate::subject_info(const std::string& req) const { if(req == "Email") return this->subject_info("RFC822"); if(subject_dn().has_field(req)) return subject_dn().get_attribute(req); if(subject_alt_name().has_field(req)) return subject_alt_name().get_attribute(req); // These will be removed later: if(req == "X509.Certificate.v2.key_id") return {hex_encode(this->v2_subject_key_id())}; if(req == "X509v3.SubjectKeyIdentifier") return {hex_encode(this->subject_key_id())}; if(req == "X509.Certificate.dn_bits") return {hex_encode(this->raw_subject_dn())}; if(req == "X509.Certificate.start") return {not_before().to_string()}; if(req == "X509.Certificate.end") return {not_after().to_string()}; if(req == "X509.Certificate.version") return {std::to_string(x509_version())}; if(req == "X509.Certificate.serial") return {hex_encode(serial_number())}; return data().m_subject_ds.get(req); } /* * Return information about the issuer */ std::vector X509_Certificate::issuer_info(const std::string& req) const { if(issuer_dn().has_field(req)) return issuer_dn().get_attribute(req); if(issuer_alt_name().has_field(req)) return issuer_alt_name().get_attribute(req); // These will be removed later: if(req == "X509.Certificate.v2.key_id") return {hex_encode(this->v2_issuer_key_id())}; if(req == "X509v3.AuthorityKeyIdentifier") return {hex_encode(this->authority_key_id())}; if(req == "X509.Certificate.dn_bits") return {hex_encode(this->raw_issuer_dn())}; return data().m_issuer_ds.get(req); } /* * Return the public key in this certificate */ std::unique_ptr X509_Certificate::load_subject_public_key() const { try { return std::unique_ptr(X509::load_key(subject_public_key_info())); } catch(std::exception& e) { throw Decoding_Error("X509_Certificate::load_subject_public_key", e); } } Public_Key* X509_Certificate::subject_public_key() const { return load_subject_public_key().release(); } std::vector X509_Certificate::raw_issuer_dn_sha256() const { if(data().m_issuer_dn_bits_sha256.empty()) throw Encoding_Error("X509_Certificate::raw_issuer_dn_sha256 called but SHA-256 disabled in build"); return data().m_issuer_dn_bits_sha256; } std::vector X509_Certificate::raw_subject_dn_sha256() const { if(data().m_subject_dn_bits_sha256.empty()) throw Encoding_Error("X509_Certificate::raw_subject_dn_sha256 called but SHA-256 disabled in build"); return data().m_subject_dn_bits_sha256; } namespace { /* * Lookup each OID in the vector */ std::vector lookup_oids(const std::vector& oids) { std::vector out; for(const OID& oid : oids) { out.push_back(oid.to_formatted_string()); } return out; } } /* * Return the list of extended key usage OIDs */ std::vector X509_Certificate::ex_constraints() const { return lookup_oids(extended_key_usage()); } /* * Return the list of certificate policies */ std::vector X509_Certificate::policies() const { return lookup_oids(certificate_policy_oids()); } std::string X509_Certificate::fingerprint(const std::string& hash_name) const { /* * The SHA-1 and SHA-256 fingerprints are precomputed since these * are the most commonly used. Especially, SHA-256 fingerprints are * used for cycle detection during path construction. * * If SHA-1 or SHA-256 was missing at parsing time the vectors are * left empty in which case we fall back to create_hex_fingerprint * which will throw if the hash is unavailable. */ if(hash_name == "SHA-256" && data().m_fingerprint_sha256.size() > 0) return data().m_fingerprint_sha256; else if(hash_name == "SHA-1" && data().m_fingerprint_sha1.size() > 0) return data().m_fingerprint_sha1; else return create_hex_fingerprint(this->BER_encode(), hash_name); } bool X509_Certificate::matches_dns_name(const std::string& name) const { if(name.empty()) return false; std::vector issued_names = subject_info("DNS"); // Fall back to CN only if no DNS names are set (RFC 6125 sec 6.4.4) if(issued_names.empty()) issued_names = subject_info("Name"); for(size_t i = 0; i != issued_names.size(); ++i) { if(host_wildcard_match(issued_names[i], name)) return true; } return false; } /* * Compare two certificates for equality */ bool X509_Certificate::operator==(const X509_Certificate& other) const { return (this->signature() == other.signature() && this->signature_algorithm() == other.signature_algorithm() && this->signed_body() == other.signed_body()); } bool X509_Certificate::operator<(const X509_Certificate& other) const { /* If signature values are not equal, sort by lexicographic ordering of that */ if(this->signature() != other.signature()) { return (this->signature() < other.signature()); } // Then compare the signed contents return this->signed_body() < other.signed_body(); } /* * X.509 Certificate Comparison */ bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2) { return !(cert1 == cert2); } std::string X509_Certificate::to_string() const { std::ostringstream out; out << "Version: " << this->x509_version() << "\n"; out << "Subject: " << subject_dn() << "\n"; out << "Issuer: " << issuer_dn() << "\n"; out << "Issued: " << this->not_before().readable_string() << "\n"; out << "Expires: " << this->not_after().readable_string() << "\n"; out << "Constraints:\n"; Key_Constraints constraints = this->constraints(); if(constraints == NO_CONSTRAINTS) out << " None\n"; else { if(constraints & DIGITAL_SIGNATURE) out << " Digital Signature\n"; if(constraints & NON_REPUDIATION) out << " Non-Repudiation\n"; if(constraints & KEY_ENCIPHERMENT) out << " Key Encipherment\n"; if(constraints & DATA_ENCIPHERMENT) out << " Data Encipherment\n"; if(constraints & KEY_AGREEMENT) out << " Key Agreement\n"; if(constraints & KEY_CERT_SIGN) out << " Cert Sign\n"; if(constraints & CRL_SIGN) out << " CRL Sign\n"; if(constraints & ENCIPHER_ONLY) out << " Encipher Only\n"; if(constraints & DECIPHER_ONLY) out << " Decipher Only\n"; } const std::vector& policies = this->certificate_policy_oids(); if(!policies.empty()) { out << "Policies: " << "\n"; for(auto oid : policies) out << " " << oid.to_string() << "\n"; } const std::vector& ex_constraints = this->extended_key_usage(); if(!ex_constraints.empty()) { out << "Extended Constraints:\n"; for(auto&& oid : ex_constraints) { out << " " << oid.to_formatted_string() << "\n"; } } const NameConstraints& name_constraints = this->name_constraints(); if(!name_constraints.permitted().empty() || !name_constraints.excluded().empty()) { out << "Name Constraints:\n"; if(!name_constraints.permitted().empty()) { out << " Permit"; for(auto st: name_constraints.permitted()) { out << " " << st.base(); } out << "\n"; } if(!name_constraints.excluded().empty()) { out << " Exclude"; for(auto st: name_constraints.excluded()) { out << " " << st.base(); } out << "\n"; } } if(!ocsp_responder().empty()) out << "OCSP responder " << ocsp_responder() << "\n"; const std::vector ca_issuers = this->ca_issuers(); if(!ca_issuers.empty()) { out << "CA Issuers:\n"; for(size_t i = 0; i != ca_issuers.size(); i++) out << " URI: " << ca_issuers[i] << "\n"; } if(!crl_distribution_point().empty()) out << "CRL " << crl_distribution_point() << "\n"; out << "Signature algorithm: " << this->signature_algorithm().get_oid().to_formatted_string() << "\n"; out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; if(this->authority_key_id().size()) out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; if(this->subject_key_id().size()) out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; try { std::unique_ptr pubkey(this->subject_public_key()); out << "Public Key [" << pubkey->algo_name() << "-" << pubkey->key_length() << "]\n\n"; out << X509::PEM_encode(*pubkey); } catch(Decoding_Error&) { const AlgorithmIdentifier& alg_id = this->subject_public_key_algo(); out << "Failed to decode key with oid " << alg_id.get_oid().to_string() << "\n"; } return out.str(); } } /* * X.509 Certificate Options * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Set when the certificate should become valid */ void X509_Cert_Options::not_before(const std::string& time_string) { start = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME); } /* * Set when the certificate should expire */ void X509_Cert_Options::not_after(const std::string& time_string) { end = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME); } /* * Set key constraint information */ void X509_Cert_Options::add_constraints(Key_Constraints usage) { constraints = usage; } /* * Set key constraint information */ void X509_Cert_Options::add_ex_constraint(const OID& oid) { ex_constraints.push_back(oid); } /* * Set key constraint information */ void X509_Cert_Options::add_ex_constraint(const std::string& oid_str) { ex_constraints.push_back(OID::from_string(oid_str)); } /* * Mark this certificate for CA usage */ void X509_Cert_Options::CA_key(size_t limit) { is_CA = true; path_limit = limit; } void X509_Cert_Options::set_padding_scheme(const std::string& scheme) { padding_scheme = scheme; } /* * Initialize the certificate options */ X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, uint32_t expiration_time) { is_CA = false; path_limit = 0; constraints = NO_CONSTRAINTS; // use default for chosen algorithm padding_scheme = ""; auto now = std::chrono::system_clock::now(); start = X509_Time(now); end = X509_Time(now + std::chrono::seconds(expiration_time)); if(initial_opts.empty()) return; std::vector parsed = split_on(initial_opts, '/'); if(parsed.size() > 4) throw Invalid_Argument("X.509 cert options: Too many names: " + initial_opts); if(parsed.size() >= 1) common_name = parsed[0]; if(parsed.size() >= 2) country = parsed[1]; if(parsed.size() >= 3) organization = parsed[2]; if(parsed.size() == 4) org_unit = parsed[3]; } } /* * X.509 Certificate Path Validation * (C) 2010,2011,2012,2014,2016 Jack Lloyd * (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) #include #endif namespace Botan { /* * PKIX path validation */ CertificatePathStatusCodes PKIX::check_chain(const std::vector>& cert_path, std::chrono::system_clock::time_point ref_time, const std::string& hostname, Usage_Type usage, size_t min_signature_algo_strength, const std::set& trusted_hashes) { if(cert_path.empty()) throw Invalid_Argument("PKIX::check_chain cert_path empty"); const bool self_signed_ee_cert = (cert_path.size() == 1); X509_Time validation_time(ref_time); CertificatePathStatusCodes cert_status(cert_path.size()); if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname)) cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH); if(!cert_path[0]->allowed_usage(usage)) cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); if(cert_path[0]->is_CA_cert() == false && cert_path[0]->has_constraints(KEY_CERT_SIGN)) { /* "If the keyCertSign bit is asserted, then the cA bit in the basic constraints extension (Section 4.2.1.9) MUST also be asserted." - RFC 5280 We don't bother doing this check on the rest of the path since they must have the cA bit asserted or the validation will fail anyway. */ cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); } for(size_t i = 0; i != cert_path.size(); ++i) { std::set& status = cert_status.at(i); const bool at_self_signed_root = (i == cert_path.size() - 1); const std::shared_ptr& subject = cert_path[i]; const std::shared_ptr& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; if(at_self_signed_root && (issuer->is_self_signed() == false)) { status.insert(Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT); } if(subject->issuer_dn() != issuer->subject_dn()) { status.insert(Certificate_Status_Code::CHAIN_NAME_MISMATCH); } // Check the serial number if(subject->is_serial_negative()) { status.insert(Certificate_Status_Code::CERT_SERIAL_NEGATIVE); } // Check the subject's DN components' length for(const auto& dn_pair : subject->subject_dn().dn_info()) { const size_t dn_ub = X509_DN::lookup_ub(dn_pair.first); // dn_pair = if(dn_ub > 0 && dn_pair.second.size() > dn_ub) { status.insert(Certificate_Status_Code::DN_TOO_LONG); } } // Check all certs for valid time range if(validation_time < subject->not_before()) status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID); if(validation_time > subject->not_after()) status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED); // Check issuer constraints if(!issuer->is_CA_cert() && !self_signed_ee_cert) status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER); std::unique_ptr issuer_key(issuer->subject_public_key()); // Check the signature algorithm is known if(OIDS::oid2str_or_empty(subject->signature_algorithm().get_oid()).empty()) { status.insert(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN); } else { // only perform the following checks if the signature algorithm is known if(!issuer_key) { status.insert(Certificate_Status_Code::CERT_PUBKEY_INVALID); } else { const Certificate_Status_Code sig_status = subject->verify_signature(*issuer_key); if(sig_status != Certificate_Status_Code::VERIFIED) status.insert(sig_status); if(issuer_key->estimated_strength() < min_signature_algo_strength) status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK); } // Ignore untrusted hashes on self-signed roots if(trusted_hashes.size() > 0 && !at_self_signed_root) { if(trusted_hashes.count(subject->hash_used_for_signature()) == 0) status.insert(Certificate_Status_Code::UNTRUSTED_HASH); } } // Check cert extensions if(subject->x509_version() == 1) { if(subject->v2_issuer_key_id().empty() == false || subject->v2_subject_key_id().empty() == false) { status.insert(Certificate_Status_Code::V2_IDENTIFIERS_IN_V1_CERT); } } Extensions extensions = subject->v3_extensions(); const auto& extensions_vec = extensions.extensions(); if(subject->x509_version() < 3 && !extensions_vec.empty()) { status.insert(Certificate_Status_Code::EXT_IN_V1_V2_CERT); } for(auto& extension : extensions_vec) { extension.first->validate(*subject, *issuer, cert_path, cert_status, i); } if(extensions.extensions().size() != extensions.get_extension_oids().size()) { status.insert(Certificate_Status_Code::DUPLICATE_CERT_EXTENSION); } } // path len check size_t max_path_length = cert_path.size(); for(size_t i = cert_path.size() - 1; i > 0 ; --i) { std::set& status = cert_status.at(i); const std::shared_ptr& subject = cert_path[i]; /* * If the certificate was not self-issued, verify that max_path_length is * greater than zero and decrement max_path_length by 1. */ if(subject->subject_dn() != subject->issuer_dn()) { if(max_path_length > 0) { --max_path_length; } else { status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG); } } /* * If pathLenConstraint is present in the certificate and is less than max_path_length, * set max_path_length to the value of pathLenConstraint. */ if(subject->path_limit() != Cert_Extension::NO_CERT_PATH_LIMIT && subject->path_limit() < max_path_length) { max_path_length = subject->path_limit(); } } return cert_status; } CertificatePathStatusCodes PKIX::check_ocsp(const std::vector>& cert_path, const std::vector>& ocsp_responses, const std::vector& trusted_certstores, std::chrono::system_clock::time_point ref_time, std::chrono::seconds max_ocsp_age) { if(cert_path.empty()) throw Invalid_Argument("PKIX::check_ocsp cert_path empty"); CertificatePathStatusCodes cert_status(cert_path.size() - 1); for(size_t i = 0; i != cert_path.size() - 1; ++i) { std::set& status = cert_status.at(i); std::shared_ptr subject = cert_path.at(i); std::shared_ptr ca = cert_path.at(i+1); if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr) && (ocsp_responses.at(i)->status() == OCSP::Response_Status_Code::Successful)) { try { Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, cert_path); if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK) { // Signature ok, so check the claimed status Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time, max_ocsp_age); status.insert(ocsp_status); } else { // Some signature problem status.insert(ocsp_signature_status); } } catch(Exception&) { status.insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID); } } } while(cert_status.size() > 0 && cert_status.back().empty()) cert_status.pop_back(); return cert_status; } CertificatePathStatusCodes PKIX::check_crl(const std::vector>& cert_path, const std::vector>& crls, std::chrono::system_clock::time_point ref_time) { if(cert_path.empty()) throw Invalid_Argument("PKIX::check_crl cert_path empty"); CertificatePathStatusCodes cert_status(cert_path.size()); const X509_Time validation_time(ref_time); for(size_t i = 0; i != cert_path.size() - 1; ++i) { std::set& status = cert_status.at(i); if(i < crls.size() && crls.at(i)) { std::shared_ptr subject = cert_path.at(i); std::shared_ptr ca = cert_path.at(i+1); if(!ca->allowed_usage(CRL_SIGN)) status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER); if(validation_time < crls[i]->this_update()) status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID); if(validation_time > crls[i]->next_update()) status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED); if(crls[i]->check_signature(ca->subject_public_key()) == false) status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE); status.insert(Certificate_Status_Code::VALID_CRL_CHECKED); if(crls[i]->is_revoked(*subject)) status.insert(Certificate_Status_Code::CERT_IS_REVOKED); std::string dp = subject->crl_distribution_point(); if(!dp.empty()) { if(dp != crls[i]->crl_issuing_distribution_point()) { status.insert(Certificate_Status_Code::NO_MATCHING_CRLDP); } } for(const auto& extension : crls[i]->extensions().extensions()) { // XXX this is wrong - the OID might be defined but the extention not full parsed // for example see #1652 // is the extension critical and unknown? if(extension.second && OIDS::oid2str_or_empty(extension.first->oid_of()) == "") { /* NIST Certificate Path Valiadation Testing document: "When an implementation does not recognize a critical extension in the * crlExtensions field, it shall assume that identified certificates have been revoked and are no longer valid" */ status.insert(Certificate_Status_Code::CERT_IS_REVOKED); } } } } while(cert_status.size() > 0 && cert_status.back().empty()) cert_status.pop_back(); return cert_status; } CertificatePathStatusCodes PKIX::check_crl(const std::vector>& cert_path, const std::vector& certstores, std::chrono::system_clock::time_point ref_time) { if(cert_path.empty()) throw Invalid_Argument("PKIX::check_crl cert_path empty"); if(certstores.empty()) throw Invalid_Argument("PKIX::check_crl certstores empty"); std::vector> crls(cert_path.size()); for(size_t i = 0; i != cert_path.size(); ++i) { BOTAN_ASSERT_NONNULL(cert_path[i]); for(size_t c = 0; c != certstores.size(); ++c) { crls[i] = certstores[c]->find_crl_for(*cert_path[i]); if(crls[i]) break; } } return PKIX::check_crl(cert_path, crls, ref_time); } #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) CertificatePathStatusCodes PKIX::check_ocsp_online(const std::vector>& cert_path, const std::vector& trusted_certstores, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds timeout, bool ocsp_check_intermediate_CAs, std::chrono::seconds max_ocsp_age) { if(cert_path.empty()) throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty"); std::vector>> ocsp_response_futures; size_t to_ocsp = 1; if(ocsp_check_intermediate_CAs) to_ocsp = cert_path.size() - 1; if(cert_path.size() == 1) to_ocsp = 0; for(size_t i = 0; i < to_ocsp; ++i) { const std::shared_ptr& subject = cert_path.at(i); const std::shared_ptr& issuer = cert_path.at(i+1); if(subject->ocsp_responder() == "") { ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr { return std::make_shared(Certificate_Status_Code::OCSP_NO_REVOCATION_URL); })); } else { ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr { OCSP::Request req(*issuer, BigInt::decode(subject->serial_number())); HTTP::Response http; try { http = HTTP::POST_sync(subject->ocsp_responder(), "application/ocsp-request", req.BER_encode(), /*redirects*/1, timeout); } catch(std::exception&) { // log e.what() ? } if (http.status_code() != 200) return std::make_shared(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE); // Check the MIME type? return std::make_shared(http.body()); })); } } std::vector> ocsp_responses; for(size_t i = 0; i < ocsp_response_futures.size(); ++i) { ocsp_responses.push_back(ocsp_response_futures[i].get()); } return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time, max_ocsp_age); } CertificatePathStatusCodes PKIX::check_crl_online(const std::vector>& cert_path, const std::vector& certstores, Certificate_Store_In_Memory* crl_store, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds timeout) { if(cert_path.empty()) throw Invalid_Argument("PKIX::check_crl_online cert_path empty"); if(certstores.empty()) throw Invalid_Argument("PKIX::check_crl_online certstores empty"); std::vector>> future_crls; std::vector> crls(cert_path.size()); for(size_t i = 0; i != cert_path.size(); ++i) { const std::shared_ptr& cert = cert_path.at(i); for(size_t c = 0; c != certstores.size(); ++c) { crls[i] = certstores[c]->find_crl_for(*cert); if(crls[i]) break; } // TODO: check if CRL is expired and re-request? // Only request if we don't already have a CRL if(crls[i]) { /* We already have a CRL, so just insert this empty one to hold a place in the vector so that indexes match up */ future_crls.emplace_back(std::future>()); } else if(cert->crl_distribution_point() == "") { // Avoid creating a thread for this case future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr { throw Not_Implemented("No CRL distribution point for this certificate"); })); } else { future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr { auto http = HTTP::GET_sync(cert->crl_distribution_point(), /*redirects*/ 1, timeout); http.throw_unless_ok(); // check the mime type? return std::make_shared(http.body()); })); } } for(size_t i = 0; i != future_crls.size(); ++i) { if(future_crls[i].valid()) { try { crls[i] = future_crls[i].get(); } catch(std::exception&) { // crls[i] left null // todo: log exception e.what() ? } } } const CertificatePathStatusCodes crl_status = PKIX::check_crl(cert_path, crls, ref_time); if(crl_store) { for(size_t i = 0; i != crl_status.size(); ++i) { if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED)) { // better be non-null, we supposedly validated it BOTAN_ASSERT_NONNULL(crls[i]); crl_store->add_crl(crls[i]); } } } return crl_status; } #endif Certificate_Status_Code PKIX::build_certificate_path(std::vector>& cert_path, const std::vector& trusted_certstores, const std::shared_ptr& end_entity, const std::vector>& end_entity_extra) { if(end_entity->is_self_signed()) { return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; } /* * This is an inelegant but functional way of preventing path loops * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate * fingerprints in the path. If there is a duplicate, we error out. * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. */ std::set certs_seen; cert_path.push_back(end_entity); certs_seen.insert(end_entity->fingerprint("SHA-256")); Certificate_Store_In_Memory ee_extras; for(size_t i = 0; i != end_entity_extra.size(); ++i) ee_extras.add_certificate(end_entity_extra[i]); // iterate until we reach a root or cannot find the issuer for(;;) { const X509_Certificate& last = *cert_path.back(); const X509_DN issuer_dn = last.issuer_dn(); const std::vector auth_key_id = last.authority_key_id(); std::shared_ptr issuer; bool trusted_issuer = false; for(Certificate_Store* store : trusted_certstores) { issuer = store->find_cert(issuer_dn, auth_key_id); if(issuer) { trusted_issuer = true; break; } } if(!issuer) { // fall back to searching supplemental certs issuer = ee_extras.find_cert(issuer_dn, auth_key_id); } if(!issuer) return Certificate_Status_Code::CERT_ISSUER_NOT_FOUND; const std::string fprint = issuer->fingerprint("SHA-256"); if(certs_seen.count(fprint) > 0) // already seen? { return Certificate_Status_Code::CERT_CHAIN_LOOP; } certs_seen.insert(fprint); cert_path.push_back(issuer); if(issuer->is_self_signed()) { if(trusted_issuer) { return Certificate_Status_Code::OK; } else { return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; } } } } /** * utilities for PKIX::build_all_certificate_paths */ namespace { // using cert_maybe_trusted = std::pair,bool>; } /** * Build all possible certificate paths from the end certificate to self-signed trusted roots. * * All potentially valid paths are put into the cert_paths vector. If no potentially valid paths are found, * one of the encountered errors is returned arbitrarily. * * todo add a path building function that returns detailed information on errors encountered while building * the potentially numerous path candidates. * * Basically, a DFS is performed starting from the end certificate. A stack (vector) serves to control the DFS. * At the beginning of each iteration, a pair is popped from the stack that contains (1) the next certificate * to add to the path (2) a bool that indicates if the certificate is part of a trusted certstore. Ideally, we * follow the unique issuer of the current certificate until a trusted root is reached. However, the issuer DN + * authority key id need not be unique among the certificates used for building the path. In such a case, * we consider all the matching issuers by pushing on the stack for each of them. * */ Certificate_Status_Code PKIX::build_all_certificate_paths(std::vector>>& cert_paths_out, const std::vector& trusted_certstores, const std::shared_ptr& end_entity, const std::vector>& end_entity_extra) { if(!cert_paths_out.empty()) { throw Invalid_Argument("PKIX::build_all_certificate_paths: cert_paths_out must be empty"); } if(end_entity->is_self_signed()) { return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; } /* * Pile up error messages */ std::vector stats; Certificate_Store_In_Memory ee_extras; for(size_t i = 0; i != end_entity_extra.size(); ++i) { ee_extras.add_certificate(end_entity_extra[i]); } /* * This is an inelegant but functional way of preventing path loops * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate * fingerprints in the path. If there is a duplicate, we error out. * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. */ std::set certs_seen; // new certs are added and removed from the path during the DFS // it is copied into cert_paths_out when we encounter a trusted root std::vector> path_so_far; // todo can we assume that the end certificate is not trusted? std::vector stack = { {end_entity, false} }; while(!stack.empty()) { // found a deletion marker that guides the DFS, backtracing if(stack.back().first == nullptr) { stack.pop_back(); std::string fprint = path_so_far.back()->fingerprint("SHA-256"); certs_seen.erase(fprint); path_so_far.pop_back(); } // process next cert on the path else { std::shared_ptr last = stack.back().first; bool trusted = stack.back().second; stack.pop_back(); // certificate already seen? const std::string fprint = last->fingerprint("SHA-256"); if(certs_seen.count(fprint) == 1) { stats.push_back(Certificate_Status_Code::CERT_CHAIN_LOOP); // the current path ended in a loop continue; } // the current path ends here if(last->is_self_signed()) { // found a trust anchor if(trusted) { cert_paths_out.push_back(path_so_far); cert_paths_out.back().push_back(last); continue; } // found an untrustworthy root else { stats.push_back(Certificate_Status_Code::CANNOT_ESTABLISH_TRUST); continue; } } const X509_DN issuer_dn = last->issuer_dn(); const std::vector auth_key_id = last->authority_key_id(); // search for trusted issuers std::vector> trusted_issuers; for(Certificate_Store* store : trusted_certstores) { auto new_issuers = store->find_all_certs(issuer_dn, auth_key_id); trusted_issuers.insert(trusted_issuers.end(), new_issuers.begin(), new_issuers.end()); } // search the supplemental certs std::vector> misc_issuers = ee_extras.find_all_certs(issuer_dn, auth_key_id); // if we could not find any issuers, the current path ends here if(trusted_issuers.size() + misc_issuers.size() == 0) { stats.push_back(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND); continue; } // push the latest certificate onto the path_so_far path_so_far.push_back(last); certs_seen.emplace(fprint); // push a deletion marker on the stack for backtracing later stack.push_back({std::shared_ptr(nullptr),false}); for(const auto& trusted_cert : trusted_issuers) { stack.push_back({trusted_cert,true}); } for(const auto& misc : misc_issuers) { stack.push_back({misc,false}); } } } // could not construct any potentially valid path if(cert_paths_out.empty()) { if(stats.empty()) throw Internal_Error("X509 path building failed for unknown reasons"); else // arbitrarily return the first error return stats[0]; } else { return Certificate_Status_Code::OK; } } void PKIX::merge_revocation_status(CertificatePathStatusCodes& chain_status, const CertificatePathStatusCodes& crl, const CertificatePathStatusCodes& ocsp, bool require_rev_on_end_entity, bool require_rev_on_intermediates) { if(chain_status.empty()) throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty"); for(size_t i = 0; i != chain_status.size() - 1; ++i) { bool had_crl = false, had_ocsp = false; if(i < crl.size() && crl[i].size() > 0) { for(auto&& code : crl[i]) { if(code == Certificate_Status_Code::VALID_CRL_CHECKED) { had_crl = true; } chain_status[i].insert(code); } } if(i < ocsp.size() && ocsp[i].size() > 0) { for(auto&& code : ocsp[i]) { if(code == Certificate_Status_Code::OCSP_RESPONSE_GOOD || code == Certificate_Status_Code::OCSP_NO_REVOCATION_URL || // softfail code == Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE) // softfail { had_ocsp = true; } chain_status[i].insert(code); } } if(had_crl == false && had_ocsp == false) { if((require_rev_on_end_entity && i == 0) || (require_rev_on_intermediates && i > 0)) { chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA); } } } } Certificate_Status_Code PKIX::overall_status(const CertificatePathStatusCodes& cert_status) { if(cert_status.empty()) throw Invalid_Argument("PKIX::overall_status empty cert status"); Certificate_Status_Code overall_status = Certificate_Status_Code::OK; // take the "worst" error as overall for(const std::set& s : cert_status) { if(!s.empty()) { auto worst = *s.rbegin(); // Leave informative OCSP/CRL confirmations on cert-level status only if(worst >= Certificate_Status_Code::FIRST_ERROR_STATUS && worst > overall_status) { overall_status = worst; } } } return overall_status; } Path_Validation_Result x509_path_validate( const std::vector& end_certs, const Path_Validation_Restrictions& restrictions, const std::vector& trusted_roots, const std::string& hostname, Usage_Type usage, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds ocsp_timeout, const std::vector>& ocsp_resp) { if(end_certs.empty()) { throw Invalid_Argument("x509_path_validate called with no subjects"); } std::shared_ptr end_entity(std::make_shared(end_certs[0])); std::vector> end_entity_extra; for(size_t i = 1; i < end_certs.size(); ++i) { end_entity_extra.push_back(std::make_shared(end_certs[i])); } std::vector>> cert_paths; Certificate_Status_Code path_building_result = PKIX::build_all_certificate_paths(cert_paths, trusted_roots, end_entity, end_entity_extra); // If we cannot successfully build a chain to a trusted self-signed root, stop now if(path_building_result != Certificate_Status_Code::OK) { return Path_Validation_Result(path_building_result); } std::vector error_results; // Try validating all the potentially valid paths and return the first one to validate properly for(auto cert_path : cert_paths) { CertificatePathStatusCodes status = PKIX::check_chain(cert_path, ref_time, hostname, usage, restrictions.minimum_key_strength(), restrictions.trusted_hashes()); CertificatePathStatusCodes crl_status = PKIX::check_crl(cert_path, trusted_roots, ref_time); CertificatePathStatusCodes ocsp_status; if(ocsp_resp.size() > 0) { ocsp_status = PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time, restrictions.max_ocsp_age()); } if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0)) { #if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) ocsp_status = PKIX::check_ocsp_online(cert_path, trusted_roots, ref_time, ocsp_timeout, restrictions.ocsp_all_intermediates()); #else ocsp_status.resize(1); ocsp_status[0].insert(Certificate_Status_Code::OCSP_NO_HTTP); #endif } PKIX::merge_revocation_status(status, crl_status, ocsp_status, restrictions.require_revocation_information(), restrictions.ocsp_all_intermediates()); Path_Validation_Result pvd(status, std::move(cert_path)); if(pvd.successful_validation()) { return pvd; } else { error_results.push_back(std::move(pvd)); } } return error_results[0]; } Path_Validation_Result x509_path_validate( const X509_Certificate& end_cert, const Path_Validation_Restrictions& restrictions, const std::vector& trusted_roots, const std::string& hostname, Usage_Type usage, std::chrono::system_clock::time_point when, std::chrono::milliseconds ocsp_timeout, const std::vector>& ocsp_resp) { std::vector certs; certs.push_back(end_cert); return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); } Path_Validation_Result x509_path_validate( const std::vector& end_certs, const Path_Validation_Restrictions& restrictions, const Certificate_Store& store, const std::string& hostname, Usage_Type usage, std::chrono::system_clock::time_point when, std::chrono::milliseconds ocsp_timeout, const std::vector>& ocsp_resp) { std::vector trusted_roots; trusted_roots.push_back(const_cast(&store)); return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); } Path_Validation_Result x509_path_validate( const X509_Certificate& end_cert, const Path_Validation_Restrictions& restrictions, const Certificate_Store& store, const std::string& hostname, Usage_Type usage, std::chrono::system_clock::time_point when, std::chrono::milliseconds ocsp_timeout, const std::vector>& ocsp_resp) { std::vector certs; certs.push_back(end_cert); std::vector trusted_roots; trusted_roots.push_back(const_cast(&store)); return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); } Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, size_t key_strength, bool ocsp_intermediates, std::chrono::seconds max_ocsp_age) : m_require_revocation_information(require_rev), m_ocsp_all_intermediates(ocsp_intermediates), m_minimum_key_strength(key_strength), m_max_ocsp_age(max_ocsp_age) { if(key_strength <= 80) { m_trusted_hashes.insert("SHA-160"); } m_trusted_hashes.insert("SHA-224"); m_trusted_hashes.insert("SHA-256"); m_trusted_hashes.insert("SHA-384"); m_trusted_hashes.insert("SHA-512"); } namespace { CertificatePathStatusCodes find_warnings(const CertificatePathStatusCodes& all_statuses) { CertificatePathStatusCodes warnings; for(const auto& status_set_i : all_statuses) { std::set warning_set_i; for(const auto& code : status_set_i) { if(code >= Certificate_Status_Code::FIRST_WARNING_STATUS && code < Certificate_Status_Code::FIRST_ERROR_STATUS) { warning_set_i.insert(code); } } warnings.push_back(warning_set_i); } return warnings; } } Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status, std::vector>&& cert_chain) : m_all_status(status), m_warnings(find_warnings(m_all_status)), m_cert_path(cert_chain), m_overall(PKIX::overall_status(m_all_status)) { } const X509_Certificate& Path_Validation_Result::trust_root() const { if(m_cert_path.empty()) throw Invalid_State("Path_Validation_Result::trust_root no path set"); if(result() != Certificate_Status_Code::VERIFIED) throw Invalid_State("Path_Validation_Result::trust_root meaningless with invalid status"); return *m_cert_path[m_cert_path.size()-1]; } std::set Path_Validation_Result::trusted_hashes() const { std::set hashes; for(size_t i = 0; i != m_cert_path.size(); ++i) hashes.insert(m_cert_path[i]->hash_used_for_signature()); return hashes; } bool Path_Validation_Result::successful_validation() const { return (result() == Certificate_Status_Code::VERIFIED || result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD || result() == Certificate_Status_Code::VALID_CRL_CHECKED); } bool Path_Validation_Result::no_warnings() const { for(auto status_set_i : m_warnings) if(!status_set_i.empty()) return false; return true; } CertificatePathStatusCodes Path_Validation_Result::warnings() const { return m_warnings; } std::string Path_Validation_Result::result_string() const { return status_string(result()); } const char* Path_Validation_Result::status_string(Certificate_Status_Code code) { if(const char* s = to_string(code)) return s; return "Unknown error"; } std::string Path_Validation_Result::warnings_string() const { const std::string sep(", "); std::string res; for(size_t i = 0; i < m_warnings.size(); i++) { for(auto code : m_warnings[i]) res += "[" + std::to_string(i) + "] " + status_string(code) + sep; } // remove last sep if(res.size() >= sep.size()) res = res.substr(0, res.size() - sep.size()); return res; } } /* * PKCS #10/Self Signed Cert Creation * (C) 1999-2008,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { namespace { /* * Load information from the X509_Cert_Options */ void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn, AlternativeName& subject_alt) { subject_dn.add_attribute("X520.CommonName", opts.common_name); subject_dn.add_attribute("X520.Country", opts.country); subject_dn.add_attribute("X520.State", opts.state); subject_dn.add_attribute("X520.Locality", opts.locality); subject_dn.add_attribute("X520.Organization", opts.organization); subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit); for(auto extra_ou : opts.more_org_units) { subject_dn.add_attribute("X520.OrganizationalUnit", extra_ou); } subject_dn.add_attribute("X520.SerialNumber", opts.serial_number); subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip); subject_alt.add_othername(OID::from_string("PKIX.XMPPAddr"), opts.xmpp, UTF8_STRING); for(auto dns : opts.more_dns) subject_alt.add_attribute("DNS", dns); } } namespace X509 { /* * Create a new self-signed X.509 certificate */ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, const Private_Key& key, const std::string& hash_fn, RandomNumberGenerator& rng) { AlgorithmIdentifier sig_algo; X509_DN subject_dn; AlternativeName subject_alt; // for now, only the padding option is used std::map sig_opts = { {"padding",opts.padding_scheme} }; const std::vector pub_key = X509::BER_encode(key); std::unique_ptr signer(choose_sig_format(key, sig_opts, rng, hash_fn, sig_algo)); BOTAN_ASSERT_NOMSG(sig_algo.get_oid().has_value()); load_info(opts, subject_dn, subject_alt); Extensions extensions = opts.extensions; Key_Constraints constraints; if(opts.is_CA) { constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); } else { verify_cert_constraints_valid_for_key_type(key, opts.constraints); constraints = opts.constraints; } extensions.add_new( new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), true); if(constraints != NO_CONSTRAINTS) { extensions.add_new(new Cert_Extension::Key_Usage(constraints), true); } std::unique_ptr skid(new Cert_Extension::Subject_Key_ID(pub_key, hash_fn)); extensions.add_new(new Cert_Extension::Authority_Key_ID(skid->get_key_id())); extensions.add_new(skid.release()); extensions.add_new( new Cert_Extension::Subject_Alternative_Name(subject_alt)); extensions.add_new( new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key, opts.start, opts.end, subject_dn, subject_dn, extensions); } /* * Create a PKCS #10 certificate request */ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, const Private_Key& key, const std::string& hash_fn, RandomNumberGenerator& rng) { X509_DN subject_dn; AlternativeName subject_alt; load_info(opts, subject_dn, subject_alt); Key_Constraints constraints; if(opts.is_CA) { constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); } else { verify_cert_constraints_valid_for_key_type(key, opts.constraints); constraints = opts.constraints; } Extensions extensions = opts.extensions; extensions.add_new(new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); if(constraints != NO_CONSTRAINTS) { extensions.add_new(new Cert_Extension::Key_Usage(constraints)); } extensions.add_new(new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); extensions.add_new(new Cert_Extension::Subject_Alternative_Name(subject_alt)); return PKCS10_Request::create(key, subject_dn, extensions, hash_fn, rng, opts.padding_scheme, opts.challenge); } } } /* * ANSI X9.19 MAC * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * Update an ANSI X9.19 MAC Calculation */ void ANSI_X919_MAC::add_data(const uint8_t input[], size_t length) { verify_key_set(m_state.empty() == false); size_t xored = std::min(8 - m_position, length); xor_buf(&m_state[m_position], input, xored); m_position += xored; if(m_position < 8) return; m_des1->encrypt(m_state); input += xored; length -= xored; while(length >= 8) { xor_buf(m_state, input, 8); m_des1->encrypt(m_state); input += 8; length -= 8; } xor_buf(m_state, input, length); m_position = length; } /* * Finalize an ANSI X9.19 MAC Calculation */ void ANSI_X919_MAC::final_result(uint8_t mac[]) { if(m_position) m_des1->encrypt(m_state); m_des2->decrypt(m_state.data(), mac); m_des1->encrypt(mac); zeroise(m_state); m_position = 0; } /* * ANSI X9.19 MAC Key Schedule */ void ANSI_X919_MAC::key_schedule(const uint8_t key[], size_t length) { m_state.resize(8); m_des1->set_key(key, 8); if(length == 16) key += 8; m_des2->set_key(key, 8); } /* * Clear memory of sensitive data */ void ANSI_X919_MAC::clear() { m_des1->clear(); m_des2->clear(); zap(m_state); m_position = 0; } std::string ANSI_X919_MAC::name() const { return "X9.19-MAC"; } MessageAuthenticationCode* ANSI_X919_MAC::clone() const { return new ANSI_X919_MAC; } /* * ANSI X9.19 MAC Constructor */ ANSI_X919_MAC::ANSI_X919_MAC() : m_des1(BlockCipher::create("DES")), m_des2(m_des1->clone()), m_position(0) { } } /* * XMSS Common Ops * Operations shared by XMSS signature generation and verification operations. * (C) 2016,2017 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { void XMSS_Common_Ops::randomize_tree_hash(secure_vector& result, const secure_vector& left, const secure_vector& right, XMSS_Address& adrs, const secure_vector& seed, XMSS_Hash& hash, const XMSS_Parameters& params) { adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode); secure_vector key { hash.prf(seed, adrs.bytes()) }; adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_MSB_Mode); secure_vector bitmask_l { hash.prf(seed, adrs.bytes()) }; adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_LSB_Mode); secure_vector bitmask_r { hash.prf(seed, adrs.bytes()) }; BOTAN_ASSERT(bitmask_l.size() == left.size() && bitmask_r.size() == right.size(), "Bitmask size doesn't match node size."); secure_vector concat_xor(params.element_size() * 2); for(size_t i = 0; i < left.size(); i++) { concat_xor[i] = left[i] ^ bitmask_l[i]; concat_xor[i + left.size()] = right[i] ^ bitmask_r[i]; } hash.h(result, key, concat_xor); } void XMSS_Common_Ops::create_l_tree(secure_vector& result, wots_keysig_t pk, XMSS_Address& adrs, const secure_vector& seed, XMSS_Hash& hash, const XMSS_Parameters& params) { size_t l = params.len(); adrs.set_tree_height(0); while(l > 1) { for(size_t i = 0; i < l >> 1; i++) { adrs.set_tree_index(static_cast(i)); randomize_tree_hash(pk[i], pk[2 * i], pk[2 * i + 1], adrs, seed, hash, params); } if(l & 0x01) { pk[l >> 1] = pk[l - 1]; } l = (l >> 1) + (l & 0x01); adrs.set_tree_height(adrs.get_tree_height() + 1); } result = pk[0]; } } /* * XMSS Hash * A collection of pseudorandom hash functions required for XMSS and WOTS * computations. * (C) 2016,2017 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { XMSS_Hash::XMSS_Hash(const XMSS_Hash& hash) : XMSS_Hash(hash.m_hash_func_name) { } XMSS_Hash::XMSS_Hash(const std::string& h_func_name) : m_hash(HashFunction::create(h_func_name)), m_hash_func_name(h_func_name) { if(!m_hash) throw Lookup_Error("XMSS cannot use hash " + h_func_name + " because it is unavailable"); m_output_length = m_hash->output_length(); BOTAN_ASSERT(m_output_length > 0, "Hash output length of zero is invalid."); m_zero_padding.resize(m_output_length - 1); m_msg_hash.reset(m_hash->clone()); } void XMSS_Hash::h(secure_vector& result, const secure_vector& key, const secure_vector& data) { m_hash->update(m_zero_padding); m_hash->update(m_id_h); m_hash->update(key); m_hash->update(data); m_hash->final(result); } void XMSS_Hash::h_msg_init(const secure_vector& randomness, const secure_vector& root, const secure_vector& index_bytes) { m_msg_hash->clear(); m_msg_hash->update(m_zero_padding); m_msg_hash->update(m_id_hmsg); m_msg_hash->update(randomness); m_msg_hash->update(root); m_msg_hash->update(index_bytes); } void XMSS_Hash::h_msg_update(const uint8_t data[], size_t size) { m_msg_hash->update(data, size); } secure_vector XMSS_Hash::h_msg_final() { return m_msg_hash->final(); } secure_vector XMSS_Hash::h_msg(const secure_vector& randomness, const secure_vector& root, const secure_vector& index_bytes, const secure_vector& data) { h_msg_init(randomness, root, index_bytes); m_msg_hash->update(data); return m_msg_hash->final(); } } /* * XMSS Index Registry * A registry for XMSS private keys, keeps track of the leaf index for * independend copies of the same key. * (C) 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { const std::string XMSS_Index_Registry::m_index_hash_function = "SHA-256"; uint64_t XMSS_Index_Registry::make_key_id( const secure_vector& private_seed, const secure_vector& prf) const { std::unique_ptr hash = HashFunction::create(m_index_hash_function); BOTAN_ASSERT(hash != nullptr, "XMSS_Index_Registry requires SHA-256"); hash->update(private_seed); hash->update(prf); secure_vector result = hash->final(); uint64_t key_id = 0; for(size_t i = 0; i < sizeof(key_id); i++) { key_id = ((key_id << 8) | result[i]); } return key_id; } std::shared_ptr> XMSS_Index_Registry::get(const secure_vector& private_seed, const secure_vector& prf) { size_t pos = get(make_key_id(private_seed, prf)); if(pos < std::numeric_limits::max()) { return m_leaf_indices[pos]; } else { return m_leaf_indices[add(make_key_id(private_seed, prf))]; } } size_t XMSS_Index_Registry::get(uint64_t id) const { for(size_t i = 0; i < m_key_ids.size(); i++) { if(m_key_ids[i] == id) { return i; } } return std::numeric_limits::max(); } size_t XMSS_Index_Registry::add(uint64_t id, size_t last_unused) { lock_guard_type lock(m_mutex); size_t pos = get(id); if(pos < m_key_ids.size()) { if(last_unused > *(m_leaf_indices[pos])) { m_leaf_indices[pos] = std::make_shared>(last_unused); } return pos; } m_key_ids.push_back(id); m_leaf_indices.push_back(std::make_shared>(last_unused)); return m_key_ids.size() - 1; } } /* * XMSS Parameters * Descibes a signature method for XMSS, as defined in: * [1] XMSS: Extended Hash-Based Signatures, * Request for Comments: 8391 * Release: May 2018. * https://datatracker.ietf.org/doc/rfc8391/ * * (C) 2016,2017,2018 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { XMSS_Parameters::xmss_algorithm_t XMSS_Parameters::xmss_id_from_string(const std::string& param_set) { if(param_set == "XMSS-SHA2_10_256") { return XMSS_SHA2_10_256; } if(param_set == "XMSS-SHA2_16_256") { return XMSS_SHA2_16_256; } if(param_set == "XMSS-SHA2_20_256") { return XMSS_SHA2_20_256; } if(param_set == "XMSS-SHA2_10_512") { return XMSS_SHA2_10_512; } if(param_set == "XMSS-SHA2_16_512") { return XMSS_SHA2_16_512; } if(param_set == "XMSS-SHA2_20_512") { return XMSS_SHA2_20_512; } if(param_set == "XMSS-SHAKE_10_256") { return XMSS_SHAKE_10_256; } if(param_set == "XMSS-SHAKE_16_256") { return XMSS_SHAKE_16_256; } if(param_set == "XMSS-SHAKE_20_256") { return XMSS_SHAKE_20_256; } if(param_set == "XMSS-SHAKE_10_512") { return XMSS_SHAKE_10_512; } if(param_set == "XMSS-SHAKE_16_512") { return XMSS_SHAKE_16_512; } if(param_set == "XMSS-SHAKE_20_512") { return XMSS_SHAKE_20_512; } throw Lookup_Error("Unknown XMSS algorithm param '" + param_set + "'"); } XMSS_Parameters::XMSS_Parameters(const std::string& param_set) : XMSS_Parameters(XMSS_Parameters::xmss_id_from_string(param_set)) { } XMSS_Parameters::XMSS_Parameters(xmss_algorithm_t oid) : m_oid(oid) { switch(oid) { case XMSS_SHA2_10_256: m_element_size = 32; m_w = 16; m_len = 67; m_tree_height = 10; m_name = "XMSS-SHA2_10_256"; m_hash_name = "SHA-256"; m_strength = 256; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_256; break; case XMSS_SHA2_16_256: m_element_size = 32; m_w = 16; m_len = 67; m_tree_height = 16; m_name = "XMSS-SHA2_16_256"; m_hash_name = "SHA-256"; m_strength = 256; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_256; break; case XMSS_SHA2_20_256: m_element_size = 32; m_w = 16; m_len = 67; m_tree_height = 20; m_name = "XMSS-SHA2_20_256"; m_hash_name = "SHA-256"; m_strength = 256; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_256; break; case XMSS_SHA2_10_512: m_element_size = 64; m_w = 16; m_len = 131; m_tree_height = 10; m_name = "XMSS-SHA2_10_512"; m_hash_name = "SHA-512"; m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512; break; case XMSS_SHA2_16_512: m_element_size = 64; m_w = 16; m_len = 131; m_tree_height = 16; m_name = "XMSS-SHA2_16_512"; m_hash_name = "SHA-512"; m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512; break; case XMSS_SHA2_20_512: m_element_size = 64; m_w = 16; m_len = 131; m_tree_height = 20; m_name = "XMSS-SHA2_20_512"; m_hash_name = "SHA-512"; m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512; break; case XMSS_SHAKE_10_256: m_element_size = 32; m_w = 16; m_len = 67; m_tree_height = 10; m_name = "XMSS-SHAKE_10_256"; m_hash_name = "SHAKE-128(256)"; m_strength = 256; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_256; break; case XMSS_SHAKE_16_256: m_element_size = 32; m_w = 16; m_len = 67; m_tree_height = 16; m_name = "XMSS-SHAKE_16_256"; m_hash_name = "SHAKE-128(256)"; m_strength = 256; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_256; break; case XMSS_SHAKE_20_256: m_element_size = 32; m_w = 16; m_len = 67; m_tree_height = 20; m_name = "XMSS-SHAKE_20_256"; m_hash_name = "SHAKE-128(256)"; m_strength = 256; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_256; break; case XMSS_SHAKE_10_512: m_element_size = 64; m_w = 16; m_len = 131; m_tree_height = 10; m_name = "XMSS-SHAKE_10_512"; m_hash_name = "SHAKE-256(512)"; m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_512; break; case XMSS_SHAKE_16_512: m_element_size = 64; m_w = 16; m_len = 131; m_tree_height = 16; m_name = "XMSS-SHAKE_16_512"; m_hash_name = "SHAKE-256(512)"; m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_512; break; case XMSS_SHAKE_20_512: m_element_size = 64; m_w = 16; m_len = 131; m_tree_height = 20; m_name = "XMSS-SHAKE_20_512"; m_hash_name = "SHAKE-256(512)"; m_strength = 512; m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_512; break; default: throw Not_Implemented("Algorithm id does not match any known XMSS algorithm id:" + std::to_string(oid)); break; } } } /* * XMSS Private Key * An XMSS: Extended Hash-Based Siganture private key. * The XMSS private key does not support the X509 and PKCS7 standard. Instead * the raw format described in [1] is used. * * [1] XMSS: Extended Hash-Based Signatures, * Request for Comments: 8391 * Release: May 2018. * https://datatracker.ietf.org/doc/rfc8391/ * * (C) 2016,2017,2018 Matthias Gierlings * (C) 2019 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) **/ #if defined(BOTAN_HAS_THREAD_UTILS) #endif namespace Botan { namespace { // fall back to raw decoding for previous versions, which did not encode an OCTET STRING secure_vector extract_raw_key(const secure_vector& key_bits) { secure_vector raw_key; try { BER_Decoder(key_bits).decode(raw_key, OCTET_STRING); } catch(Decoding_Error&) { raw_key = key_bits; } return raw_key; } } XMSS_PrivateKey::XMSS_PrivateKey(const secure_vector& key_bits) : XMSS_PublicKey(unlock(key_bits)), m_wots_priv_key(m_wots_params.oid(), m_public_seed), m_hash(xmss_hash_function()), m_index_reg(XMSS_Index_Registry::get_instance()) { /* The code requires sizeof(size_t) >= ceil(tree_height / 8) Maximum supported tree height is 20, ceil(20/8) == 3, so 4 byte size_t is sufficient for all defined parameters, or even a (hypothetical) tree height 32, which would be extremely slow to compute. */ static_assert(sizeof(size_t) >= 4, "size_t is big enough to support leaf index"); secure_vector raw_key = extract_raw_key(key_bits); if(raw_key.size() != XMSS_PrivateKey::size()) { throw Decoding_Error("Invalid XMSS private key size"); } // extract & copy unused leaf index from raw_key uint64_t unused_leaf = 0; auto begin = (raw_key.begin() + XMSS_PublicKey::size()); auto end = raw_key.begin() + XMSS_PublicKey::size() + sizeof(uint32_t); for(auto& i = begin; i != end; i++) { unused_leaf = ((unused_leaf << 8) | *i); } if(unused_leaf >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) { throw Decoding_Error("XMSS private key leaf index out of bounds"); } begin = end; end = begin + XMSS_PublicKey::m_xmss_params.element_size(); m_prf.clear(); m_prf.reserve(XMSS_PublicKey::m_xmss_params.element_size()); std::copy(begin, end, std::back_inserter(m_prf)); begin = end; end = begin + m_wots_params.element_size(); m_wots_priv_key.set_private_seed(secure_vector(begin, end)); set_unused_leaf_index(static_cast(unused_leaf)); } XMSS_PrivateKey::XMSS_PrivateKey( XMSS_Parameters::xmss_algorithm_t xmss_algo_id, RandomNumberGenerator& rng) : XMSS_PublicKey(xmss_algo_id, rng), m_wots_priv_key(XMSS_PublicKey::m_xmss_params.ots_oid(), public_seed(), rng), m_hash(xmss_hash_function()), m_prf(rng.random_vec(XMSS_PublicKey::m_xmss_params.element_size())), m_index_reg(XMSS_Index_Registry::get_instance()) { XMSS_Address adrs; set_root(tree_hash(0, XMSS_PublicKey::m_xmss_params.tree_height(), adrs)); } XMSS_PrivateKey::XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, size_t idx_leaf, const secure_vector& wots_priv_seed, const secure_vector& prf, const secure_vector& root, const secure_vector& public_seed) : XMSS_PublicKey(xmss_algo_id, root, public_seed), m_wots_priv_key(XMSS_PublicKey::m_xmss_params.ots_oid(), public_seed, wots_priv_seed), m_hash(XMSS_PublicKey::m_xmss_params.hash_function_name()), m_prf(prf), m_index_reg(XMSS_Index_Registry::get_instance()) { set_unused_leaf_index(idx_leaf); } secure_vector XMSS_PrivateKey::tree_hash(size_t start_idx, size_t target_node_height, XMSS_Address& adrs) { BOTAN_ASSERT_NOMSG(target_node_height <= 30); BOTAN_ASSERT((start_idx % (static_cast(1) << target_node_height)) == 0, "Start index must be divisible by 2^{target node height}."); #if defined(BOTAN_HAS_THREAD_UTILS) // dertermine number of parallel tasks to split the tree_hashing into. Thread_Pool& thread_pool = Thread_Pool::global_instance(); const size_t split_level = std::min(target_node_height, thread_pool.worker_count()); // skip parallelization overhead for leaf nodes. if(split_level == 0) { secure_vector result; tree_hash_subtree(result, start_idx, target_node_height, adrs); return result; } const size_t subtrees = static_cast(1) << split_level; const size_t last_idx = (static_cast(1) << (target_node_height)) + start_idx; const size_t offs = (last_idx - start_idx) / subtrees; // this cast cannot overflow because target_node_height is limited uint8_t level = static_cast(split_level); // current level in the tree BOTAN_ASSERT((last_idx - start_idx) % subtrees == 0, "Number of worker threads in tree_hash need to divide range " "of calculated nodes."); std::vector> nodes( subtrees, secure_vector(XMSS_PublicKey::m_xmss_params.element_size())); std::vector node_addresses(subtrees, adrs); std::vector xmss_hash(subtrees, m_hash); std::vector> work; // Calculate multiple subtrees in parallel. for(size_t i = 0; i < subtrees; i++) { using tree_hash_subtree_fn_t = void (XMSS_PrivateKey::*)(secure_vector&, size_t, size_t, XMSS_Address&, XMSS_Hash&); tree_hash_subtree_fn_t work_fn = &XMSS_PrivateKey::tree_hash_subtree; work.push_back(thread_pool.run( work_fn, this, std::ref(nodes[i]), start_idx + i * offs, target_node_height - split_level, std::ref(node_addresses[i]), std::ref(xmss_hash[i]))); } for(auto& w : work) { w.get(); } work.clear(); // Parallelize the top tree levels horizontally while(level-- > 1) { std::vector> ro_nodes( nodes.begin(), nodes.begin() + (static_cast(1) << (level+1))); for(size_t i = 0; i < (static_cast(1) << level); i++) { BOTAN_ASSERT_NOMSG(xmss_hash.size() > i); node_addresses[i].set_tree_height(static_cast(target_node_height - (level + 1))); node_addresses[i].set_tree_index( (node_addresses[2 * i + 1].get_tree_index() - 1) >> 1); work.push_back(thread_pool.run( &XMSS_Common_Ops::randomize_tree_hash, std::ref(nodes[i]), std::cref(ro_nodes[2 * i]), std::cref(ro_nodes[2 * i + 1]), std::ref(node_addresses[i]), std::cref(this->public_seed()), std::ref(xmss_hash[i]), std::cref(m_xmss_params))); } for(auto &w : work) { w.get(); } work.clear(); } // Avoid creation an extra thread to calculate root node. node_addresses[0].set_tree_height(static_cast(target_node_height - 1)); node_addresses[0].set_tree_index( (node_addresses[1].get_tree_index() - 1) >> 1); XMSS_Common_Ops::randomize_tree_hash(nodes[0], nodes[0], nodes[1], node_addresses[0], this->public_seed(), m_hash, m_xmss_params); return nodes[0]; #else secure_vector result; tree_hash_subtree(result, start_idx, target_node_height, adrs, m_hash); return result; #endif } void XMSS_PrivateKey::tree_hash_subtree(secure_vector& result, size_t start_idx, size_t target_node_height, XMSS_Address& adrs, XMSS_Hash& hash) { const secure_vector& seed = this->public_seed(); std::vector> nodes( target_node_height + 1, secure_vector(XMSS_PublicKey::m_xmss_params.element_size())); // node stack, holds all nodes on stack and one extra "pending" node. This // temporary node referred to as "node" in the XMSS standard document stays // a pending element, meaning it is not regarded as element on the stack // until level is increased. std::vector node_levels(target_node_height + 1); uint8_t level = 0; // current level on the node stack. XMSS_WOTS_PublicKey pk(m_wots_priv_key.wots_parameters().oid(), seed); const size_t last_idx = (static_cast(1) << target_node_height) + start_idx; for(size_t i = start_idx; i < last_idx; i++) { adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); adrs.set_ots_address(static_cast(i)); this->wots_private_key().generate_public_key( pk, // getWOTS_SK(SK, s + i), reference implementation uses adrs // instead of zero padded index s + i. this->wots_private_key().at(adrs, hash), adrs, hash); adrs.set_type(XMSS_Address::Type::LTree_Address); adrs.set_ltree_address(static_cast(i)); XMSS_Common_Ops::create_l_tree(nodes[level], pk, adrs, seed, hash, m_xmss_params); node_levels[level] = 0; adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); adrs.set_tree_height(0); adrs.set_tree_index(static_cast(i)); while(level > 0 && node_levels[level] == node_levels[level - 1]) { adrs.set_tree_index(((adrs.get_tree_index() - 1) >> 1)); XMSS_Common_Ops::randomize_tree_hash(nodes[level - 1], nodes[level - 1], nodes[level], adrs, seed, hash, m_xmss_params); node_levels[level - 1]++; level--; //Pop stack top element adrs.set_tree_height(adrs.get_tree_height() + 1); } level++; //push temporary node to stack } result = nodes[level - 1]; } secure_vector XMSS_PrivateKey::private_key_bits() const { return DER_Encoder().encode(raw_private_key(), OCTET_STRING).get_contents(); } std::shared_ptr> XMSS_PrivateKey::recover_global_leaf_index() const { BOTAN_ASSERT(m_wots_priv_key.private_seed().size() == XMSS_PublicKey::m_xmss_params.element_size() && m_prf.size() == XMSS_PublicKey::m_xmss_params.element_size(), "Trying to retrieve index for partially initialized key"); return m_index_reg.get(m_wots_priv_key.private_seed(), m_prf); } void XMSS_PrivateKey::set_unused_leaf_index(size_t idx) { if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) { throw Decoding_Error("XMSS private key leaf index out of bounds"); } else { std::atomic& index = static_cast&>(*recover_global_leaf_index()); size_t current = 0; do { current = index.load(); if(current > idx) { return; } } while(!index.compare_exchange_strong(current, idx)); } } size_t XMSS_PrivateKey::reserve_unused_leaf_index() { size_t idx = (static_cast&>( *recover_global_leaf_index())).fetch_add(1); if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) { throw Decoding_Error("XMSS private key, one time signatures exhaused"); } return idx; } size_t XMSS_PrivateKey::unused_leaf_index() const { return *recover_global_leaf_index(); } secure_vector XMSS_PrivateKey::raw_private_key() const { std::vector pk { raw_public_key() }; secure_vector result(pk.begin(), pk.end()); result.reserve(size()); for(int i = 3; i >= 0; i--) { result.push_back( static_cast( static_cast(unused_leaf_index()) >> 8 * i)); } std::copy(m_prf.begin(), m_prf.end(), std::back_inserter(result)); std::copy(m_wots_priv_key.private_seed().begin(), m_wots_priv_key.private_seed().end(), std::back_inserter(result)); return result; } std::unique_ptr XMSS_PrivateKey::create_signature_op(RandomNumberGenerator&, const std::string&, const std::string& provider) const { if(provider == "base" || provider.empty()) return std::unique_ptr( new XMSS_Signature_Operation(*this)); throw Provider_Not_Found(algo_name(), provider); } } /* * XMSS Public Key * An XMSS: Extended Hash-Based Siganture public key. * The XMSS public key does not support the X509 standard. Instead the * raw format described in [1] is used. * * [1] XMSS: Extended Hash-Based Signatures, * Request for Comments: 8391 * Release: May 2018. * https://datatracker.ietf.org/doc/rfc8391/ * * (C) 2016,2017 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { namespace { // fall back to raw decoding for previous versions, which did not encode an OCTET STRING std::vector extract_raw_key(const std::vector& key_bits) { std::vector raw_key; try { BER_Decoder(key_bits).decode(raw_key, OCTET_STRING); } catch(Decoding_Error&) { raw_key = key_bits; } return raw_key; } } XMSS_PublicKey::XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, RandomNumberGenerator& rng) : m_xmss_params(xmss_oid), m_wots_params(m_xmss_params.ots_oid()), m_root(m_xmss_params.element_size()), m_public_seed(rng.random_vec(m_xmss_params.element_size())) {} XMSS_PublicKey::XMSS_PublicKey(const std::vector& key_bits) : m_raw_key(extract_raw_key(key_bits)), m_xmss_params(XMSS_PublicKey::deserialize_xmss_oid(m_raw_key)), m_wots_params(m_xmss_params.ots_oid()) { if(m_raw_key.size() < XMSS_PublicKey::size()) { throw Decoding_Error("Invalid XMSS public key size detected"); } // extract & copy root from raw key m_root.clear(); m_root.reserve(m_xmss_params.element_size()); auto begin = m_raw_key.begin() + sizeof(uint32_t); auto end = begin + m_xmss_params.element_size(); std::copy(begin, end, std::back_inserter(m_root)); // extract & copy public seed from raw key begin = end; end = begin + m_xmss_params.element_size(); m_public_seed.clear(); m_public_seed.reserve(m_xmss_params.element_size()); std::copy(begin, end, std::back_inserter(m_public_seed)); } XMSS_Parameters::xmss_algorithm_t XMSS_PublicKey::deserialize_xmss_oid(const std::vector& raw_key) { if(raw_key.size() < 4) { throw Decoding_Error("XMSS signature OID missing."); } // extract and convert algorithm id to enum type uint32_t raw_id = 0; for(size_t i = 0; i < 4; i++) { raw_id = ((raw_id << 8) | raw_key[i]); } return static_cast(raw_id); } std::unique_ptr XMSS_PublicKey::create_verification_op(const std::string&, const std::string& provider) const { if(provider == "base" || provider.empty()) { return std::unique_ptr( new XMSS_Verification_Operation(*this)); } throw Provider_Not_Found(algo_name(), provider); } std::vector XMSS_PublicKey::raw_public_key() const { std::vector result { static_cast(m_xmss_params.oid() >> 24), static_cast(m_xmss_params.oid() >> 16), static_cast(m_xmss_params.oid() >> 8), static_cast(m_xmss_params.oid()) }; std::copy(m_root.begin(), m_root.end(), std::back_inserter(result)); std::copy(m_public_seed.begin(), m_public_seed.end(), std::back_inserter(result)); return result; } std::vector XMSS_PublicKey::public_key_bits() const { std::vector output; DER_Encoder(output).encode(raw_public_key(), OCTET_STRING); return output; } } /* * XMSS Signature * (C) 2016,2017,2018 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { XMSS_Signature::XMSS_Signature(XMSS_Parameters::xmss_algorithm_t oid, const secure_vector& raw_sig) : m_leaf_idx(0), m_randomness(0, 0x00), m_tree_sig() { XMSS_Parameters xmss_params(oid); if(raw_sig.size() != (xmss_params.len() + xmss_params.tree_height() + 1) * xmss_params.element_size() + sizeof(uint32_t)) { throw Decoding_Error("XMSS signature size invalid."); } for(size_t i = 0; i < 4; i++) { m_leaf_idx = ((m_leaf_idx << 8) | raw_sig[i]); } if(m_leaf_idx >= (1ull << xmss_params.tree_height())) { throw Decoding_Error("XMSS signature leaf index out of bounds."); } auto begin = raw_sig.begin() + sizeof(uint32_t); auto end = begin + xmss_params.element_size(); std::copy(begin, end, std::back_inserter(m_randomness)); for(size_t i = 0; i < xmss_params.len(); i++) { begin = end; end = begin + xmss_params.element_size(); m_tree_sig.ots_signature().push_back(secure_vector(0)); m_tree_sig.ots_signature().back().reserve( xmss_params.element_size()); std::copy(begin, end, std::back_inserter(m_tree_sig.ots_signature().back())); } for(size_t i = 0; i < xmss_params.tree_height(); i++) { begin = end; end = begin + xmss_params.element_size(); m_tree_sig.authentication_path().push_back(secure_vector(0)); m_tree_sig.authentication_path().back().reserve( xmss_params.element_size()); std::copy(begin, end, std::back_inserter(m_tree_sig.authentication_path().back())); } } secure_vector XMSS_Signature::bytes() const { secure_vector result { static_cast(m_leaf_idx >> 24U), static_cast(m_leaf_idx >> 16U), static_cast(m_leaf_idx >> 8U), static_cast(m_leaf_idx) }; std::copy(m_randomness.begin(), m_randomness.end(), std::back_inserter(result)); for(const auto& sig : tree().ots_signature()) { std::copy(sig.begin(), sig.end(), std::back_inserter(result)); } for(const auto& auth : tree().authentication_path()) { std::copy(auth.begin(), auth.end(), std::back_inserter(result)); } return result; } } /* * XMSS Signature Operation * Signature generation operation for Extended Hash-Based Signatures (XMSS) as * defined in: * * [1] XMSS: Extended Hash-Based Signatures, * Request for Comments: 8391 * Release: May 2018. * https://datatracker.ietf.org/doc/rfc8391/ * * (C) 2016,2017,2018 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { XMSS_Signature_Operation::XMSS_Signature_Operation( const XMSS_PrivateKey& private_key) : m_priv_key(private_key), m_xmss_params(private_key.xmss_oid()), m_hash(private_key.xmss_hash_function()), m_randomness(0), m_leaf_idx(0), m_is_initialized(false) {} XMSS_WOTS_PublicKey::TreeSignature XMSS_Signature_Operation::generate_tree_signature(const secure_vector& msg, XMSS_PrivateKey& xmss_priv_key, XMSS_Address& adrs) { wots_keysig_t auth_path = build_auth_path(xmss_priv_key, adrs); adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); adrs.set_ots_address(m_leaf_idx); wots_keysig_t sig_ots = xmss_priv_key.wots_private_key().sign(msg, adrs); return XMSS_WOTS_PublicKey::TreeSignature(sig_ots, auth_path); } XMSS_Signature XMSS_Signature_Operation::sign(const secure_vector& msg_hash, XMSS_PrivateKey& xmss_priv_key) { XMSS_Address adrs; XMSS_Signature sig(m_leaf_idx, m_randomness, generate_tree_signature(msg_hash, xmss_priv_key,adrs)); return sig; } size_t XMSS_Signature_Operation::signature_length() const { return sizeof(uint64_t) + // size of leaf index m_xmss_params.element_size() + m_xmss_params.len() * m_xmss_params.element_size() + m_xmss_params.tree_height() * m_xmss_params.element_size(); } wots_keysig_t XMSS_Signature_Operation::build_auth_path(XMSS_PrivateKey& priv_key, XMSS_Address& adrs) { wots_keysig_t auth_path(m_xmss_params.tree_height()); adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); for(size_t j = 0; j < m_xmss_params.tree_height(); j++) { size_t k = (m_leaf_idx / (1ULL << j)) ^ 0x01; auth_path[j] = priv_key.tree_hash(k * (1ULL << j), j, adrs); } return auth_path; } void XMSS_Signature_Operation::update(const uint8_t msg[], size_t msg_len) { initialize(); m_hash.h_msg_update(msg, msg_len); } secure_vector XMSS_Signature_Operation::sign(RandomNumberGenerator&) { initialize(); secure_vector signature(sign(m_hash.h_msg_final(), m_priv_key).bytes()); m_is_initialized = false; return signature; } void XMSS_Signature_Operation::initialize() { // return if we already initialized and reserved a leaf index for signing. if(m_is_initialized) { return; } secure_vector index_bytes; // reserve leaf index so it can not be reused in by another signature // operation using the same private key. m_leaf_idx = static_cast(m_priv_key.reserve_unused_leaf_index()); // write prefix for message hashing into buffer. XMSS_Tools::concat(index_bytes, m_leaf_idx, 32); m_randomness = m_hash.prf(m_priv_key.prf(), index_bytes); index_bytes.clear(); XMSS_Tools::concat(index_bytes, m_leaf_idx, m_priv_key.xmss_parameters().element_size()); m_hash.h_msg_init(m_randomness, m_priv_key.root(), index_bytes); m_is_initialized = true; } } /* * XMSS Verification Operation * Provides signature verification capabilities for Extended Hash-Based * Signatures (XMSS). * * (C) 2016,2017 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { XMSS_Verification_Operation::XMSS_Verification_Operation( const XMSS_PublicKey& public_key) : m_pub_key(public_key), m_hash(public_key.xmss_hash_function()), m_msg_buf(0) { } secure_vector XMSS_Verification_Operation::root_from_signature(const XMSS_Signature& sig, const secure_vector& msg, XMSS_Address& adrs, const secure_vector& seed) { const auto params = m_pub_key.xmss_parameters(); const uint32_t next_index = static_cast(sig.unused_leaf_index()); adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); adrs.set_ots_address(next_index); XMSS_WOTS_PublicKey pub_key_ots(m_pub_key.wots_parameters().oid(), msg, sig.tree().ots_signature(), adrs, seed); adrs.set_type(XMSS_Address::Type::LTree_Address); adrs.set_ltree_address(next_index); std::array, 2> node; XMSS_Common_Ops::create_l_tree(node[0], pub_key_ots, adrs, seed, m_hash, params); adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); adrs.set_tree_index(next_index); for(size_t k = 0; k < params.tree_height(); k++) { adrs.set_tree_height(static_cast(k)); if(((next_index / (static_cast(1) << k)) & 0x01) == 0) { adrs.set_tree_index(adrs.get_tree_index() >> 1); XMSS_Common_Ops::randomize_tree_hash(node[1], node[0], sig.tree().authentication_path()[k], adrs, seed, m_hash, params); } else { adrs.set_tree_index((adrs.get_tree_index() - 1) >> 1); XMSS_Common_Ops::randomize_tree_hash(node[1], sig.tree().authentication_path()[k], node[0], adrs, seed, m_hash, params); } node[0] = node[1]; } return node[0]; } bool XMSS_Verification_Operation::verify(const XMSS_Signature& sig, const secure_vector& msg, const XMSS_PublicKey& public_key) { XMSS_Address adrs; secure_vector index_bytes; XMSS_Tools::concat(index_bytes, sig.unused_leaf_index(), m_pub_key.xmss_parameters().element_size()); secure_vector msg_digest = m_hash.h_msg(sig.randomness(), public_key.root(), index_bytes, msg); secure_vector node = root_from_signature(sig, msg_digest, adrs, public_key.public_seed()); return (node == public_key.root()); } // FIXME: XMSS signature verification requires the "randomness" parameter out // of the XMSS signature, which is part of the prefix that is hashed before // msg. Since the signature is unknown till sign() is called all message // content has to be buffered. For large messages this can be inconvenient or // impossible. // Possible solution: Change PK_Ops::Verification interface to take the // signature as constructor argument, make sign a parameterless member call. void XMSS_Verification_Operation::update(const uint8_t msg[], size_t msg_len) { std::copy(msg, msg + msg_len, std::back_inserter(m_msg_buf)); } bool XMSS_Verification_Operation::is_valid_signature(const uint8_t sig[], size_t sig_len) { try { XMSS_Signature signature(m_pub_key.xmss_parameters().oid(), secure_vector(sig, sig + sig_len)); bool result = verify(signature, m_msg_buf, m_pub_key); m_msg_buf.clear(); return result; } catch(...) { m_msg_buf.clear(); return false; } } } /* * XMSS WOTS Parameters * Descibes a signature method for XMSS Winternitz One Time Signatures, * as defined in: * [1] XMSS: Extended Hash-Based Signatures, * Request for Comments: 8391 * Release: May 2018. * https://datatracker.ietf.org/doc/rfc8391/ * * (C) 2016,2017,2018 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { XMSS_WOTS_Parameters::ots_algorithm_t XMSS_WOTS_Parameters::xmss_wots_id_from_string(const std::string& param_set) { if(param_set == "WOTSP-SHA2_256") { return WOTSP_SHA2_256; } if(param_set == "WOTSP-SHA2_512") { return WOTSP_SHA2_512; } if(param_set == "WOTSP-SHAKE_256") { return WOTSP_SHAKE_256; } if(param_set == "WOTSP-SHAKE_512") { return WOTSP_SHAKE_512; } throw Invalid_Argument("Unknown XMSS-WOTS algorithm param '" + param_set + "'"); } XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(const std::string& param_set) : XMSS_WOTS_Parameters(xmss_wots_id_from_string(param_set)) {} XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(ots_algorithm_t oid) : m_oid(oid) { switch(oid) { case WOTSP_SHA2_256: m_element_size = 32; m_w = 16; m_len = 67; m_name = "WOTSP-SHA2_256"; m_hash_name = "SHA-256"; m_strength = 256; break; case WOTSP_SHA2_512: m_element_size = 64; m_w = 16; m_len = 131; m_name = "WOTSP-SHA2_512"; m_hash_name = "SHA-512"; m_strength = 512; break; case WOTSP_SHAKE_256: m_element_size = 32; m_w = 16; m_len = 67; m_name = "WOTSP-SHAKE_256"; m_hash_name = "SHAKE-128(256)"; m_strength = 256; break; case WOTSP_SHAKE_512: m_element_size = 64; m_w = 16; m_len = 131; m_name = "WOTSP-SHAKE_512"; m_hash_name = "SHAKE-256(512)"; m_strength = 512; break; default: throw Not_Implemented("Algorithm id does not match any known XMSS WOTS algorithm id."); break; } m_lg_w = (m_w == 16) ? 4 : 2; m_len_1 = static_cast(std::ceil((8 * element_size()) / m_lg_w)); m_len_2 = static_cast( floor(log2(m_len_1 * (wots_parameter() - 1)) / m_lg_w) + 1); BOTAN_ASSERT(m_len == m_len_1 + m_len_2, "Invalid XMSS WOTS parameter " "\"len\" detedted."); } secure_vector XMSS_WOTS_Parameters::base_w(const secure_vector& msg, size_t out_size) const { secure_vector result; size_t in = 0; size_t total = 0; size_t bits = 0; for(size_t i = 0; i < out_size; i++) { if(bits == 0) { total = msg[in]; in++; bits += 8; } bits -= m_lg_w; result.push_back(static_cast((total >> bits) & (m_w - 1))); } return result; } secure_vector XMSS_WOTS_Parameters::base_w(size_t value) const { value <<= (8 - ((m_len_2 * m_lg_w) % 8)); size_t len_2_bytes = static_cast( std::ceil(static_cast(m_len_2 * m_lg_w) / 8.f)); secure_vector result; XMSS_Tools::concat(result, value, len_2_bytes); return base_w(result, m_len_2); } void XMSS_WOTS_Parameters::append_checksum(secure_vector& data) { size_t csum = 0; for(size_t i = 0; i < data.size(); i++) { csum += wots_parameter() - 1 - data[i]; } secure_vector csum_bytes = base_w(csum); std::move(csum_bytes.begin(), csum_bytes.end(), std::back_inserter(data)); } } /* * XMSS WOTS Private Key * A Winternitz One Time Signature private key for use with Extended Hash-Based * Signatures. * * (C) 2016,2017 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { wots_keysig_t XMSS_WOTS_PrivateKey::generate(const secure_vector& priv_seed, XMSS_Hash& hash) { wots_keysig_t priv_key(m_wots_params.len(), secure_vector(0)); for(size_t i = 0; i < m_wots_params.len(); i++) { XMSS_Tools::concat(priv_key[i], i, 32); hash.prf(priv_key[i], priv_seed, priv_key[i]); } return priv_key; } XMSS_WOTS_PublicKey XMSS_WOTS_PrivateKey::generate_public_key(XMSS_Address& adrs) { XMSS_WOTS_PublicKey pub_key(m_wots_params.oid(), public_seed()); generate_public_key(pub_key, wots_keysig_t((*this)[adrs]), adrs); return pub_key; } void XMSS_WOTS_PrivateKey::generate_public_key(XMSS_WOTS_PublicKey& pub_key, wots_keysig_t&& in_key_data, XMSS_Address& adrs, XMSS_Hash& hash) { BOTAN_ASSERT(wots_parameters() == pub_key.wots_parameters() && public_seed() == pub_key.public_seed(), "Conflicting public key data."); pub_key.set_key_data(std::move(in_key_data)); for(size_t i = 0; i < m_wots_params.len(); i++) { adrs.set_chain_address(static_cast(i)); chain(pub_key[i], 0, m_wots_params.wots_parameter() - 1, adrs, public_seed(), hash); } } wots_keysig_t XMSS_WOTS_PrivateKey::sign(const secure_vector& msg, XMSS_Address& adrs, XMSS_Hash& hash) { secure_vector msg_digest { m_wots_params.base_w(msg, m_wots_params.len_1()) }; m_wots_params.append_checksum(msg_digest); wots_keysig_t sig(this->at(adrs, hash)); for(size_t i = 0; i < m_wots_params.len(); i++) { adrs.set_chain_address(static_cast(i)); chain(sig[i], 0 , msg_digest[i], adrs, m_public_seed, hash); } return sig; } wots_keysig_t XMSS_WOTS_PrivateKey::at(const XMSS_Address& adrs, XMSS_Hash& hash) { secure_vector result; hash.prf(result, m_private_seed, adrs.bytes()); return generate(result, hash); } wots_keysig_t XMSS_WOTS_PrivateKey::at(size_t i, XMSS_Hash& hash) { secure_vector idx_bytes; XMSS_Tools::concat(idx_bytes, i, m_wots_params.element_size()); hash.h(idx_bytes, m_private_seed, idx_bytes); return generate(idx_bytes, hash); } } /* * XMSS WOTS Public Key * A Winternitz One Time Signature public key for use with Extended Hash-Based * Signatures. * * (C) 2016,2017,2018 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) **/ namespace Botan { void XMSS_WOTS_PublicKey::chain(secure_vector& result, size_t start_idx, size_t steps, XMSS_Address& adrs, const secure_vector& seed, XMSS_Hash& hash) { secure_vector prf_output(hash.output_length()); for(size_t i = start_idx; i < (start_idx + steps) && i < m_wots_params.wots_parameter(); i++) { adrs.set_hash_address(static_cast(i)); //Calculate tmp XOR bitmask adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_Mode); hash.prf(prf_output, seed, adrs.bytes()); xor_buf(result, prf_output, result.size()); // Calculate key adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode); //Calculate f(key, tmp XOR bitmask) hash.prf(prf_output, seed, adrs.bytes()); hash.f(result, prf_output, result); } } wots_keysig_t XMSS_WOTS_PublicKey::pub_key_from_signature(const secure_vector& msg, const wots_keysig_t& sig, XMSS_Address& adrs, const secure_vector& seed) { secure_vector msg_digest { m_wots_params.base_w(msg, m_wots_params.len_1()) }; m_wots_params.append_checksum(msg_digest); wots_keysig_t result(sig); for(size_t i = 0; i < m_wots_params.len(); i++) { adrs.set_chain_address(static_cast(i)); chain(result[i], msg_digest[i], m_wots_params.wots_parameter() - 1 - msg_digest[i], adrs, seed); } return result; } } /* * XTEA * (C) 1999-2009,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { /* * XTEA Encryption */ void XTEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); const uint32_t* EK = &m_EK[0]; const size_t blocks4 = blocks / 4; const size_t blocks_left = blocks % 4; BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; i++) { uint32_t L0, R0, L1, R1, L2, R2, L3, R3; load_be(in + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); for(size_t r = 0; r != 32; ++r) { L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*r]; L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*r]; L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*r]; L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*r]; R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*r+1]; R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*r+1]; R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*r+1]; R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*r+1]; } store_be(out + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); } BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks_left; ++i) { uint32_t L, R; load_be(in + BLOCK_SIZE*(4*blocks4+i), L, R); for(size_t r = 0; r != 32; ++r) { L += (((R << 4) ^ (R >> 5)) + R) ^ EK[2*r]; R += (((L << 4) ^ (L >> 5)) + L) ^ EK[2*r+1]; } store_be(out + BLOCK_SIZE*(4*blocks4+i), L, R); } } /* * XTEA Decryption */ void XTEA::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { verify_key_set(m_EK.empty() == false); const uint32_t* EK = &m_EK[0]; const size_t blocks4 = blocks / 4; const size_t blocks_left = blocks % 4; BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; i++) { uint32_t L0, R0, L1, R1, L2, R2, L3, R3; load_be(in + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); for(size_t r = 0; r != 32; ++r) { R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*r]; R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*r]; R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*r]; R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*r]; L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*r]; L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*r]; L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*r]; L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*r]; } store_be(out + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); } BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks_left; ++i) { uint32_t L, R; load_be(in + BLOCK_SIZE*(4*blocks4+i), L, R); for(size_t r = 0; r != 32; ++r) { R -= (((L << 4) ^ (L >> 5)) + L) ^ m_EK[63 - 2*r]; L -= (((R << 4) ^ (R >> 5)) + R) ^ m_EK[62 - 2*r]; } store_be(out + BLOCK_SIZE*(4*blocks4+i), L, R); } } /* * XTEA Key Schedule */ void XTEA::key_schedule(const uint8_t key[], size_t) { m_EK.resize(64); secure_vector UK(4); for(size_t i = 0; i != 4; ++i) UK[i] = load_be(key, i); uint32_t D = 0; for(size_t i = 0; i != 64; i += 2) { m_EK[i ] = D + UK[D % 4]; D += 0x9E3779B9; m_EK[i+1] = D + UK[(D >> 11) % 4]; } } void XTEA::clear() { zap(m_EK); } } /* * XTS Mode * (C) 2009,2013 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ namespace Botan { XTS_Mode::XTS_Mode(BlockCipher* cipher) : m_cipher(cipher), m_cipher_block_size(m_cipher->block_size()), m_cipher_parallelism(m_cipher->parallel_bytes()) { if(poly_double_supported_size(m_cipher_block_size) == false) { throw Invalid_Argument("Cannot use " + cipher->name() + " with XTS"); } m_tweak_cipher.reset(m_cipher->clone()); } void XTS_Mode::clear() { m_cipher->clear(); m_tweak_cipher->clear(); reset(); } void XTS_Mode::reset() { m_tweak.clear(); } std::string XTS_Mode::name() const { return cipher().name() + "/XTS"; } size_t XTS_Mode::minimum_final_size() const { return cipher_block_size(); } Key_Length_Specification XTS_Mode::key_spec() const { return cipher().key_spec().multiple(2); } size_t XTS_Mode::default_nonce_length() const { return cipher_block_size(); } bool XTS_Mode::valid_nonce_length(size_t n) const { return cipher_block_size() == n; } void XTS_Mode::key_schedule(const uint8_t key[], size_t length) { const size_t key_half = length / 2; if(length % 2 == 1 || !m_cipher->valid_keylength(key_half)) throw Invalid_Key_Length(name(), length); m_cipher->set_key(key, key_half); m_tweak_cipher->set_key(&key[key_half], key_half); } void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); m_tweak.resize(update_granularity()); copy_mem(m_tweak.data(), nonce, nonce_len); m_tweak_cipher->encrypt(m_tweak.data()); update_tweak(0); } void XTS_Mode::update_tweak(size_t which) { const size_t BS = m_tweak_cipher->block_size(); if(which > 0) poly_double_n_le(m_tweak.data(), &m_tweak[(which-1)*BS], BS); const size_t blocks_in_tweak = update_granularity() / BS; for(size_t i = 1; i < blocks_in_tweak; ++i) poly_double_n_le(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); } size_t XTS_Encryption::output_length(size_t input_length) const { return input_length; } size_t XTS_Encryption::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(tweak_set()); const size_t BS = cipher_block_size(); BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); size_t blocks = sz / BS; const size_t blocks_in_tweak = update_granularity() / BS; while(blocks) { const size_t to_proc = std::min(blocks, blocks_in_tweak); cipher().encrypt_n_xex(buf, tweak(), to_proc); buf += to_proc * BS; blocks -= to_proc; update_tweak(to_proc); } return sz; } void XTS_Encryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS encrypt"); const size_t BS = cipher_block_size(); if(sz % BS == 0) { update(buffer, offset); } else { // steal ciphertext const size_t full_blocks = ((sz / BS) - 1) * BS; const size_t final_bytes = sz - full_blocks; BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); buffer.resize(full_blocks + offset); update(buffer, offset); xor_buf(last, tweak(), BS); cipher().encrypt(last); xor_buf(last, tweak(), BS); for(size_t i = 0; i != final_bytes - BS; ++i) { last[i] ^= last[i + BS]; last[i + BS] ^= last[i]; last[i] ^= last[i + BS]; } xor_buf(last, tweak() + BS, BS); cipher().encrypt(last); xor_buf(last, tweak() + BS, BS); buffer += last; } } size_t XTS_Decryption::output_length(size_t input_length) const { return input_length; } size_t XTS_Decryption::process(uint8_t buf[], size_t sz) { BOTAN_STATE_CHECK(tweak_set()); const size_t BS = cipher_block_size(); BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); size_t blocks = sz / BS; const size_t blocks_in_tweak = update_granularity() / BS; while(blocks) { const size_t to_proc = std::min(blocks, blocks_in_tweak); cipher().decrypt_n_xex(buf, tweak(), to_proc); buf += to_proc * BS; blocks -= to_proc; update_tweak(to_proc); } return sz; } void XTS_Decryption::finish(secure_vector& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS decrypt"); const size_t BS = cipher_block_size(); if(sz % BS == 0) { update(buffer, offset); } else { // steal ciphertext const size_t full_blocks = ((sz / BS) - 1) * BS; const size_t final_bytes = sz - full_blocks; BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); buffer.resize(full_blocks + offset); update(buffer, offset); xor_buf(last, tweak() + BS, BS); cipher().decrypt(last); xor_buf(last, tweak() + BS, BS); for(size_t i = 0; i != final_bytes - BS; ++i) { last[i] ^= last[i + BS]; last[i + BS] ^= last[i]; last[i] ^= last[i + BS]; } xor_buf(last, tweak(), BS); cipher().decrypt(last); xor_buf(last, tweak(), BS); buffer += last; } } }