From 16fe6de2e8001792fbec15607558fc4f2ea65b94 Mon Sep 17 00:00:00 2001 From: wydeep Date: Tue, 25 Jun 2019 03:34:15 -0700 Subject: [PATCH] SQLyog 13.1.3 GA --- build/SQLyogCommunity.vcxproj | 23 +- build/SQLyogCommunity.vcxproj.filters | 24 +- include/CommonHelper.h | 28 +- include/ConnectionBase.h | 4 + include/FrameWindow.h | 8 +- include/Global.h | 4 + include/SQLyog.rc | 10 +- include/Version.h | 6 +- include/cryptlib/3way.h | 63 + include/cryptlib/adler32.h | 33 + include/cryptlib/adv-simd.h | 1410 ++++++++++ include/cryptlib/aes.h | 30 + include/cryptlib/algebra.h | 453 +++ include/cryptlib/algparam.h | 514 ++++ include/cryptlib/arc4.h | 89 + include/cryptlib/argnames.h | 99 + include/cryptlib/aria.h | 71 + include/cryptlib/asn.h | 577 ++++ include/cryptlib/authenc.h | 87 + include/cryptlib/base32.h | 158 ++ include/cryptlib/base64.h | 158 ++ include/cryptlib/basecode.h | 139 + include/cryptlib/bench.h | 57 + include/cryptlib/blake2.h | 309 +++ include/cryptlib/blowfish.h | 54 + include/cryptlib/blumshub.h | 58 + include/cryptlib/camellia.h | 49 + include/cryptlib/cast.h | 109 + include/cryptlib/cbcmac.h | 59 + include/cryptlib/ccm.h | 121 + include/cryptlib/chacha.h | 85 + include/cryptlib/channels.h | 142 + include/cryptlib/cmac.h | 66 + include/cryptlib/config.h | 1172 ++++++++ include/cryptlib/cpu.h | 773 ++++++ include/cryptlib/crc.h | 74 + include/cryptlib/cryptlib.h | 3210 ++++++++++++++++++++++ include/cryptlib/default.h | 310 +++ include/cryptlib/des.h | 163 ++ include/cryptlib/dh.h | 275 ++ include/cryptlib/dh2.h | 70 + include/cryptlib/dll.h | 72 + include/cryptlib/dmac.h | 106 + include/cryptlib/drbg.h | 745 +++++ include/cryptlib/dsa.h | 42 + include/cryptlib/eax.h | 108 + include/cryptlib/ec2n.h | 137 + include/cryptlib/eccrypto.h | 663 +++++ include/cryptlib/ecp.h | 155 ++ include/cryptlib/ecpoint.h | 146 + include/cryptlib/elgamal.h | 149 + include/cryptlib/emsa2.h | 101 + include/cryptlib/eprecomp.h | 162 ++ include/cryptlib/esign.h | 169 ++ include/cryptlib/factory.h | 179 ++ include/cryptlib/fhmqv.h | 302 ++ include/cryptlib/files.h | 177 ++ include/cryptlib/filters.h | 1433 ++++++++++ include/cryptlib/fips140.h | 112 + include/cryptlib/fltrimpl.h | 87 + include/cryptlib/gcm.h | 131 + include/cryptlib/gf256.h | 72 + include/cryptlib/gf2_32.h | 73 + include/cryptlib/gf2n.h | 387 +++ include/cryptlib/gfpcrypt.h | 861 ++++++ include/cryptlib/gost.h | 66 + include/cryptlib/gzip.h | 144 + include/cryptlib/hashfwd.h | 35 + include/cryptlib/hex.h | 50 + include/cryptlib/hkdf.h | 178 ++ include/cryptlib/hmac.h | 75 + include/cryptlib/hmqv.h | 310 +++ include/cryptlib/hrtimer.h | 65 + include/cryptlib/ida.h | 180 ++ include/cryptlib/idea.h | 66 + include/cryptlib/integer.h | 815 ++++++ include/cryptlib/iterhash.h | 196 ++ include/cryptlib/kalyna.h | 218 ++ include/cryptlib/keccak.h | 105 + include/cryptlib/lubyrack.h | 137 + include/cryptlib/luc.h | 338 +++ include/cryptlib/mars.h | 60 + include/cryptlib/md2.h | 54 + include/cryptlib/md4.h | 35 + include/cryptlib/md5.h | 35 + include/cryptlib/mdc.h | 84 + include/cryptlib/mersenne.h | 228 ++ include/cryptlib/misc.h | 2572 +++++++++++++++++ include/cryptlib/modarith.h | 323 +++ include/cryptlib/modes.h | 493 ++++ include/cryptlib/modexppc.h | 48 + include/cryptlib/mqueue.h | 105 + include/cryptlib/mqv.h | 223 ++ include/cryptlib/naclite.h | 417 +++ include/cryptlib/nbtheory.h | 316 +++ include/cryptlib/network.h | 234 ++ include/cryptlib/nr.h | 6 + include/cryptlib/oaep.h | 54 + include/cryptlib/oids.h | 156 ++ include/cryptlib/osrng.h | 277 ++ include/cryptlib/ossig.h | 128 + include/cryptlib/padlkrng.h | 136 + include/cryptlib/panama.h | 157 ++ include/cryptlib/pch.h | 31 + include/cryptlib/pkcspad.h | 123 + include/cryptlib/poly1305.h | 167 ++ include/cryptlib/polynomi.h | 463 ++++ include/cryptlib/ppc-simd.h | 553 ++++ include/cryptlib/pssr.h | 105 + include/cryptlib/pubkey.h | 2315 ++++++++++++++++ include/cryptlib/pwdbased.h | 461 ++++ include/cryptlib/queue.h | 158 ++ include/cryptlib/rabin.h | 135 + include/cryptlib/randpool.h | 98 + include/cryptlib/rc2.h | 91 + include/cryptlib/rc5.h | 59 + include/cryptlib/rc6.h | 60 + include/cryptlib/rdrand.h | 137 + include/cryptlib/resource.h | 15 + include/cryptlib/rijndael.h | 101 + include/cryptlib/ripemd.h | 65 + include/cryptlib/rng.h | 109 + include/cryptlib/rsa.h | 263 ++ include/cryptlib/rw.h | 146 + include/cryptlib/safer.h | 98 + include/cryptlib/salsa.h | 89 + include/cryptlib/scrypt.h | 101 + include/cryptlib/seal.h | 59 + include/cryptlib/secblock.h | 899 ++++++ include/cryptlib/seckey.h | 466 ++++ include/cryptlib/seed.h | 44 + include/cryptlib/serpent.h | 57 + include/cryptlib/serpentp.h | 434 +++ include/cryptlib/sha.h | 196 ++ include/cryptlib/sha3.h | 104 + include/cryptlib/shacal2.h | 65 + include/cryptlib/shark.h | 77 + include/cryptlib/simon.h | 180 ++ include/cryptlib/simple.h | 365 +++ include/cryptlib/siphash.h | 312 +++ include/cryptlib/skipjack.h | 67 + include/cryptlib/sm3.h | 61 + include/cryptlib/sm4.h | 76 + include/cryptlib/smartptr.h | 256 ++ include/cryptlib/socketft.h | 227 ++ include/cryptlib/sosemanuk.h | 61 + include/cryptlib/speck.h | 180 ++ include/cryptlib/square.h | 63 + include/cryptlib/stdcpp.h | 76 + include/cryptlib/strciphr.h | 622 +++++ include/cryptlib/tea.h | 148 + include/cryptlib/threefish.h | 201 ++ include/cryptlib/tiger.h | 38 + include/cryptlib/trap.h | 144 + include/cryptlib/trdlocal.h | 44 + include/cryptlib/trunhash.h | 52 + include/cryptlib/ttmac.h | 44 + include/cryptlib/tweetnacl.h | 272 ++ include/cryptlib/twofish.h | 64 + include/cryptlib/validate.h | 268 ++ include/cryptlib/vmac.h | 90 + include/cryptlib/wait.h | 235 ++ include/cryptlib/wake.h | 75 + include/cryptlib/whrlpool.h | 34 + include/cryptlib/winpipes.h | 146 + include/cryptlib/words.h | 120 + include/cryptlib/xtr.h | 219 ++ include/cryptlib/xtrcrypt.h | 55 + include/cryptlib/zdeflate.h | 174 ++ include/cryptlib/zinflate.h | 159 ++ include/cryptlib/zlib.h | 60 + include/mysql/CMakeLists.txt | 40 + include/mysql/errmsg.h | 53 +- include/mysql/ma_common.h | 65 +- include/mysql/ma_config.h.in | 140 + include/mysql/ma_context.h | 233 ++ include/mysql/ma_crypt.h | 166 ++ include/mysql/ma_global.h | 1103 ++++++++ include/mysql/ma_hash.h | 70 + include/mysql/ma_list.h | 47 + include/mysql/ma_pthread.h | 34 + include/mysql/ma_pvio.h | 133 + include/mysql/ma_server_error.h | 2 + include/mysql/ma_sha1.h | 42 + include/mysql/ma_string.h | 55 + include/mysql/ma_sys.h | 546 ++++ include/mysql/ma_tls.h | 161 ++ include/mysql/mariadb/ma_io.h | 55 + include/mysql/mariadb_async.h | 37 + include/mysql/mariadb_com.h | 457 +++ include/mysql/mariadb_ctype.h | 76 + include/mysql/mariadb_dyncol.h | 256 ++ include/mysql/mariadb_stmt.h | 285 ++ include/mysql/mariadb_version.h | 36 + include/mysql/mariadb_version.h.in | 38 + include/mysql/mysql.h | 428 ++- include/mysql/mysql/client_plugin.h | 92 +- include/mysql/mysql/plugin_auth_common.h | 3 +- include/mysql/mysqld_error.h | 570 +++- include/resource.h | 2 - include/tinyxml/tinyxml2.h | 2266 +++++++++++++++ include/wyFile.h | 2 +- include/wyString.h | 3 +- include/wyTheme.h | 12 +- lib/Keywords.db | Bin 116736 -> 116736 bytes lib/win32/debug/auth_gssapi_client.dll | Bin 783872 -> 783872 bytes lib/win32/debug/auth_gssapi_client.lib | Bin 1966 -> 1966 bytes lib/win32/debug/dialog.dll | Bin 798720 -> 798720 bytes lib/win32/debug/dialog.lib | Bin 1738 -> 1738 bytes lib/win32/debug/mariadbclient.lib | Bin 3583320 -> 4152632 bytes lib/win32/debug/mysql_clear_password.dll | Bin 777216 -> 777216 bytes lib/win32/debug/mysql_clear_password.lib | Bin 1992 -> 1992 bytes lib/win32/debug/sha256_password.dll | Bin 833536 -> 832512 bytes lib/win32/debug/sha256_password.lib | Bin 1926 -> 1926 bytes lib/win32/linux/auth_gssapi_client.so | Bin 0 -> 8433 bytes lib/win32/linux/caching_sha2_password.so | Bin 0 -> 10590 bytes lib/win32/linux/dialog.so | Bin 8018 -> 8124 bytes lib/win32/linux/libcrypto.so | Bin 0 -> 2153494 bytes lib/win32/linux/libcrypto.so.1.0.0 | 1 + lib/win32/linux/libssl.so | Bin 0 -> 466806 bytes lib/win32/linux/mysql_clear_password.so | Bin 5177 -> 5108 bytes lib/win32/linux/sha256_password.so | Bin 0 -> 7626 bytes lib/win32/release/auth_gssapi_client.dll | Bin 98304 -> 98304 bytes lib/win32/release/auth_gssapi_client.lib | Bin 1966 -> 1966 bytes lib/win32/release/dialog.dll | Bin 99840 -> 99840 bytes lib/win32/release/dialog.exp | Bin 912 -> 915 bytes lib/win32/release/dialog.lib | Bin 1738 -> 1738 bytes lib/win32/release/mariadbclient.lib | Bin 1759330 -> 1715188 bytes lib/win32/release/sha256_password.dll | Bin 87040 -> 88064 bytes lib/win32/release/sha256_password.lib | Bin 1926 -> 1926 bytes lib/x64/debug/auth_gssapi_client.dll | Bin 981504 -> 981504 bytes lib/x64/debug/auth_gssapi_client.lib | Bin 1970 -> 1970 bytes lib/x64/debug/dialog.dll | Bin 1000448 -> 1000448 bytes lib/x64/debug/dialog.lib | Bin 1742 -> 1742 bytes lib/x64/debug/mariadbclient.lib | Bin 3818650 -> 4382438 bytes lib/x64/debug/mysql_clear_password.dll | Bin 971264 -> 971264 bytes lib/x64/debug/mysql_clear_password.lib | Bin 1996 -> 1996 bytes lib/x64/debug/sha256_password.dll | Bin 1043456 -> 1041408 bytes lib/x64/debug/sha256_password.lib | Bin 1928 -> 1928 bytes lib/x64/linux/auth_gssapi_client.so | Bin 0 -> 11014 bytes lib/x64/linux/caching_sha2_password.so | Bin 0 -> 13239 bytes lib/x64/linux/dialog.so | Bin 10623 -> 10259 bytes lib/x64/linux/libcrypto.so | Bin 0 -> 2689497 bytes lib/x64/linux/libcrypto.so.1.0.0 | 1 + lib/x64/linux/libssl.so | Bin 0 -> 516726 bytes lib/x64/linux/mysql_clear_password.so | Bin 7184 -> 7033 bytes lib/x64/linux/sha256_password.so | Bin 0 -> 10099 bytes lib/x64/release/auth_gssapi_client.dll | Bin 116224 -> 116224 bytes lib/x64/release/auth_gssapi_client.lib | Bin 1970 -> 1970 bytes lib/x64/release/dialog.dll | Bin 117760 -> 117760 bytes lib/x64/release/dialog.lib | Bin 1742 -> 1742 bytes lib/x64/release/mariadbclient.lib | Bin 2083598 -> 2037276 bytes lib/x64/release/mysql_clear_password.dll | Bin 86528 -> 86528 bytes lib/x64/release/mysql_clear_password.lib | Bin 1996 -> 1996 bytes lib/x64/release/sha256_password.dll | Bin 103424 -> 103936 bytes lib/x64/release/sha256_password.lib | Bin 1928 -> 1928 bytes src/CalendarCtrl.cpp | 3 +- src/CommonHelper.cpp | 135 +- src/ConnectionBase.cpp | 151 +- src/ConnectionTab.cpp | 17 +- src/CustTab.cpp | 22 +- src/DataView.cpp | 17 +- src/ExportAsSQL.cpp | 7 +- src/FrameWindow.cpp | 284 +- src/GUIHelper.cpp | 118 +- src/MDIWindow.cpp | 29 +- src/SQLTokenizer.cpp | 2 +- src/TabCheck.cpp | 11 +- src/TabModule.cpp | 56 +- src/WinMain.cpp | 4 + src/tinyxml/tinyxml2.cpp | 2731 ++++++++++++++++++ src/wyFile.cpp | 2 +- src/wyString.cpp | 51 + src/wyTheme.cpp | 32 +- 274 files changed, 51071 insertions(+), 475 deletions(-) create mode 100644 include/cryptlib/3way.h create mode 100644 include/cryptlib/adler32.h create mode 100644 include/cryptlib/adv-simd.h create mode 100644 include/cryptlib/aes.h create mode 100644 include/cryptlib/algebra.h create mode 100644 include/cryptlib/algparam.h create mode 100644 include/cryptlib/arc4.h create mode 100644 include/cryptlib/argnames.h create mode 100644 include/cryptlib/aria.h create mode 100644 include/cryptlib/asn.h create mode 100644 include/cryptlib/authenc.h create mode 100644 include/cryptlib/base32.h create mode 100644 include/cryptlib/base64.h create mode 100644 include/cryptlib/basecode.h create mode 100644 include/cryptlib/bench.h create mode 100644 include/cryptlib/blake2.h create mode 100644 include/cryptlib/blowfish.h create mode 100644 include/cryptlib/blumshub.h create mode 100644 include/cryptlib/camellia.h create mode 100644 include/cryptlib/cast.h create mode 100644 include/cryptlib/cbcmac.h create mode 100644 include/cryptlib/ccm.h create mode 100644 include/cryptlib/chacha.h create mode 100644 include/cryptlib/channels.h create mode 100644 include/cryptlib/cmac.h create mode 100644 include/cryptlib/config.h create mode 100644 include/cryptlib/cpu.h create mode 100644 include/cryptlib/crc.h create mode 100644 include/cryptlib/cryptlib.h create mode 100644 include/cryptlib/default.h create mode 100644 include/cryptlib/des.h create mode 100644 include/cryptlib/dh.h create mode 100644 include/cryptlib/dh2.h create mode 100644 include/cryptlib/dll.h create mode 100644 include/cryptlib/dmac.h create mode 100644 include/cryptlib/drbg.h create mode 100644 include/cryptlib/dsa.h create mode 100644 include/cryptlib/eax.h create mode 100644 include/cryptlib/ec2n.h create mode 100644 include/cryptlib/eccrypto.h create mode 100644 include/cryptlib/ecp.h create mode 100644 include/cryptlib/ecpoint.h create mode 100644 include/cryptlib/elgamal.h create mode 100644 include/cryptlib/emsa2.h create mode 100644 include/cryptlib/eprecomp.h create mode 100644 include/cryptlib/esign.h create mode 100644 include/cryptlib/factory.h create mode 100644 include/cryptlib/fhmqv.h create mode 100644 include/cryptlib/files.h create mode 100644 include/cryptlib/filters.h create mode 100644 include/cryptlib/fips140.h create mode 100644 include/cryptlib/fltrimpl.h create mode 100644 include/cryptlib/gcm.h create mode 100644 include/cryptlib/gf256.h create mode 100644 include/cryptlib/gf2_32.h create mode 100644 include/cryptlib/gf2n.h create mode 100644 include/cryptlib/gfpcrypt.h create mode 100644 include/cryptlib/gost.h create mode 100644 include/cryptlib/gzip.h create mode 100644 include/cryptlib/hashfwd.h create mode 100644 include/cryptlib/hex.h create mode 100644 include/cryptlib/hkdf.h create mode 100644 include/cryptlib/hmac.h create mode 100644 include/cryptlib/hmqv.h create mode 100644 include/cryptlib/hrtimer.h create mode 100644 include/cryptlib/ida.h create mode 100644 include/cryptlib/idea.h create mode 100644 include/cryptlib/integer.h create mode 100644 include/cryptlib/iterhash.h create mode 100644 include/cryptlib/kalyna.h create mode 100644 include/cryptlib/keccak.h create mode 100644 include/cryptlib/lubyrack.h create mode 100644 include/cryptlib/luc.h create mode 100644 include/cryptlib/mars.h create mode 100644 include/cryptlib/md2.h create mode 100644 include/cryptlib/md4.h create mode 100644 include/cryptlib/md5.h create mode 100644 include/cryptlib/mdc.h create mode 100644 include/cryptlib/mersenne.h create mode 100644 include/cryptlib/misc.h create mode 100644 include/cryptlib/modarith.h create mode 100644 include/cryptlib/modes.h create mode 100644 include/cryptlib/modexppc.h create mode 100644 include/cryptlib/mqueue.h create mode 100644 include/cryptlib/mqv.h create mode 100644 include/cryptlib/naclite.h create mode 100644 include/cryptlib/nbtheory.h create mode 100644 include/cryptlib/network.h create mode 100644 include/cryptlib/nr.h create mode 100644 include/cryptlib/oaep.h create mode 100644 include/cryptlib/oids.h create mode 100644 include/cryptlib/osrng.h create mode 100644 include/cryptlib/ossig.h create mode 100644 include/cryptlib/padlkrng.h create mode 100644 include/cryptlib/panama.h create mode 100644 include/cryptlib/pch.h create mode 100644 include/cryptlib/pkcspad.h create mode 100644 include/cryptlib/poly1305.h create mode 100644 include/cryptlib/polynomi.h create mode 100644 include/cryptlib/ppc-simd.h create mode 100644 include/cryptlib/pssr.h create mode 100644 include/cryptlib/pubkey.h create mode 100644 include/cryptlib/pwdbased.h create mode 100644 include/cryptlib/queue.h create mode 100644 include/cryptlib/rabin.h create mode 100644 include/cryptlib/randpool.h create mode 100644 include/cryptlib/rc2.h create mode 100644 include/cryptlib/rc5.h create mode 100644 include/cryptlib/rc6.h create mode 100644 include/cryptlib/rdrand.h create mode 100644 include/cryptlib/resource.h create mode 100644 include/cryptlib/rijndael.h create mode 100644 include/cryptlib/ripemd.h create mode 100644 include/cryptlib/rng.h create mode 100644 include/cryptlib/rsa.h create mode 100644 include/cryptlib/rw.h create mode 100644 include/cryptlib/safer.h create mode 100644 include/cryptlib/salsa.h create mode 100644 include/cryptlib/scrypt.h create mode 100644 include/cryptlib/seal.h create mode 100644 include/cryptlib/secblock.h create mode 100644 include/cryptlib/seckey.h create mode 100644 include/cryptlib/seed.h create mode 100644 include/cryptlib/serpent.h create mode 100644 include/cryptlib/serpentp.h create mode 100644 include/cryptlib/sha.h create mode 100644 include/cryptlib/sha3.h create mode 100644 include/cryptlib/shacal2.h create mode 100644 include/cryptlib/shark.h create mode 100644 include/cryptlib/simon.h create mode 100644 include/cryptlib/simple.h create mode 100644 include/cryptlib/siphash.h create mode 100644 include/cryptlib/skipjack.h create mode 100644 include/cryptlib/sm3.h create mode 100644 include/cryptlib/sm4.h create mode 100644 include/cryptlib/smartptr.h create mode 100644 include/cryptlib/socketft.h create mode 100644 include/cryptlib/sosemanuk.h create mode 100644 include/cryptlib/speck.h create mode 100644 include/cryptlib/square.h create mode 100644 include/cryptlib/stdcpp.h create mode 100644 include/cryptlib/strciphr.h create mode 100644 include/cryptlib/tea.h create mode 100644 include/cryptlib/threefish.h create mode 100644 include/cryptlib/tiger.h create mode 100644 include/cryptlib/trap.h create mode 100644 include/cryptlib/trdlocal.h create mode 100644 include/cryptlib/trunhash.h create mode 100644 include/cryptlib/ttmac.h create mode 100644 include/cryptlib/tweetnacl.h create mode 100644 include/cryptlib/twofish.h create mode 100644 include/cryptlib/validate.h create mode 100644 include/cryptlib/vmac.h create mode 100644 include/cryptlib/wait.h create mode 100644 include/cryptlib/wake.h create mode 100644 include/cryptlib/whrlpool.h create mode 100644 include/cryptlib/winpipes.h create mode 100644 include/cryptlib/words.h create mode 100644 include/cryptlib/xtr.h create mode 100644 include/cryptlib/xtrcrypt.h create mode 100644 include/cryptlib/zdeflate.h create mode 100644 include/cryptlib/zinflate.h create mode 100644 include/cryptlib/zlib.h create mode 100644 include/mysql/CMakeLists.txt create mode 100644 include/mysql/ma_config.h.in create mode 100644 include/mysql/ma_context.h create mode 100644 include/mysql/ma_crypt.h create mode 100644 include/mysql/ma_global.h create mode 100644 include/mysql/ma_hash.h create mode 100644 include/mysql/ma_list.h create mode 100644 include/mysql/ma_pthread.h create mode 100644 include/mysql/ma_pvio.h create mode 100644 include/mysql/ma_server_error.h create mode 100644 include/mysql/ma_sha1.h create mode 100644 include/mysql/ma_string.h create mode 100644 include/mysql/ma_sys.h create mode 100644 include/mysql/ma_tls.h create mode 100644 include/mysql/mariadb/ma_io.h create mode 100644 include/mysql/mariadb_async.h create mode 100644 include/mysql/mariadb_com.h create mode 100644 include/mysql/mariadb_ctype.h create mode 100644 include/mysql/mariadb_dyncol.h create mode 100644 include/mysql/mariadb_stmt.h create mode 100644 include/mysql/mariadb_version.h create mode 100644 include/mysql/mariadb_version.h.in create mode 100644 include/tinyxml/tinyxml2.h create mode 100644 lib/win32/linux/auth_gssapi_client.so create mode 100644 lib/win32/linux/caching_sha2_password.so create mode 100644 lib/win32/linux/libcrypto.so create mode 100644 lib/win32/linux/libcrypto.so.1.0.0 create mode 100644 lib/win32/linux/libssl.so create mode 100644 lib/win32/linux/sha256_password.so create mode 100644 lib/x64/linux/auth_gssapi_client.so create mode 100644 lib/x64/linux/caching_sha2_password.so create mode 100644 lib/x64/linux/libcrypto.so create mode 100644 lib/x64/linux/libcrypto.so.1.0.0 create mode 100644 lib/x64/linux/libssl.so create mode 100644 lib/x64/linux/sha256_password.so create mode 100644 src/tinyxml/tinyxml2.cpp diff --git a/build/SQLyogCommunity.vcxproj b/build/SQLyogCommunity.vcxproj index 3207496..4ff37fc 100644 --- a/build/SQLyogCommunity.vcxproj +++ b/build/SQLyogCommunity.vcxproj @@ -96,7 +96,7 @@ Disabled - ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;%(AdditionalIncludeDirectories) + ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;../include/cryptlib;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x600;COMMUNITY;UNICODE;_UNICODE;PCRE_STATIC;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) true EnableFastChecks @@ -108,7 +108,7 @@ EditAndContinue - shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;ssleay32MD.lib;libeay32MD.lib;wevtapi.lib;%(AdditionalDependencies) + shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;ssleay32MD.lib;libeay32MD.lib;wevtapi.lib;cryptlib.lib;tinyxml2.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) false LIBCMT;msvcrt;%(IgnoreSpecificDefaultLibraries) @@ -126,7 +126,7 @@ Disabled - ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;%(AdditionalIncludeDirectories) + ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;../include/cryptlib;%(AdditionalIncludeDirectories) WIN32;WIN64;_DEBUG;_WINDOWS;_WIN32_WINNT=0x501;COMMUNITY;UNICODE;_UNICODE;PCRE_STATIC;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -137,7 +137,7 @@ ProgramDatabase - shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;%(AdditionalDependencies) + shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;cryptlib.lib;tinyxml2.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) false LIBCMT; LIBC;LIBCD;msvcrt;%(IgnoreSpecificDefaultLibraries) @@ -158,7 +158,7 @@ AnySuitable Speed - ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;%(AdditionalIncludeDirectories) + ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;../include/cryptlib;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x600;SCI_LEXER;STATIC_BUILD;COMMUNITY;_UNICODE;UNICODE;PCRE_STATIC;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) true Sync @@ -171,7 +171,7 @@ ProgramDatabase - shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;wevtapi.lib;%(AdditionalDependencies) + shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;wevtapi.lib;cryptlib.lib;tinyxml2.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) false LIBCD;msvcrt;%(IgnoreSpecificDefaultLibraries) @@ -192,7 +192,7 @@ AnySuitable Speed - ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;%(AdditionalIncludeDirectories) + ../include;../include/scintilla;../include/mysql;../include/htmlayout;../include/pcre;../include/tinyxml;../include/vld;../include/cryptlib;%(AdditionalIncludeDirectories) WIN32;WIN64;NDEBUG;_WINDOWS;_WIN32_WINNT=0x501;SCI_LEXER;STATIC_BUILD;COMMUNITY;_UNICODE;UNICODE;PCRE_STATIC;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) true Sync @@ -205,7 +205,7 @@ ProgramDatabase - shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;%(AdditionalDependencies) + shfolder.lib;version.lib;Ws2_32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;comctl32.lib;htmlhelp.lib;wininet.lib;imm32.lib;gdiplus.lib;ole32.lib;msimg32.lib;sqlite3.lib;mariadbclient.lib;HTMLayout.lib;pcre.lib;Rpcrt4.lib;shlwapi.lib;vld.lib;winmm.lib;cryptlib.lib;tinyxml2.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) false LIBCD.lib;msvcrt.lib;%(IgnoreSpecificDefaultLibraries) @@ -382,10 +382,6 @@ $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj - - - - @@ -503,8 +499,7 @@ - - + diff --git a/build/SQLyogCommunity.vcxproj.filters b/build/SQLyogCommunity.vcxproj.filters index 85fd48a..c889d9b 100644 --- a/build/SQLyogCommunity.vcxproj.filters +++ b/build/SQLyogCommunity.vcxproj.filters @@ -16,9 +16,6 @@ {e0ae8f8b-7667-4836-b7dd-25f4d7f82934} - - {124cf439-cdf7-4c76-a8e7-1266d239e8c2} - @@ -300,18 +297,6 @@ Source Files - - Source Files\tinyxml - - - Source Files\tinyxml - - - Source Files\tinyxml - - - Source Files\tinyxml - Source Files @@ -671,12 +656,6 @@ Header Files - - Header Files\tinyxml - - - Header Files\tinyxml - Header Files @@ -716,6 +695,9 @@ Header Files + + Header Files\tinyxml + diff --git a/include/CommonHelper.h b/include/CommonHelper.h index bdf3b65..254213c 100644 --- a/include/CommonHelper.h +++ b/include/CommonHelper.h @@ -59,7 +59,6 @@ #define FMT_SPACE_4 " " - #define REGKEY "Use any UUID here" @@ -568,6 +567,8 @@ wyInt32 GetBitFieldColumnWidth(wyString &strcreate, wyInt32 fieldpos); */ wyInt32 GetModuleNameLength(); +wyBool GetModuleDir(wyString &path); + //Gets the mysql specific escaped value. /** @param tunnel : IN Tunnel pointer @@ -949,14 +950,14 @@ wyBool IsDatatypeNumeric(wyString &datatype); @param text : IN String to decode @returns wyTrue on success */ -wyBool DecodePassword(wyString &text); +wyBool DecodePassword_Absolute(wyString &text); /// Encoding of password /** @param text : IN String to decode @returns wyTrue on success */ -wyBool EncodePassword(wyString &text); +wyBool EncodePassword_Absolute(wyString &text); /// Rotate string left , bitwise /** @@ -976,6 +977,27 @@ void RemoveDefiner(wyString &text, const wyChar* pattern, wyInt32 extra); void RemoveBrackets(wyString &text, const wyChar* pattern); +/// Encryption of password +/** +@param text : IN String to decode +@returns wyTrue on success +*/ +wyBool EncodePassword(wyString &text); + +/// Decoding of password +/** +@param text : IN String to decode +@returns wyTrue on success +*/ +wyBool DecodePassword(wyString &text); + +//Encrypt the password +wyBool MigrateAllPassword(wyString conn, wyString dirstr); + +wyBool MigratePassword(wyString conn, wyString dirstr, wyString &pwdstr); + +wyBool MigratePassword(wyString &pwdstr); + //void DebugLog(const char *buffer); #ifdef _WIN32 void WriteLog(const wyChar* str); diff --git a/include/ConnectionBase.h b/include/ConnectionBase.h index 2023d70..3ca3759 100644 --- a/include/ConnectionBase.h +++ b/include/ConnectionBase.h @@ -103,6 +103,8 @@ class ConnectionBase /// Status bar original window procedure WNDPROC m_wpstatusbarorigproc; + wyBool m_isencrypted_clone; + public: @@ -908,6 +910,8 @@ class ConnectionBase //array for connection color wyInt32 *m_arrayofcolor; + wyBool CopyAndRename(wyString& directorystr, wyString& fullpathstr, wyString& newpath); + }; #endif diff --git a/include/FrameWindow.h b/include/FrameWindow.h index 673b480..8c11fcb 100644 --- a/include/FrameWindow.h +++ b/include/FrameWindow.h @@ -120,7 +120,7 @@ class ListOfOpenQueryTabs : public wyElem TabType tabtype; ListOfOpenQueryTabs() { - tabname = ""; + tabname.SetAs(""); seqofquerytab = 1; seqofquerybuilder = 1; seqofschemadesigner = 1; @@ -138,7 +138,7 @@ class MDIListForDropDrown : public wyElem //TabModule * m_hwndTabModuleinlist; MDIListForDropDrown() { - name = ""; + name.SetAs(""); opentab = new List(); } }; @@ -187,7 +187,7 @@ class ListofOpenTabs : public wyElem TabModule * m_hwndTabModuleinlist; ListofOpenTabs() { - name = ""; + name.SetAs(""); } }; @@ -1746,6 +1746,7 @@ class FrameWindow wyBool SaveConnectionDetails2(wySQLite *ssnsqliteobj = NULL); wyBool SaveSessionFile(HWND hwnd, wyBool issaveas); wyBool OpenSessionFile(); + void MigratePasswordofSessionFile(wyString filename); wyString m_sessionfile; wyString m_sessionname; wyString m_previoussessionfile; @@ -1755,6 +1756,7 @@ class FrameWindow wyBool WriteTabDetailsToTempList(tabeditorelem *temptabeditorele, CTCITEM quetabitem, wyInt32 tabid, wyInt32 position, wyInt32 id,TabTypes *tabqueryactive, MDIWindow *wnd); wyBool SetStatusParts2(HWND hwndstatus); wyInt32 OnStatusBarWmCtlColorStatic(HWND hwnd, WPARAM wparam, LPARAM lparam); + void CreateIniFileBackup(); HFONT m_trialtextfont; HFONT m_trialbuyfont; //HBRUSH m_trialbuybrush; diff --git a/include/Global.h b/include/Global.h index 63cec8b..ac399db 100644 --- a/include/Global.h +++ b/include/Global.h @@ -332,6 +332,7 @@ typedef struct __struct_tunnelauth bool isproxy; bool ischallenge; bool isbase64encode; + bool isencrypted; wchar_t proxy[128]; wchar_t proxyusername[128]; @@ -447,6 +448,9 @@ struct ConnectionInfo //persist info tab wyBool m_isInfoOpen; + + wyUInt32 m_isencrypted; + }; diff --git a/include/SQLyog.rc b/include/SQLyog.rc index 9a61d4d..b9b8198 100644 --- a/include/SQLyog.rc +++ b/include/SQLyog.rc @@ -850,14 +850,6 @@ BEGIN END END -IDR_CONNDROPDOWNMENU MENU -BEGIN - POPUP "connection drop down list" - BEGIN - MENUITEM " a", IDM_DROPDOWNLISTITEM - END -END - IDR_INFOTABMENU MENU BEGIN POPUP "Object" @@ -905,7 +897,7 @@ BEGIN PUSHBUTTON "&Rename...",IDC_EDITCONN,267,9,46,15,WS_DISABLED PUSHBUTTON "&Delete",IDC_DELETE,318,9,46,15,WS_DISABLED LTEXT "Sa&ved Connections",IDC_DESCSTATIC,113,32,69,9,WS_DISABLED - CONTROL "",IDC_DESC,"CustomComboBox1",WS_DISABLED | WS_TABSTOP | 0x10,180,30,184,15 + CONTROL "",IDC_DESC,"CustomComboBox1", WS_DISABLED | WS_TABSTOP| CBS_DROPDOWN | 0x10,180,30,184,15 CONTROL "Tab1",IDC_CONNTAB,"SysTabControl32",TCS_HOTTRACK | WS_DISABLED | WS_GROUP | WS_TABSTOP,113,50,251,181 LTEXT "MyS&QL Host Address",IDC_MYSQLHOSTST,119,74,70,9,WS_DISABLED EDITTEXT IDC_DLGCONNECT_HOST,190,72,166,12,ES_AUTOHSCROLL | WS_DISABLED diff --git a/include/Version.h b/include/Version.h index 18bf38e..a53fe42 100644 --- a/include/Version.h +++ b/include/Version.h @@ -1,5 +1,5 @@ #define MAJOR_VERSION_INT 13 #define MINOR_VERSION_INT 1 -#define UPDATE_VERSION_INT 1 -#define RELEASE_VERSION_INT 0 -#define EXTRAINFO "" +#define UPDATE_VERSION_INT 3 +#define RELEASE_VERSION_INT 0 +#define EXTRAINFO " " diff --git a/include/cryptlib/3way.h b/include/cryptlib/3way.h new file mode 100644 index 0000000..868fa8c --- /dev/null +++ b/include/cryptlib/3way.h @@ -0,0 +1,63 @@ +// 3way.h - originally written and placed in the public domain by Wei Dai + +/// \file 3way.h +/// \brief Classes for the 3-Way block cipher + +#ifndef CRYPTOPP_THREEWAY_H +#define CRYPTOPP_THREEWAY_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ThreeWay block cipher information +struct ThreeWay_Info : public FixedBlockSize<12>, public FixedKeyLength<12>, public VariableRounds<11> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "3-Way";} +}; + +/// \brief ThreeWay block cipher +/// \sa 3-Way +class ThreeWay : public ThreeWay_Info, public BlockCipherDocumentation +{ + /// \brief Class specific implementation and overrides used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int m_rounds; + FixedSizeSecBlock m_k; + }; + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Dec apply to \p DECRYPTION. + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef ThreeWay::Encryption ThreeWayEncryption; +typedef ThreeWay::Decryption ThreeWayDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/adler32.h b/include/cryptlib/adler32.h new file mode 100644 index 0000000..c64bc39 --- /dev/null +++ b/include/cryptlib/adler32.h @@ -0,0 +1,33 @@ +// adler32.h - originally written and placed in the public domain by Wei Dai + +/// \file adler32.h +/// \brief Class file for ADLER-32 checksum calculations + +#ifndef CRYPTOPP_ADLER32_H +#define CRYPTOPP_ADLER32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ADLER-32 checksum calculations +class Adler32 : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4) + Adler32() {Reset();} + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Adler32";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + +private: + void Reset() {m_s1 = 1; m_s2 = 0;} + + word16 m_s1, m_s2; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/adv-simd.h b/include/cryptlib/adv-simd.h new file mode 100644 index 0000000..4233319 --- /dev/null +++ b/include/cryptlib/adv-simd.h @@ -0,0 +1,1410 @@ +// adv-simd.h - written and placed in the public domain by Jeffrey Walton +// +// The SIMD based implementations for ciphers that use SSE, NEON and Power7 +// have a commom pattern. Namely, they have a specialized implementation of +// AdvancedProcessBlocks which processes multiple block using hardware +// acceleration. After several implementations we noticed a lot of copy and +// paste occuring. adv-simd.h provides a template to avoid the copy and paste. +// +// There are 8 templates provided in this file. The number following the +// function name is the block size of the cipher. The name following that +// is the acceleration and arrangement. For example 4x1_SSE means Intel SSE +// using two encrypt (or decrypt) functions: one that operates on 4 blocks, +// and one that operates on 1 block. +// +// * AdvancedProcessBlocks64_4x1_SSE +// * AdvancedProcessBlocks128_4x1_SSE +// * AdvancedProcessBlocks64_6x2_SSE +// * AdvancedProcessBlocks128_6x2_SSE +// * AdvancedProcessBlocks64_6x2_NEON +// * AdvancedProcessBlocks128_6x2_NEON +// * AdvancedProcessBlocks64_6x2_ALTIVEC +// * AdvancedProcessBlocks128_6x2_ALTIVEC +// + +#ifndef CRYPTOPP_ADVANCED_SIMD_TEMPLATES +#define CRYPTOPP_ADVANCED_SIMD_TEMPLATES + +#include "config.h" +#include "misc.h" +#include "stdcpp.h" + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +# include +#endif + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include +# include +# include +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc-simd.h" +#endif + +// https://www.spinics.net/lists/gcchelp/msg47735.html and +// https://www.spinics.net/lists/gcchelp/msg47749.html +#if (CRYPTOPP_GCC_VERSION >= 40900) +# define GCC_NO_UBSAN __attribute__ ((no_sanitize_undefined)) +#else +# define GCC_NO_UBSAN +#endif + +// ************************ All block ciphers *********************** // + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::BlockTransformation; + +CRYPTOPP_CONSTANT(BT_XorInput = BlockTransformation::BT_XorInput) +CRYPTOPP_CONSTANT(BT_AllowParallel = BlockTransformation::BT_AllowParallel) +CRYPTOPP_CONSTANT(BT_InBlockIsCounter = BlockTransformation::BT_InBlockIsCounter) +CRYPTOPP_CONSTANT(BT_ReverseDirection = BlockTransformation::BT_ReverseDirection) +CRYPTOPP_CONSTANT(BT_DontIncrementInOutPointers = BlockTransformation::BT_DontIncrementInOutPointers) + +ANONYMOUS_NAMESPACE_END + +// *************************** ARM NEON ************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +NAMESPACE_BEGIN(CryptoPP) + +template +inline size_t AdvancedProcessBlocks64_6x2_NEON(F2 func2, F6 func6, + const word32 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 8); + +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const word32 s_zero32x4[] = {0, 0, 0, 0}; + const word32 s_one32x4_1b[] = {0, 0, 0, 1<<24}; + const word32 s_one32x4_2b[] = {0, 2<<24, 0, 2<<24}; +#else + const word32 s_zero32x4[] = {0, 0, 0, 0}; + const word32 s_one32x4_1b[] = {0, 0, 0, 1}; + const word32 s_one32x4_2b[] = {0, 2, 0, 2}; +#endif + + const ptrdiff_t blockSize = 8; + const ptrdiff_t neonBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : neonBlockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? neonBlockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : neonBlockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - neonBlockSize; + xorBlocks += static_cast(length) - neonBlockSize; + outBlocks += static_cast(length) - neonBlockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*neonBlockSize) + { + uint32x4_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + // For 64-bit block ciphers we need to load the CTR block, which is 8 bytes. + // After the dup load we have two counters in the NEON word. Then we need + // to increment the low ctr by 0 and the high ctr by 1. + const uint8x8_t ctr = vld1_u8(inBlocks); + block0 = vaddq_u32(vld1q_u32(s_one32x4_1b), + vreinterpretq_u32_u8(vcombine_u8(ctr,ctr))); + + // After initial increment of {0,1} remaining counters increment by {2,2}. + const uint32x4_t be2 = vld1q_u32(s_one32x4_2b); + block1 = vaddq_u32(be2, block0); + block2 = vaddq_u32(be2, block1); + block3 = vaddq_u32(be2, block2); + block4 = vaddq_u32(be2, block3); + block5 = vaddq_u32(be2, block4); + + vst1_u8(const_cast(inBlocks), vget_low_u8( + vreinterpretq_u8_u32(vaddq_u32(be2, block5)))); + } + else + { + block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block1 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block2 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block3 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block4 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block5 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block4 = veorq_u32(block4, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block5 = veorq_u32(block5, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block4 = veorq_u32(block4, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block5 = veorq_u32(block5, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block0)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block1)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block2)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block3)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block4)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block5)); + outBlocks += outIncrement; + + length -= 6*neonBlockSize; + } + + while (length >= 2*neonBlockSize) + { + uint32x4_t block0, block1; + if (flags & BT_InBlockIsCounter) + { + // For 64-bit block ciphers we need to load the CTR block, which is 8 bytes. + // After the dup load we have two counters in the NEON word. Then we need + // to increment the low ctr by 0 and the high ctr by 1. + const uint8x8_t ctr = vld1_u8(inBlocks); + block0 = vaddq_u32(vld1q_u32(s_one32x4_1b), + vreinterpretq_u32_u8(vcombine_u8(ctr,ctr))); + + // After initial increment of {0,1} remaining counters increment by {2,2}. + const uint32x4_t be2 = vld1q_u32(s_one32x4_2b); + block1 = vaddq_u32(be2, block0); + + vst1_u8(const_cast(inBlocks), vget_low_u8( + vreinterpretq_u8_u32(vaddq_u32(be2, block1)))); + } + else + { + block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block1 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block0)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block1)); + outBlocks += outIncrement; + + length -= 2*neonBlockSize; + } + } + + if (length) + { + // Adjust to real block size + if (flags & BT_ReverseDirection) + { + inIncrement += inIncrement ? blockSize : 0; + xorIncrement += xorIncrement ? blockSize : 0; + outIncrement += outIncrement ? blockSize : 0; + inBlocks -= inIncrement; + xorBlocks -= xorIncrement; + outBlocks -= outIncrement; + } + else + { + inIncrement -= inIncrement ? blockSize : 0; + xorIncrement -= xorIncrement ? blockSize : 0; + outIncrement -= outIncrement ? blockSize : 0; + } + + while (length >= blockSize) + { + uint32x4_t block, zero = vld1q_u32(s_zero32x4); + + const uint8x8_t v = vld1_u8(inBlocks); + block = vreinterpretq_u32_u8(vcombine_u8(v,v)); + + if (xorInput) + { + const uint8x8_t x = vld1_u8(xorBlocks); + block = veorq_u32(block, vreinterpretq_u32_u8(vcombine_u8(x,x))); + } + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[7]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + { + const uint8x8_t x = vld1_u8(xorBlocks); + block = veorq_u32(block, vreinterpretq_u32_u8(vcombine_u8(x,x))); + } + + vst1_u8(const_cast(outBlocks), + vget_low_u8(vreinterpretq_u8_u32(block))); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + } + + return length; +} + +template +inline size_t AdvancedProcessBlocks128_NEON1x6(F1 func1, F6 func6, + const word32 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const word32 s_zero32x4[] = {0, 0, 0, 0}; + const word32 s_one32x4[] = {0, 0, 0, 1<<24}; +#else + const word32 s_zero32x4[] = {0, 0, 0, 0}; + const word32 s_one32x4[] = {0, 0, 0, 1}; +#endif + + const ptrdiff_t blockSize = 16; + // const ptrdiff_t neonBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - blockSize; + xorBlocks += static_cast(length) - blockSize; + outBlocks += static_cast(length) - blockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint64x2_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t be = vreinterpretq_u64_u32(vld1q_u32(s_one32x4)); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + block1 = vaddq_u64(block0, be); + block2 = vaddq_u64(block1, be); + block3 = vaddq_u64(block2, be); + block4 = vaddq_u64(block3, be); + block5 = vaddq_u64(block4, be); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block5, be))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5)); + outBlocks += outIncrement; + + length -= 6*blockSize; + } + } + + while (length >= blockSize) + { + uint64x2_t block; + block = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block)); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + + return length; +} + +template +inline size_t AdvancedProcessBlocks128_6x2_NEON(F2 func2, F6 func6, + const word64 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const word32 s_one32x4[] = {0, 0, 0, 1<<24}; +#else + const word32 s_one32x4[] = {0, 0, 0, 1}; +#endif + + const ptrdiff_t blockSize = 16; + // const ptrdiff_t neonBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - blockSize; + xorBlocks += static_cast(length) - blockSize; + outBlocks += static_cast(length) - blockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint64x2_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t be = vreinterpretq_u64_u32(vld1q_u32(s_one32x4)); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + block1 = vaddq_u64(block0, be); + block2 = vaddq_u64(block1, be); + block3 = vaddq_u64(block2, be); + block4 = vaddq_u64(block3, be); + block5 = vaddq_u64(block4, be); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block5, be))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5)); + outBlocks += outIncrement; + + length -= 6*blockSize; + } + + while (length >= 2*blockSize) + { + uint64x2_t block0, block1; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t be = vreinterpretq_u64_u32(vld1q_u32(s_one32x4)); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, be); + + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block1, be))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks += xorIncrement; + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks += outIncrement; + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks += outIncrement; + + length -= 2*blockSize; + } + } + + while (length >= blockSize) + { + uint64x2_t block, zero = {0,0}; + block = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block)); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// *************************** Intel SSE ************************** // + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) + +// Hack for SunCC, http://github.com/weidai11/cryptopp/issues/224 +#if (__SUNPRO_CC >= 0x5130) +# define MAYBE_CONST +# define MAYBE_UNCONST_CAST(T, x) const_cast(x) +#else +# define MAYBE_CONST const +# define MAYBE_UNCONST_CAST(T, x) (x) +#endif + +// Clang __m128i casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#ifndef M128_CAST +# define M128_CAST(x) ((__m128i *)(void *)(x)) +#endif +#ifndef CONST_M128_CAST +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#endif + +// GCC double casts, https://www.spinics.net/lists/gcchelp/msg47735.html +#ifndef DOUBLE_CAST +# define DOUBLE_CAST(x) ((double *)(void *)(x)) +#endif +#ifndef CONST_DOUBLE_CAST +# define CONST_DOUBLE_CAST(x) ((const double *)(const void *)(x)) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +template +inline size_t GCC_NO_UBSAN AdvancedProcessBlocks64_6x2_SSE(F2 func2, F6 func6, + const word32 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 8); + + CRYPTOPP_ALIGN_DATA(16) + const word32 s_one32x4_1b[] = {0, 0, 0, 1<<24}; + CRYPTOPP_ALIGN_DATA(16) + const word32 s_one32x4_2b[] = {0, 2<<24, 0, 2<<24}; + + const ptrdiff_t blockSize = 8; + const ptrdiff_t xmmBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : xmmBlockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? xmmBlockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : xmmBlockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - xmmBlockSize; + xorBlocks += static_cast(length) - xmmBlockSize; + outBlocks += static_cast(length) - xmmBlockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*xmmBlockSize) + { + __m128i block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + // For 64-bit block ciphers we need to load the CTR block, which is 8 bytes. + // After the dup load we have two counters in the XMM word. Then we need + // to increment the low ctr by 0 and the high ctr by 1. + block0 = _mm_add_epi32(*CONST_M128_CAST(s_one32x4_1b), _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(inBlocks)))); + + // After initial increment of {0,1} remaining counters increment by {2,2}. + const __m128i be2 = *CONST_M128_CAST(s_one32x4_2b); + block1 = _mm_add_epi32(be2, block0); + block2 = _mm_add_epi32(be2, block1); + block3 = _mm_add_epi32(be2, block2); + block4 = _mm_add_epi32(be2, block3); + block5 = _mm_add_epi32(be2, block4); + + // Store the next counter. UBsan false positive; mem_addr can be unaligned. + _mm_store_sd(DOUBLE_CAST(inBlocks), + _mm_castsi128_pd(_mm_add_epi32(be2, block5))); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block4 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block5 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block4); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block5); + outBlocks += outIncrement; + + length -= 6*xmmBlockSize; + } + + while (length >= 2*xmmBlockSize) + { + __m128i block0, block1; + if (flags & BT_InBlockIsCounter) + { + // For 64-bit block ciphers we need to load the CTR block, which is 8 bytes. + // After the dup load we have two counters in the XMM word. Then we need + // to increment the low ctr by 0 and the high ctr by 1. + block0 = _mm_add_epi32(*CONST_M128_CAST(s_one32x4_1b), _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(inBlocks)))); + + // After initial increment of {0,1} remaining counters increment by {2,2}. + const __m128i be2 = *CONST_M128_CAST(s_one32x4_2b); + block1 = _mm_add_epi32(be2, block0); + + // Store the next counter. UBsan false positive; mem_addr can be unaligned. + _mm_store_sd(DOUBLE_CAST(inBlocks), + _mm_castsi128_pd(_mm_add_epi64(be2, block1))); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks += outIncrement; + + length -= 2*xmmBlockSize; + } + } + + if (length) + { + // Adjust to real block size + if (flags & BT_ReverseDirection) + { + inIncrement += inIncrement ? blockSize : 0; + xorIncrement += xorIncrement ? blockSize : 0; + outIncrement += outIncrement ? blockSize : 0; + inBlocks -= inIncrement; + xorBlocks -= xorIncrement; + outBlocks -= outIncrement; + } + else + { + inIncrement -= inIncrement ? blockSize : 0; + xorIncrement -= xorIncrement ? blockSize : 0; + outIncrement -= outIncrement ? blockSize : 0; + } + + while (length >= blockSize) + { + __m128i block, zero = _mm_setzero_si128(); + block = _mm_castpd_si128( + // UBsan false positive; mem_addr can be unaligned. + _mm_load_sd(CONST_DOUBLE_CAST(inBlocks))); + + if (xorInput) + { + block = _mm_xor_si128(block, _mm_castpd_si128( + // UBsan false positive; mem_addr can be unaligned. + _mm_load_sd(CONST_DOUBLE_CAST(xorBlocks)))); + } + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[7]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block = _mm_xor_si128(block, _mm_castpd_si128( + // UBsan false positive; mem_addr can be unaligned. + _mm_load_sd(CONST_DOUBLE_CAST(xorBlocks)))); + } + + // UBsan false positive; mem_addr can be unaligned. + _mm_store_sd(DOUBLE_CAST(outBlocks), _mm_castsi128_pd(block)); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + } + + return length; +} + +template +inline size_t AdvancedProcessBlocks128_6x2_SSE(F2 func2, F6 func6, + const word64 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + CRYPTOPP_ALIGN_DATA(16) + const word32 s_one32x4[] = {0, 0, 0, 1<<24}; + + const ptrdiff_t blockSize = 16; + // const ptrdiff_t xmmBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - blockSize; + xorBlocks += static_cast(length) - blockSize; + outBlocks += static_cast(length) - blockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + __m128i block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const __m128i be1 = *CONST_M128_CAST(s_one32x4); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, be1); + block2 = _mm_add_epi32(block1, be1); + block3 = _mm_add_epi32(block2, be1); + block4 = _mm_add_epi32(block3, be1); + block5 = _mm_add_epi32(block4, be1); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block5, be1)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block4 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block5 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block4); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block5); + outBlocks += outIncrement; + + length -= 6*blockSize; + } + + while (length >= 2*blockSize) + { + __m128i block0, block1; + if (flags & BT_InBlockIsCounter) + { + const __m128i be1 = *CONST_M128_CAST(s_one32x4); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, be1); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block1, be1)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks += outIncrement; + + length -= 2*blockSize; + } + } + + while (length >= blockSize) + { + __m128i block, zero = _mm_setzero_si128(); + block = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + + if (xorInput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + _mm_storeu_si128(M128_CAST(outBlocks), block); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + + return length; +} + +template +inline size_t AdvancedProcessBlocks128_4x1_SSE(F1 func1, F4 func4, + MAYBE_CONST word32 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + CRYPTOPP_ALIGN_DATA(16) + const word32 s_one32x4[] = {0, 0, 0, 1<<24}; + + const ptrdiff_t blockSize = 16; + // const ptrdiff_t xmmBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - blockSize; + xorBlocks += static_cast(length) - blockSize; + outBlocks += static_cast(length) - blockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + __m128i block0, block1, block2, block3; + if (flags & BT_InBlockIsCounter) + { + const __m128i be1 = *CONST_M128_CAST(s_one32x4); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, be1); + block2 = _mm_add_epi32(block1, be1); + block3 = _mm_add_epi32(block2, be1); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block3, be1)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + func4(block0, block1, block2, block3, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks += xorIncrement; + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks += outIncrement; + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks += outIncrement; + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + __m128i block = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + + if (xorInput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + _mm_storeu_si128(M128_CAST(outBlocks), block); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// *********************** Altivec/Power 4 ********************** // + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + +NAMESPACE_BEGIN(CryptoPP) + +template +inline size_t AdvancedProcessBlocks128_6x1_ALTIVEC(F1 func1, F6 func6, + const word32 *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const uint32x4_p s_one = {1,0,0,0}; +#else + const uint32x4_p s_one = {0,0,0,1}; +#endif + + const ptrdiff_t blockSize = 16; + // const ptrdiff_t vexBlockSize = 16; + + ptrdiff_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + ptrdiff_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + ptrdiff_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks += static_cast(length) - blockSize; + xorBlocks += static_cast(length) - blockSize; + outBlocks += static_cast(length) - blockSize; + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint32x4_p block0, block1, block2, block3, block4, block5, temp; + + if (flags & BT_InBlockIsCounter) + { + block0 = VectorLoad(inBlocks); + block1 = VectorAdd(block0, s_one); + block2 = VectorAdd(block1, s_one); + block3 = VectorAdd(block2, s_one); + block4 = VectorAdd(block3, s_one); + block5 = VectorAdd(block4, s_one); + temp = VectorAdd(block5, s_one); + VectorStore(temp, const_cast(inBlocks)); + } + else + { + block0 = VectorLoad(inBlocks); + inBlocks += inIncrement; + block1 = VectorLoad(inBlocks); + inBlocks += inIncrement; + block2 = VectorLoad(inBlocks); + inBlocks += inIncrement; + block3 = VectorLoad(inBlocks); + inBlocks += inIncrement; + block4 = VectorLoad(inBlocks); + inBlocks += inIncrement; + block5 = VectorLoad(inBlocks); + inBlocks += inIncrement; + } + + if (xorInput) + { + block0 = VectorXor(block0, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block1 = VectorXor(block1, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block2 = VectorXor(block2, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block3 = VectorXor(block3, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block4 = VectorXor(block4, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block5 = VectorXor(block5, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, rounds); + + if (xorOutput) + { + block0 = VectorXor(block0, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block1 = VectorXor(block1, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block2 = VectorXor(block2, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block3 = VectorXor(block3, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block4 = VectorXor(block4, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + block5 = VectorXor(block5, VectorLoad(xorBlocks)); + xorBlocks += xorIncrement; + } + + VectorStore(block0, outBlocks); + outBlocks += outIncrement; + VectorStore(block1, outBlocks); + outBlocks += outIncrement; + VectorStore(block2, outBlocks); + outBlocks += outIncrement; + VectorStore(block3, outBlocks); + outBlocks += outIncrement; + VectorStore(block4, outBlocks); + outBlocks += outIncrement; + VectorStore(block5, outBlocks); + outBlocks += outIncrement; + + length -= 6*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_p block = VectorLoad(inBlocks); + + if (xorInput) + block = VectorXor(block, VectorLoad(xorBlocks)); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, rounds); + + if (xorOutput) + block = VectorXor(block, VectorLoad(xorBlocks)); + + VectorStore(block, outBlocks); + + inBlocks += inIncrement; + outBlocks += outIncrement; + xorBlocks += xorIncrement; + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +#endif // CRYPTOPP_ADVANCED_SIMD_TEMPLATES diff --git a/include/cryptlib/aes.h b/include/cryptlib/aes.h new file mode 100644 index 0000000..ec98dd4 --- /dev/null +++ b/include/cryptlib/aes.h @@ -0,0 +1,30 @@ +// aes.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Class file for the AES cipher (Rijndael) +/// \details AES is a typdef for Rijndael classes. All key sizes are supported. +/// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 + +#ifndef CRYPTOPP_AES_H +#define CRYPTOPP_AES_H + +#include "rijndael.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AES block cipher (Rijndael) +/// \details AES is a typdef for Rijndael classes. All key sizes are supported. +/// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks +/// \sa AES winner, announced on 10/2/2000 +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 +DOCUMENTED_TYPEDEF(Rijndael, AES) + +typedef RijndaelEncryption AESEncryption; +typedef RijndaelDecryption AESDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/algebra.h b/include/cryptlib/algebra.h new file mode 100644 index 0000000..58c9bee --- /dev/null +++ b/include/cryptlib/algebra.h @@ -0,0 +1,453 @@ +// algebra.h - originally written and placed in the public domain by Wei Dai + +/// \file algebra.h +/// \brief Classes for performing mathematics over different fields + +#ifndef CRYPTOPP_ALGEBRA_H +#define CRYPTOPP_ALGEBRA_H + +#include "config.h" +#include "integer.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Integer; + +/// \brief Abstract group +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractGroup +{ +public: + typedef T Element; + + virtual ~AbstractGroup() {} + + /// \brief Compare two elements for equality + /// \param a first element + /// \param b second element + /// \returns true if the elements are equal, false otherwise + /// \details Equal() tests the elements for equality using a==b + virtual bool Equal(const Element &a, const Element &b) const =0; + + /// \brief Provides the Identity element + /// \returns the Identity element + virtual const Element& Identity() const =0; + + /// \brief Adds elements in the group + /// \param a first element + /// \param b second element + /// \returns the sum of a and b + virtual const Element& Add(const Element &a, const Element &b) const =0; + + /// \brief Inverts the element in the group + /// \param a first element + /// \returns the inverse of the element + virtual const Element& Inverse(const Element &a) const =0; + + /// \brief Determine if inversion is fast + /// \returns true if inversion is fast, false otherwise + virtual bool InversionIsFast() const {return false;} + + /// \brief Doubles an element in the group + /// \param a the element + /// \returns the element doubled + virtual const Element& Double(const Element &a) const; + + /// \brief Subtracts elements in the group + /// \param a first element + /// \param b second element + /// \returns the difference of a and b. The element a must provide a Subtract member function. + virtual const Element& Subtract(const Element &a, const Element &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \returns TODO + virtual Element& Accumulate(Element &a, const Element &b) const; + + /// \brief Reduces an element in the congruence class + /// \param a element to reduce + /// \param b the congruence class + /// \returns the reduced element + virtual Element& Reduce(Element &a, const Element &b) const; + + /// \brief Performs a scalar multiplication + /// \param a multiplicand + /// \param e multiplier + /// \returns the product + virtual Element ScalarMultiply(const Element &a, const Integer &e) const; + + /// \brief TODO + /// \param x first multiplicand + /// \param e1 the first multiplier + /// \param y second multiplicand + /// \param e2 the second multiplier + /// \returns TODO + virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + /// \brief Multiplies a base to multiple exponents in a group + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousMultiply() multiplies the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousMultiply() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; +}; + +/// \brief Abstract ring +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractRing : public AbstractGroup +{ +public: + typedef T Element; + + /// \brief Construct an AbstractRing + AbstractRing() {m_mg.m_pRing = this;} + + /// \brief Copy construct an AbstractRing + /// \param source other AbstractRing + AbstractRing(const AbstractRing &source) + {CRYPTOPP_UNUSED(source); m_mg.m_pRing = this;} + + /// \brief Assign an AbstractRing + /// \param source other AbstractRing + AbstractRing& operator=(const AbstractRing &source) + {CRYPTOPP_UNUSED(source); return *this;} + + /// \brief Determines whether an element is a unit in the group + /// \param a the element + /// \returns true if the element is a unit after reduction, false otherwise. + virtual bool IsUnit(const Element &a) const =0; + + /// \brief Retrieves the multiplicative identity + /// \returns the multiplicative identity + virtual const Element& MultiplicativeIdentity() const =0; + + /// \brief Multiplies elements in the group + /// \param a the multiplicand + /// \param b the multiplier + /// \returns the product of a and b + virtual const Element& Multiply(const Element &a, const Element &b) const =0; + + /// \brief Calculate the multiplicative inverse of an element in the group + /// \param a the element + virtual const Element& MultiplicativeInverse(const Element &a) const =0; + + /// \brief Square an element in the group + /// \param a the element + /// \returns the element squared + virtual const Element& Square(const Element &a) const; + + /// \brief Divides elements in the group + /// \param a the dividend + /// \param b the divisor + /// \returns the quotient + virtual const Element& Divide(const Element &a, const Element &b) const; + + /// \brief Raises a base to an exponent in the group + /// \param a the base + /// \param e the exponent + /// \returns the exponentiation + virtual Element Exponentiate(const Element &a, const Integer &e) const; + + /// \brief TODO + /// \param x first element + /// \param e1 first exponent + /// \param y second element + /// \param e2 second exponent + /// \returns TODO + virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + /// \brief Exponentiates a base to multiple exponents in the Ring + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Retrieves the multiplicative group + /// \returns the multiplicative group + virtual const AbstractGroup& MultiplicativeGroup() const + {return m_mg;} + +private: + class MultiplicativeGroupT : public AbstractGroup + { + public: + const AbstractRing& GetRing() const + {return *m_pRing;} + + bool Equal(const Element &a, const Element &b) const + {return GetRing().Equal(a, b);} + + const Element& Identity() const + {return GetRing().MultiplicativeIdentity();} + + const Element& Add(const Element &a, const Element &b) const + {return GetRing().Multiply(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return a = GetRing().Multiply(a, b);} + + const Element& Inverse(const Element &a) const + {return GetRing().MultiplicativeInverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return GetRing().Divide(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return a = GetRing().Divide(a, b);} + + const Element& Double(const Element &a) const + {return GetRing().Square(a);} + + Element ScalarMultiply(const Element &a, const Integer &e) const + {return GetRing().Exponentiate(a, e);} + + Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const + {return GetRing().CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);} + + const AbstractRing *m_pRing; + }; + + MultiplicativeGroupT m_mg; +}; + +// ******************************************************** + +/// \brief Base and exponent +/// \tparam T base class or type +/// \tparam E exponent class or type +template +struct BaseAndExponent +{ +public: + BaseAndExponent() {} + BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {} + bool operator<(const BaseAndExponent &rhs) const {return exponent < rhs.exponent;} + T base; + E exponent; +}; + +// VC60 workaround: incomplete member template support +template + Element GeneralCascadeMultiplication(const AbstractGroup &group, Iterator begin, Iterator end); +template + Element GeneralCascadeExponentiation(const AbstractRing &ring, Iterator begin, Iterator end); + +// ******************************************************** + +/// \brief Abstract Euclidean domain +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractEuclideanDomain : public AbstractRing +{ +public: + typedef T Element; + + /// \brief Performs the division algorithm on two elements in the ring + /// \param r the remainder + /// \param q the quotient + /// \param a the dividend + /// \param d the divisor + virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0; + + /// \brief Performs a modular reduction in the ring + /// \param a the element + /// \param b the modulus + /// \returns the result of a%b. + virtual const Element& Mod(const Element &a, const Element &b) const =0; + + /// \brief Calculates the greatest common denominator in the ring + /// \param a the first element + /// \param b the second element + /// \returns the the greatest common denominator of a and b. + virtual const Element& Gcd(const Element &a, const Element &b) const; + +protected: + mutable Element result; +}; + +// ******************************************************** + +/// \brief Euclidean domain +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class EuclideanDomainOf : public AbstractEuclideanDomain +{ +public: + typedef T Element; + + EuclideanDomainOf() {} + + bool Equal(const Element &a, const Element &b) const + {return a==b;} + + const Element& Identity() const + {return Element::Zero();} + + const Element& Add(const Element &a, const Element &b) const + {return result = a+b;} + + Element& Accumulate(Element &a, const Element &b) const + {return a+=b;} + + const Element& Inverse(const Element &a) const + {return result = -a;} + + const Element& Subtract(const Element &a, const Element &b) const + {return result = a-b;} + + Element& Reduce(Element &a, const Element &b) const + {return a-=b;} + + const Element& Double(const Element &a) const + {return result = a.Doubled();} + + const Element& MultiplicativeIdentity() const + {return Element::One();} + + const Element& Multiply(const Element &a, const Element &b) const + {return result = a*b;} + + const Element& Square(const Element &a) const + {return result = a.Squared();} + + bool IsUnit(const Element &a) const + {return a.IsUnit();} + + const Element& MultiplicativeInverse(const Element &a) const + {return result = a.MultiplicativeInverse();} + + const Element& Divide(const Element &a, const Element &b) const + {return result = a/b;} + + const Element& Mod(const Element &a, const Element &b) const + {return result = a%b;} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d);} + + bool operator==(const EuclideanDomainOf &rhs) const + {CRYPTOPP_UNUSED(rhs); return true;} + +private: + mutable Element result; +}; + +/// \brief Quotient ring +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class QuotientRing : public AbstractRing +{ +public: + typedef T EuclideanDomain; + typedef typename T::Element Element; + + QuotientRing(const EuclideanDomain &domain, const Element &modulus) + : m_domain(domain), m_modulus(modulus) {} + + const EuclideanDomain & GetDomain() const + {return m_domain;} + + const Element& GetModulus() const + {return m_modulus;} + + bool Equal(const Element &a, const Element &b) const + {return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());} + + const Element& Identity() const + {return m_domain.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return m_domain.Add(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return m_domain.Accumulate(a, b);} + + const Element& Inverse(const Element &a) const + {return m_domain.Inverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return m_domain.Subtract(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return m_domain.Reduce(a, b);} + + const Element& Double(const Element &a) const + {return m_domain.Double(a);} + + bool IsUnit(const Element &a) const + {return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));} + + const Element& MultiplicativeIdentity() const + {return m_domain.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);} + + const Element& Square(const Element &a) const + {return m_domain.Mod(m_domain.Square(a), m_modulus);} + + const Element& MultiplicativeInverse(const Element &a) const; + + bool operator==(const QuotientRing &rhs) const + {return m_domain == rhs.m_domain && m_modulus == rhs.m_modulus;} + +protected: + EuclideanDomain m_domain; + Element m_modulus; +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "algebra.cpp" +#endif + +#endif diff --git a/include/cryptlib/algparam.h b/include/cryptlib/algparam.h new file mode 100644 index 0000000..0eccc43 --- /dev/null +++ b/include/cryptlib/algparam.h @@ -0,0 +1,514 @@ +// algparam.h - originally written and placed in the public domain by Wei Dai + +/// \file algparam.h +/// \brief Classes for working with NameValuePairs + +#ifndef CRYPTOPP_ALGPARAM_H +#define CRYPTOPP_ALGPARAM_H + +#include "config.h" +#include "cryptlib.h" + +#include "smartptr.h" +#include "secblock.h" +#include "integer.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Used to pass byte array input as part of a NameValuePairs object +class ConstByteArrayParameter +{ +public: + /// \brief Construct a ConstByteArrayParameter + /// \param data a C-String + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + Assign((const byte *)data, data ? strlen(data) : 0, deepCopy); + } + + /// \brief Construct a ConstByteArrayParameter + /// \param data a memory buffer + /// \param size the length of the memory buffer + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + Assign(data, size, deepCopy); + } + + /// \brief Construct a ConstByteArrayParameter + /// \tparam T a std::basic_string class + /// \param string a std::basic_string class + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + template ConstByteArrayParameter(const T &string, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1); + Assign((const byte *)string.data(), string.size(), deepCopy); + } + + /// \brief Assign contents from a memory buffer + /// \param data a memory buffer + /// \param size the length of the memory buffer + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + void Assign(const byte *data, size_t size, bool deepCopy) + { + // This fires, which means: no data with a size, or data with no size. + // CRYPTOPP_ASSERT((data && size) || !(data || size)); + if (deepCopy) + m_block.Assign(data, size); + else + { + m_data = data; + m_size = size; + } + m_deepCopy = deepCopy; + } + + /// \brief Pointer to the first byte in the memory block + const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;} + /// \brief Pointer beyond the last byte in the memory block + const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;} + /// \brief Length of the memory block + size_t size() const {return m_deepCopy ? m_block.size() : m_size;} + +private: + bool m_deepCopy; + const byte *m_data; + size_t m_size; + SecByteBlock m_block; +}; + +/// \brief Used to pass byte array input as part of a NameValuePairs object +class ByteArrayParameter +{ +public: + /// \brief Construct a ByteArrayParameter + /// \param data a memory buffer + /// \param size the length of the memory buffer + ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0) + : m_data(data), m_size(size) {} + + /// \brief Construct a ByteArrayParameter + /// \param block a SecByteBlock + ByteArrayParameter(SecByteBlock &block) + : m_data(block.begin()), m_size(block.size()) {} + + /// \brief Pointer to the first byte in the memory block + byte *begin() const {return m_data;} + /// \brief Pointer beyond the last byte in the memory block + byte *end() const {return m_data + m_size;} + /// \brief Length of the memory block + size_t size() const {return m_size;} + +private: + byte *m_data; + size_t m_size; +}; + +/// \brief Combines two sets of NameValuePairs +/// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs. +/// If a name is not found in the first set, then the second set is searched for the +/// name and value pair. The second set of NameValuePairs often provides default values. +class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs +{ +public: + /// \brief Construct a CombinedNameValuePairs + /// \param pairs1 reference to the first set of NameValuePairs + /// \param pairs2 reference to the second set of NameValuePairs + CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2) + : m_pairs1(pairs1), m_pairs2(pairs2) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +private: + const NameValuePairs &m_pairs1, &m_pairs2; +}; + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +template +class GetValueHelperClass +{ +public: + GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst) + : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false) + { + if (strcmp(m_name, "ValueNames") == 0) + { + m_found = m_getValueNames = true; + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType); + if (searchFirst) + searchFirst->GetVoidValue(m_name, valueType, pValue); + if (typeid(T) != typeid(BASE)) + pObject->BASE::GetVoidValue(m_name, valueType, pValue); + ((*reinterpret_cast(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';'; + } + + if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType); + *reinterpret_cast(pValue) = pObject; + m_found = true; + return; + } + + if (!m_found && searchFirst) + m_found = searchFirst->GetVoidValue(m_name, valueType, pValue); + + if (!m_found && typeid(T) != typeid(BASE)) + m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue); + } + + operator bool() const {return m_found;} + + template + GetValueHelperClass & operator()(const char *name, const R & (T::*pm)() const) + { + if (m_getValueNames) + (*reinterpret_cast(m_pValue) += name) += ";"; + if (!m_found && strcmp(name, m_name) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType); + *reinterpret_cast(m_pValue) = (m_pObject->*pm)(); + m_found = true; + } + return *this; + } + + GetValueHelperClass &Assignable() + { +#ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason + if (m_getValueNames) + ((*reinterpret_cast(m_pValue) += "ThisObject:") += typeid(T).name()) += ';'; + if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType); + *reinterpret_cast(m_pValue) = *m_pObject; + m_found = true; + } +#endif + return *this; + } + +private: + const T *m_pObject; + const char *m_name; + const std::type_info *m_valueType; + void *m_pValue; + bool m_found, m_getValueNames; +}; + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +// ******************************************************** + +template +class AssignFromHelperClass +{ +public: + AssignFromHelperClass(T *pObject, const NameValuePairs &source) + : m_pObject(pObject), m_source(source), m_done(false) + { + if (source.GetThisObject(*pObject)) + m_done = true; + else if (typeid(BASE) != typeid(T)) + pObject->BASE::AssignFrom(source); + } + + template + AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&)) + { + if (!m_done) + { + R value; + if (!m_source.GetValue(name, value)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'"); + (m_pObject->*pm)(value); + } + return *this; + } + + template + AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&)) + { + if (!m_done) + { + R value1; + if (!m_source.GetValue(name1, value1)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'"); + S value2; + if (!m_source.GetValue(name2, value2)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'"); + (m_pObject->*pm)(value1, value2); + } + return *this; + } + +private: + T *m_pObject; + const NameValuePairs &m_source; + bool m_done; +}; + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ******************************************************** + +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER +// Allow the linker to discard Integer code if not needed. +// Also see http://github.com/weidai11/cryptopp/issues/389. +CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt); +#endif + +CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId(); + +/// \brief Base class for AlgorithmParameters +class CRYPTOPP_DLL AlgorithmParametersBase +{ +public: + /// \brief Exception thrown when an AlgorithmParameter is unused + class ParameterNotUsed : public Exception + { + public: + ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {} + }; + + virtual ~AlgorithmParametersBase() CRYPTOPP_THROW + { + +#if defined(CRYPTOPP_CXX17_EXCEPTIONS) + if (std::uncaught_exceptions() == 0) +#elif defined(CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE) + if (std::uncaught_exception() == false) +#else + try +#endif + { + if (m_throwIfNotUsed && !m_used) + throw ParameterNotUsed(m_name); + } +#if !defined(CRYPTOPP_CXX17_EXCEPTIONS) && !defined(CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE) + catch(const Exception&) + { + } +#endif + } + + // this is actually a move, not a copy + AlgorithmParametersBase(const AlgorithmParametersBase &x) + : m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used) + { + m_next.reset(const_cast(x).m_next.release()); + x.m_used = true; + } + + /// \brief Construct a AlgorithmParametersBase + /// \param name the parameter name + /// \param throwIfNotUsed flags indicating whether an exception should be thrown + /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception + /// will be thrown in the destructor if the parameter is not not retrieved. + AlgorithmParametersBase(const char *name, bool throwIfNotUsed) + : m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +protected: + friend class AlgorithmParameters; + void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60 + + virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0; + virtual void MoveInto(void *p) const =0; // not really const + + const char *m_name; + bool m_throwIfNotUsed; + mutable bool m_used; + member_ptr m_next; +}; + +/// \brief Template base class for AlgorithmParameters +/// \tparam T the class or type +template +class AlgorithmParametersTemplate : public AlgorithmParametersBase +{ +public: + /// \brief Construct an AlgorithmParametersTemplate + /// \param name the name of the value + /// \param value a reference to the value + /// \param throwIfNotUsed flags indicating whether an exception should be thrown + /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception + /// will be thrown in the destructor if the parameter is not not retrieved. + AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed) + : AlgorithmParametersBase(name, throwIfNotUsed), m_value(value) + { + } + + void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const + { +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER + // Special case for retrieving an Integer parameter when an int was passed in + if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value))) +#endif + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType); + *reinterpret_cast(pValue) = m_value; + } + } + +#if defined(DEBUG_NEW) && (_MSC_VER >= 1300) +# pragma push_macro("new") +# undef new +#endif + + void MoveInto(void *buffer) const + { + AlgorithmParametersTemplate* p = new(buffer) AlgorithmParametersTemplate(*this); + CRYPTOPP_UNUSED(p); // silence warning + } + +#if defined(DEBUG_NEW) && (_MSC_VER >= 1300) +# pragma pop_macro("new") +#endif + +protected: + T m_value; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; + +/// \brief An object that implements NameValuePairs +/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by +/// repeatedly using operator() on the object returned by MakeParameters, for example: +///
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   
+class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs +{ +public: + /// \brief Construct a AlgorithmParameters + /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by + /// repeatedly using operator() on the object returned by MakeParameters, for example: + ///
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   
+ AlgorithmParameters(); + +#ifdef __BORLANDC__ + /// \brief Construct a AlgorithmParameters + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed + /// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), + /// such as MSVC 7.0 and earlier. + /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by + /// repeatedly using operator() on the object returned by MakeParameters, for example: + ///
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   
+ template + AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true) + : m_next(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)) + , m_defaultThrowIfNotUsed(throwIfNotUsed) + { + } +#endif + + AlgorithmParameters(const AlgorithmParameters &x); + + AlgorithmParameters & operator=(const AlgorithmParameters &x); + + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed + template + AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed) + { + member_ptr p(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)); + p->m_next.reset(m_next.release()); + m_next.reset(p.release()); + m_defaultThrowIfNotUsed = throwIfNotUsed; + return *this; + } + + /// \brief Appends a NameValuePair to a collection of NameValuePairs + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + template + AlgorithmParameters & operator()(const char *name, const T &value) + { + return operator()(name, value, m_defaultThrowIfNotUsed); + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +protected: + member_ptr m_next; + bool m_defaultThrowIfNotUsed; +}; + +/// \brief Create an object that implements NameValuePairs +/// \tparam T the class or type +/// \param name the name of the object or value to retrieve +/// \param value reference to a variable that receives the value +/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed +/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), +/// such as MSVC 7.0 and earlier. +/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by +/// repeatedly using \p operator() on the object returned by \p MakeParameters, for example: +///
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   
+#ifdef __BORLANDC__ +typedef AlgorithmParameters MakeParameters; +#else +template +AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true) +{ + return AlgorithmParameters()(name, value, throwIfNotUsed); +} +#endif + +#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2) + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/arc4.h b/include/cryptlib/arc4.h new file mode 100644 index 0000000..99ffdd6 --- /dev/null +++ b/include/cryptlib/arc4.h @@ -0,0 +1,89 @@ +// arc4.h - originally written and placed in the public domain by Wei Dai + +/// \file arc4.h +/// \brief Classes for ARC4 cipher +/// \since Crypto++ 3.1 + +#ifndef CRYPTOPP_ARC4_H +#define CRYPTOPP_ARC4_H + +#include "cryptlib.h" +#include "strciphr.h" +#include "secblock.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief ARC4 base class +/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions +/// \since Crypto++ 3.1 +class CRYPTOPP_NO_VTABLE ARC4_Base : public VariableKeyLength<16, 1, 256>, public RandomNumberGenerator, public SymmetricCipher, public SymmetricCipherDocumentation +{ +public: + ~ARC4_Base(); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARC4";} + + void GenerateBlock(byte *output, size_t size); + void DiscardBytes(size_t n); + + void ProcessData(byte *outString, const byte *inString, size_t length); + + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + + typedef SymmetricCipherFinal Encryption; + typedef SymmetricCipherFinal Decryption; + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + virtual unsigned int GetDefaultDiscardBytes() const {return 0;} + + FixedSizeSecBlock m_state; + byte m_x, m_y; +}; + +/// \brief Alleged RC4 +/// \sa Alleged RC4 +/// \since Crypto++ 3.1 +DOCUMENTED_TYPEDEF(SymmetricCipherFinal, ARC4) + +/// \brief MARC4 base class +/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions +/// \details MARC4 discards the first 256 bytes of keystream, which may be weaker than the rest +/// \since Crypto++ 3.1 +class CRYPTOPP_NO_VTABLE MARC4_Base : public ARC4_Base +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARC4";} + + typedef SymmetricCipherFinal Encryption; + typedef SymmetricCipherFinal Decryption; + +protected: + unsigned int GetDefaultDiscardBytes() const {return 256;} +}; + +/// \brief Modified Alleged RC4 +/// \sa Alleged RC4 +/// \since Crypto++ 3.1 +DOCUMENTED_TYPEDEF(SymmetricCipherFinal, MARC4) + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/argnames.h b/include/cryptlib/argnames.h new file mode 100644 index 0000000..4f929d5 --- /dev/null +++ b/include/cryptlib/argnames.h @@ -0,0 +1,99 @@ +// argnames.h - originally written and placed in the public domain by Wei Dai + +/// \file argnames.h +/// \brief Standard names for retrieving values by name when working with \p NameValuePairs + +#ifndef CRYPTOPP_ARGNAMES_H +#define CRYPTOPP_ARGNAMES_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +DOCUMENTED_NAMESPACE_BEGIN(Name) + +#define CRYPTOPP_DEFINE_NAME_STRING(name) inline const char *name() {return #name;} + +CRYPTOPP_DEFINE_NAME_STRING(ValueNames) ///< string, a list of value names with a semicolon (';') after each name +CRYPTOPP_DEFINE_NAME_STRING(Version) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Seed) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Key) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(IV) ///< ConstByteArrayParameter, also accepts const byte * for backwards compatibility +CRYPTOPP_DEFINE_NAME_STRING(StolenIV) ///< byte * +CRYPTOPP_DEFINE_NAME_STRING(Nonce) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Rounds) ///< int +CRYPTOPP_DEFINE_NAME_STRING(FeedbackSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(WordSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(BlockSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(EffectiveKeyLength) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(KeySize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(ModulusSize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrderSize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponentSize)///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(Modulus) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicElement) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrder) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(Cofactor) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupGenerator) ///< Integer, ECP::Point, or EC2N::Point +CRYPTOPP_DEFINE_NAME_STRING(Curve) ///< ECP or EC2N +CRYPTOPP_DEFINE_NAME_STRING(GroupOID) ///< OID +CRYPTOPP_DEFINE_NAME_STRING(PointerToPrimeSelector) ///< const PrimeSelector * +CRYPTOPP_DEFINE_NAME_STRING(Prime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(Prime2) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime1PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime2PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(MultiplicativeInverseOfPrime2ModPrime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime2) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PutMessage) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(TruncatedDigestSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(BlockPaddingScheme) ///< StreamTransformationFilter::BlockPaddingScheme +CRYPTOPP_DEFINE_NAME_STRING(HashVerificationFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(AuthenticatedDecryptionFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(SignatureVerificationFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(InputBuffer) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(OutputBuffer) ///< ByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(InputFileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(InputFileNameWide) ///< const wchar_t * +CRYPTOPP_DEFINE_NAME_STRING(InputStreamPointer) ///< std::istream * +CRYPTOPP_DEFINE_NAME_STRING(InputBinaryMode) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(OutputFileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(OutputFileNameWide) ///< const wchar_t * +CRYPTOPP_DEFINE_NAME_STRING(OutputStreamPointer) ///< std::ostream * +CRYPTOPP_DEFINE_NAME_STRING(OutputBinaryMode) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(EncodingParameters) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(KeyDerivationParameters) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Separator) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Terminator) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Uppercase) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(GroupSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Pad) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(PaddingByte) ///< byte +CRYPTOPP_DEFINE_NAME_STRING(Log2Base) ///< int +CRYPTOPP_DEFINE_NAME_STRING(EncodingLookupArray) ///< const byte * +CRYPTOPP_DEFINE_NAME_STRING(DecodingLookupArray) ///< const byte * +CRYPTOPP_DEFINE_NAME_STRING(InsertLineBreaks) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(MaxLineLength) ///< int +CRYPTOPP_DEFINE_NAME_STRING(DigestSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(L1KeyLength) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(TableSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(Blinding) ///< bool, timing attack mitigations, ON by default +CRYPTOPP_DEFINE_NAME_STRING(DerivedKey) ///< ByteArrayParameter, key derivation, derived key +CRYPTOPP_DEFINE_NAME_STRING(DerivedKeyLength) ///< int, key derivation, derived key length in bytes +CRYPTOPP_DEFINE_NAME_STRING(Personalization) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(PersonalizationSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(Salt) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Tweak) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(SaltSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(TreeMode) ///< byte +CRYPTOPP_DEFINE_NAME_STRING(FileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(FileTime) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Comment) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(Identity) ///< ConstByteArrayParameter +DOCUMENTED_NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/aria.h b/include/cryptlib/aria.h new file mode 100644 index 0000000..d4f3090 --- /dev/null +++ b/include/cryptlib/aria.h @@ -0,0 +1,71 @@ +// aria.h - written and placed in the public domain by Jeffrey Walton + +/// \file aria.h +/// \brief Classes for the ARIA block cipher +/// \details The Crypto++ 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. +/// \sa RFC 5794, A Description of the ARIA Encryption Algorithm, +/// Korea +/// Internet & Security Agency homepage + +#ifndef CRYPTOPP_ARIA_H +#define CRYPTOPP_ARIA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ARIA block cipher information +/// \since Crypto++ 6.0 +struct ARIA_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARIA";} +}; + +/// \brief ARIA block cipher +/// \details The Crypto++ 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. +/// \sa RFC 5794, A Description of the ARIA Encryption Algorithm, +/// Korea +/// Internet & Security Agency homepage +/// \sa ARIA +/// \since Crypto++ 6.0 +class ARIA : public ARIA_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + Base() : m_rounds(0) {} + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + // Reference implementation allocates a table of 17 round keys. + typedef SecBlock > AlignedByteBlock; + typedef SecBlock > AlignedWordBlock; + + AlignedByteBlock m_rk; // round keys + AlignedWordBlock m_w; // w0, w1, w2, w3, t and u + unsigned int m_rounds; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef ARIA::Encryption ARIAEncryption; +typedef ARIA::Decryption ARIADecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/asn.h b/include/cryptlib/asn.h new file mode 100644 index 0000000..95590d0 --- /dev/null +++ b/include/cryptlib/asn.h @@ -0,0 +1,577 @@ +// asn.h - originally written and placed in the public domain by Wei Dai + +/// \file asn.h +/// \brief Classes and functions for working with ANS.1 objects + +#ifndef CRYPTOPP_ASN_H +#define CRYPTOPP_ASN_H + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "queue.h" +#include "misc.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ASN.1 types +/// \note These tags and flags are not complete +enum ASNTag +{ + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + TAG_NULL = 0x05, + OBJECT_IDENTIFIER = 0x06, + OBJECT_DESCRIPTOR = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0a, + UTF8_STRING = 0x0c, + SEQUENCE = 0x10, + SET = 0x11, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + VIDEOTEXT_STRING = 0x15, + IA5_STRING = 0x16, + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + GRAPHIC_STRING = 0x19, + VISIBLE_STRING = 0x1a, + GENERAL_STRING = 0x1b +}; + +/// \brief ASN.1 flags +/// \note These tags and flags are not complete +enum ASNIdFlag +{ + UNIVERSAL = 0x00, +// DATA = 0x01, +// HEADER = 0x02, + PRIMITIVE = 0x00, + CONSTRUCTED = 0x20, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + PRIVATE = 0xc0 +}; + +/// \brief Raises a BERDecodeErr +inline void BERDecodeError() {throw BERDecodeErr();} + +/// \brief Exception thrown when an unknown object identifier is encountered +class CRYPTOPP_DLL UnknownOID : public BERDecodeErr +{ +public: + /// \brief Construct an UnknownOID + UnknownOID() : BERDecodeErr("BER decode error: unknown object identifier") {} + /// \brief Construct an UnknownOID + /// \param err error message to use for the execption + UnknownOID(const char *err) : BERDecodeErr(err) {} +}; + +// unsigned int DERLengthEncode(unsigned int length, byte *output=0); + +/// \brief DER encode a length +/// \param bt BufferedTransformation object for writing +/// \param length the size to encode +/// \returns the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DERLengthEncode(BufferedTransformation &bt, lword length); + +/// \brief BER decode a length +/// \param bt BufferedTransformation object for reading +/// \param length the decoded size +/// \returns true if the value was decoded +/// \throws BERDecodeError if the value fails to decode or is too large for size_t +/// \details BERLengthDecode() returns false if the encoding is indefinite length. +CRYPTOPP_DLL bool CRYPTOPP_API BERLengthDecode(BufferedTransformation &bt, size_t &length); + +/// \brief DER encode NULL +/// \param bt BufferedTransformation object for writing +CRYPTOPP_DLL void CRYPTOPP_API DEREncodeNull(BufferedTransformation &bt); + +/// \brief BER decode NULL +/// \param bt BufferedTransformation object for reading +CRYPTOPP_DLL void CRYPTOPP_API BERDecodeNull(BufferedTransformation &bt); + +/// \brief DER encode octet string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string +/// \returns the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen); + +/// \brief DER encode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the string to encode +/// \returns the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str); + +/// \brief BER decode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \returns the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str); + +/// \brief BER decode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \returns the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param asnTag the ASN.1 type +/// \returns the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag); + +/// \brief BER decode text string +/// \param bt BufferedTransformation object for reading +/// \param str the string to encode +/// \param asnTag the ASN.1 type +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag); + +/// \brief DER encode bit string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string +/// \param unusedBits the number of unused bits +/// \returns the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits=0); + +/// \brief DER decode bit string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \param unusedBits the number of unused bits +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits); + +/// \brief BER decode and DER re-encode +/// \param bt BufferedTransformation object for writing +/// \param dest BufferedTransformation object +CRYPTOPP_DLL void CRYPTOPP_API DERReencode(BufferedTransformation &bt, BufferedTransformation &dest); + +/// \brief Object Identifier +class CRYPTOPP_DLL OID +{ +public: + virtual ~OID() {} + + /// \brief Construct an OID + OID() {} + /// \brief Construct an OID + /// \param v value to initialize the OID + OID(word32 v) : m_values(1, v) {} + /// \brief Construct an OID + /// \param bt BufferedTransformation object + OID(BufferedTransformation &bt) {BERDecode(bt);} + + /// \brief Append a value to an OID + /// \param rhs the value to append + inline OID & operator+=(word32 rhs) {m_values.push_back(rhs); return *this;} + + /// \brief DER encode this OID + /// \param bt BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief BER decode an OID + /// \param bt BufferedTransformation object + void BERDecode(BufferedTransformation &bt); + + /// \brief BER decode an OID + /// \param bt BufferedTransformation object + /// \throws BERDecodeErr() if decoded value doesn't match an expected OID + /// \details BERDecodeAndCheck() can be used to parse an OID and verify it matches an expected. + ///
+	///   BERSequenceDecoder key(bt);
+	///   ...
+	///   BERSequenceDecoder algorithm(key);
+	///   GetAlgorithmID().BERDecodeAndCheck(algorithm);
+	/// 
+ void BERDecodeAndCheck(BufferedTransformation &bt) const; + + const std::vector& GetValues() const { + return m_values; + } + +protected: + friend bool operator==(const OID &lhs, const OID &rhs); + friend bool operator!=(const OID &lhs, const OID &rhs); + friend bool operator<(const OID &lhs, const OID &rhs); + + std::vector m_values; + +private: + static void EncodeValue(BufferedTransformation &bt, word32 v); + static size_t DecodeValue(BufferedTransformation &bt, word32 &v); +}; + +/// \brief ASN.1 encoded object filter +class EncodedObjectFilter : public Filter +{ +public: + enum Flag {PUT_OBJECTS=1, PUT_MESSANGE_END_AFTER_EACH_OBJECT=2, PUT_MESSANGE_END_AFTER_ALL_OBJECTS=4, PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS=8}; + enum State {IDENTIFIER, LENGTH, BODY, TAIL, ALL_DONE} m_state; + + virtual ~EncodedObjectFilter() {} + + /// \brief Construct an EncodedObjectFilter + /// \param attachment a BufferedTrasformation to attach to this object + /// \param nObjects the number of objects + /// \param flags bitwise OR of EncodedObjectFilter::Flag + EncodedObjectFilter(BufferedTransformation *attachment = NULLPTR, unsigned int nObjects = 1, word32 flags = 0); + + /// \brief Input a byte buffer for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + void Put(const byte *inString, size_t length); + + unsigned int GetNumberOfCompletedObjects() const {return m_nCurrentObject;} + unsigned long GetPositionOfObject(unsigned int i) const {return m_positions[i];} + +private: + BufferedTransformation & CurrentTarget(); + + ByteQueue m_queue; + std::vector m_positions; + lword m_lengthRemaining; + word32 m_nObjects, m_nCurrentObject, m_level, m_flags; + byte m_id; +}; + +/// \brief BER General Decoder +class CRYPTOPP_DLL BERGeneralDecoder : public Store +{ +public: + virtual ~BERGeneralDecoder(); + + explicit BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag); + explicit BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag); + + bool IsDefiniteLength() const {return m_definiteLength;} + lword RemainingLength() const {CRYPTOPP_ASSERT(m_definiteLength); return m_length;} + bool EndReached() const; + byte PeekByte() const; + void CheckByte(byte b); + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + // call this to denote end of sequence + void MessageEnd(); + +protected: + BufferedTransformation &m_inQueue; + lword m_length; + bool m_finished, m_definiteLength; + +private: + void Init(byte asnTag); + void StoreInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} + lword ReduceLength(lword delta); +}; + +/// \brief DER General Encoder +class CRYPTOPP_DLL DERGeneralEncoder : public ByteQueue +{ +public: + virtual ~DERGeneralEncoder(); + + explicit DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED); + explicit DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED); + + // call this to denote end of sequence + void MessageEnd(); + +private: + BufferedTransformation &m_outQueue; + byte m_asnTag; + bool m_finished; +}; + +/// \brief BER Sequence Decoder +class CRYPTOPP_DLL BERSequenceDecoder : public BERGeneralDecoder +{ +public: + explicit BERSequenceDecoder(BufferedTransformation &inQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} + explicit BERSequenceDecoder(BERSequenceDecoder &inQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +/// \brief DER Sequence Encoder +class CRYPTOPP_DLL DERSequenceEncoder : public DERGeneralEncoder +{ +public: + explicit DERSequenceEncoder(BufferedTransformation &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} + explicit DERSequenceEncoder(DERSequenceEncoder &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +/// \brief BER Set Decoder +class CRYPTOPP_DLL BERSetDecoder : public BERGeneralDecoder +{ +public: + explicit BERSetDecoder(BufferedTransformation &inQueue, byte asnTag = SET | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} + explicit BERSetDecoder(BERSetDecoder &inQueue, byte asnTag = SET | CONSTRUCTED) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +/// \brief DER Set Encoder +class CRYPTOPP_DLL DERSetEncoder : public DERGeneralEncoder +{ +public: + explicit DERSetEncoder(BufferedTransformation &outQueue, byte asnTag = SET | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} + explicit DERSetEncoder(DERSetEncoder &outQueue, byte asnTag = SET | CONSTRUCTED) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +/// \brief Optional data encoder and decoder +/// \tparam T class or type +template +class ASNOptional : public member_ptr +{ +public: + /// \brief BER decode optional data + /// \param seqDecoder sequence with the optional ASN.1 data + /// \param tag ASN.1 tag to match as optional data + /// \param mask the mask to apply when matching the tag + /// \sa ASNTag and ASNIdFlag + void BERDecode(BERSequenceDecoder &seqDecoder, byte tag, byte mask = ~CONSTRUCTED) + { + byte b; + if (seqDecoder.Peek(b) && (b & mask) == tag) + reset(new T(seqDecoder)); + } + + /// \brief DER encode optional data + /// \param out BufferedTransformation object + void DEREncode(BufferedTransformation &out) + { + if (this->get() != NULLPTR) + this->get()->DEREncode(out); + } +}; + +/// \brief Encode and decode ASN.1 objects with additional information +/// \tparam BASE base class or type +/// \details Encodes and decodes public keys, private keys and group +/// parameters with OID identifying the algorithm or scheme. +template +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1CryptoMaterial : public ASN1Object, public BASE +{ +public: + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo and privateKeyInfo parts. + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + void Load(BufferedTransformation &bt) + {BERDecode(bt);} +}; + +/// \brief Encodes and decodes subjectPublicKeyInfo +class CRYPTOPP_DLL X509PublicKey : public ASN1CryptoMaterial +{ +public: + virtual ~X509PublicKey() {} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Retrieves the OID of the algorithm + /// \returns OID of the algorithm + virtual OID GetAlgorithmID() const =0; + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} // see RFC 2459, section 7.3.1 + + /// decode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header + virtual void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0; + /// encode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header + virtual void DEREncodePublicKey(BufferedTransformation &bt) const =0; +}; + +/// \brief Encodes and decodesprivateKeyInfo +class CRYPTOPP_DLL PKCS8PrivateKey : public ASN1CryptoMaterial +{ +public: + virtual ~PKCS8PrivateKey() {} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Retrieves the OID of the algorithm + /// \returns OID of the algorithm + virtual OID GetAlgorithmID() const =0; + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} // see RFC 2459, section 7.3.1 + + /// decode privateKey part of privateKeyInfo, without the OCTET STRING header + virtual void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0; + /// encode privateKey part of privateKeyInfo, without the OCTET STRING header + virtual void DEREncodePrivateKey(BufferedTransformation &bt) const =0; + + /// decode optional attributes including context-specific tag + /*! /note default implementation stores attributes to be output in DEREncodeOptionalAttributes */ + virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt); + /// encode optional attributes including context-specific tag + virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const; + +protected: + ByteQueue m_optionalAttributes; +}; + +// ******************************************************** + +/// \brief DER Encode unsigned value +/// \tparam T class or type +/// \param out BufferedTransformation object +/// \param w unsigned value to encode +/// \param asnTag the ASN.1 type +/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM +template +size_t DEREncodeUnsigned(BufferedTransformation &out, T w, byte asnTag = INTEGER) +{ + byte buf[sizeof(w)+1]; + unsigned int bc; + if (asnTag == BOOLEAN) + { + buf[sizeof(w)] = w ? 0xff : 0; + bc = 1; + } + else + { + buf[0] = 0; + for (unsigned int i=0; i> (sizeof(w)-1-i)*8); + bc = sizeof(w); + while (bc > 1 && buf[sizeof(w)+1-bc] == 0) + --bc; + if (buf[sizeof(w)+1-bc] & 0x80) + ++bc; + } + out.Put(asnTag); + size_t lengthBytes = DERLengthEncode(out, bc); + out.Put(buf+sizeof(w)+1-bc, bc); + return 1+lengthBytes+bc; +} + +/// \brief BER Decode unsigned value +/// \tparam T fundamental C++ type +/// \param in BufferedTransformation object +/// \param w the decoded value +/// \param asnTag the ASN.1 type +/// \param minValue the minimum expected value +/// \param maxValue the maximum expected value +/// \throws BERDecodeErr() if the value cannot be parsed or the decoded value is not within range. +/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM +template +void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER, + T minValue = 0, T maxValue = T(0xffffffff)) +{ + byte b; + if (!in.Get(b) || b != asnTag) + BERDecodeError(); + + size_t bc; + bool definite = BERLengthDecode(in, bc); + if (!definite) + BERDecodeError(); + if (bc > in.MaxRetrievable()) // Issue 346 + BERDecodeError(); + if (asnTag == BOOLEAN && bc != 1) // X.690, 8.2.1 + BERDecodeError(); + if ((asnTag == INTEGER || asnTag == ENUMERATED) && bc == 0) // X.690, 8.3.1 and 8.4 + BERDecodeError(); + + SecByteBlock buf(bc); + + if (bc != in.Get(buf, bc)) + BERDecodeError(); + + // This consumes leading 0 octets. According to X.690, 8.3.2, it could be non-conforming behavior. + // X.690, 8.3.2 says "the bits of the first octet and bit 8 of the second octet ... (a) shall + // not all be ones and (b) shall not all be zeros ... These rules ensure that an integer value + // is always encoded in the smallest possible number of octet". + // We invented AER (Alternate Encoding Rules), which is more relaxed than BER, CER, and DER. + const byte *ptr = buf; + while (bc > sizeof(w) && *ptr == 0) + { + bc--; + ptr++; + } + if (bc > sizeof(w)) + BERDecodeError(); + + w = 0; + for (unsigned int i=0; i maxValue) + BERDecodeError(); +} + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Compare two OIDs for equality +/// \param lhs the first OID +/// \param rhs the second OID +/// \returns true if the OIDs are equal, false otherwise +inline bool operator==(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for inequality +/// \param lhs the first OID +/// \param rhs the second OID +/// \returns true if the OIDs are not equal, false otherwise +inline bool operator!=(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \returns true if the first OID is less than the second OID, false otherwise +/// \details operator<() calls std::lexicographical_compare() on each element in the array of values. +inline bool operator<(const OID &lhs, const OID &rhs); +/// \brief Append a value to an OID +/// \param lhs the OID +/// \param rhs the value to append +inline OID operator+(const OID &lhs, unsigned long rhs); +#else +inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values == rhs.m_values;} +inline bool operator!=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values != rhs.m_values;} +inline bool operator<(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return std::lexicographical_compare(lhs.m_values.begin(), lhs.m_values.end(), rhs.m_values.begin(), rhs.m_values.end());} +inline ::CryptoPP::OID operator+(const ::CryptoPP::OID &lhs, unsigned long rhs) + {return ::CryptoPP::OID(lhs)+=rhs;} +#endif + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/include/cryptlib/authenc.h b/include/cryptlib/authenc.h new file mode 100644 index 0000000..e570798 --- /dev/null +++ b/include/cryptlib/authenc.h @@ -0,0 +1,87 @@ +// authenc.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for authenticated encryption modes of operation +/// \details Authenticated encryption (AE) schemes combine confidentiality and authenticity +/// into a single mode of operation They gained traction in the early 2000's because manually +/// combining them was error prone for the typical developer. Around that time, the desire to +/// authenticate but not ecrypt additional data (AAD) was also identified. When both features +/// are available from a scheme, the system is referred to as an AEAD scheme. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the +/// motivation for the API, like calling AAD a "header", can be found in Bellare, +/// Rogaway and Wagner's The EAX +/// Mode of Operation. The EAX paper suggested a basic API to help standardize AEAD +/// schemes in software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_AUTHENC_H +#define CRYPTOPP_AUTHENC_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base class for authenticated encryption modes of operation +/// \details AuthenticatedSymmetricCipherBase() serves as a base implementation for one direction +/// (encryption or decryption) of a stream cipher or block cipher mode with authentication. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the +/// motivation for the API, like calling AAD a "header", can be found in Bellare, +/// Rogaway and Wagner's The EAX +/// Mode of Operation. The EAX paper suggested a basic API to help standardize AEAD +/// schemes in software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipherBase : public AuthenticatedSymmetricCipher +{ +public: + AuthenticatedSymmetricCipherBase() : m_totalHeaderLength(0), m_totalMessageLength(0), + m_totalFooterLength(0), m_bufferedDataLength(0), m_state(State_Start) {} + + // StreamTransformation interface + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + + void SetKey(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Restart() {if (m_state > State_KeySet) m_state = State_KeySet;} + void Resynchronize(const byte *iv, int length=-1); + void Update(const byte *input, size_t length); + void ProcessData(byte *outString, const byte *inString, size_t length); + void TruncatedFinal(byte *mac, size_t macSize); + +protected: + void UncheckedSetKey(const byte * key, unsigned int length,const CryptoPP::NameValuePairs ¶ms) + {CRYPTOPP_UNUSED(key), CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); CRYPTOPP_ASSERT(false);} + + void AuthenticateData(const byte *data, size_t len); + const SymmetricCipher & GetSymmetricCipher() const + {return const_cast(this)->AccessSymmetricCipher();}; + + virtual SymmetricCipher & AccessSymmetricCipher() =0; + virtual bool AuthenticationIsOnPlaintext() const =0; + virtual unsigned int AuthenticationBlockSize() const =0; + virtual void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) =0; + virtual void Resync(const byte *iv, size_t len) =0; + virtual size_t AuthenticateBlocks(const byte *data, size_t len) =0; + virtual void AuthenticateLastHeaderBlock() =0; + virtual void AuthenticateLastConfidentialBlock() {} + virtual void AuthenticateLastFooterBlock(byte *mac, size_t macSize) =0; + + // State_AuthUntransformed: authentication is applied to plain text (Authenticate-then-Encrypt) + // State_AuthTransformed: authentication is applied to cipher text (Encrypt-then-Authenticate) + enum State {State_Start, State_KeySet, State_IVSet, State_AuthUntransformed, State_AuthTransformed, State_AuthFooter}; + + AlignedSecByteBlock m_buffer; + lword m_totalHeaderLength, m_totalMessageLength, m_totalFooterLength; + unsigned int m_bufferedDataLength; + State m_state; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/base32.h b/include/cryptlib/base32.h new file mode 100644 index 0000000..80a64ed --- /dev/null +++ b/include/cryptlib/base32.h @@ -0,0 +1,158 @@ +// base32.h - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai +// extended hex alphabet added by JW in November, 2017. + +/// \file base32.h +/// \brief Classes for Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + +#ifndef CRYPTOPP_BASE32_H +#define CRYPTOPP_BASE32_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base32 encodes data using DUDE encoding +/// \details Converts data to base32 using DUDE encoding. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder +class Base32Encoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base32Encoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \details Base32Encoder() constructs a default encoder. The constructor lacks fields for padding and + /// line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32Encoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base32Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ /// \details You can change the encoding to RFC 4648, Base + /// 32 Encoding with Extended Hex Alphabet by performing the following: + ///
+	///     Base32Encoder encoder;
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);
+ /// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and + /// the decoder's lookup table. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base32 decodes data using DUDE encoding +/// \details Converts data from base32 using DUDE encoding. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder +class Base32Decoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base32Decoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa IsolatedInitialize() for an example of modifying a Base32Decoder after construction. + Base32Decoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details You can change the encoding to RFC 4648, Base + /// 32 Encoding with Extended Hex Alphabet by performing the following: + ///
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     Base32Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 32, true /*insensitive*/);
+	///
+	///     Base32Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);
+ /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +/// \brief Base32 encodes data using extended hex +/// \details Converts data to base32 using extended hex alphabet. The alphabet is different than Base32Encoder. +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +/// \since Crypto++ 6.0 +class Base32HexEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base32HexEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \details Base32HexEncoder() constructs a default encoder. The constructor lacks fields for padding and + /// line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base32HexEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base32 decodes data using extended hex +/// \details Converts data from base32 using extended hex alphabet. The alphabet is different than Base32Decoder. +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +/// \since Crypto++ 6.0 +class Base32HexDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base32HexDecoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/base64.h b/include/cryptlib/base64.h new file mode 100644 index 0000000..be5c6b7 --- /dev/null +++ b/include/cryptlib/base64.h @@ -0,0 +1,158 @@ +// base64.h - originally written and placed in the public domain by Wei Dai + +/// \file base64.h +/// \brief Classes for the Base64Encoder, Base64Decoder, Base64URLEncoder and Base64URLDecoder + +#ifndef CRYPTOPP_BASE64_H +#define CRYPTOPP_BASE64_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base64 encodes data using DUDE +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding. +class Base64Encoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base64Encoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param insertLineBreaks a BufferedTrasformation to attach to this object + /// \param maxLineLength the length of a line if line breaks are used + /// \details Base64Encoder constructs a default encoder. The constructor lacks a parameter for padding, and you must + /// use IsolatedInitialize() to modify the Base64Encoder after construction. + /// \sa IsolatedInitialize() for an example of modifying an encoder after construction. + Base64Encoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = true, int maxLineLength = 72) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), insertLineBreaks)(Name::MaxLineLength(), maxLineLength)); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base64Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ /// \details You can change the encoding to RFC 4648 web safe alphabet by performing the following: + ///
+	///     Base64Encoder encoder;
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);
+ /// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and + /// the decoder's lookup table. + /// \sa Base64URLEncoder for an encoder that provides the web safe alphabet, and Base64Decoder::IsolatedInitialize() + /// for an example of modifying a decoder's lookup table after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base64 decodes data using DUDE +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding. +class Base64Decoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base64Decoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa IsolatedInitialize() for an example of modifying an encoder after construction. + Base64Decoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The default decoding alpahbet is RFC 4868. You can change the to RFC 4868 web safe alphabet + /// by performing the following: + ///
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     Base64Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 64, false);
+	///
+	///     Base64Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);
+ /// \sa Base64URLDecoder for a decoder that provides the web safe alphabet, and Base64Encoder::IsolatedInitialize() + /// for an example of modifying an encoder's alphabet after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +/// \brief Base64 encodes data using a web safe alphabet +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding +/// with URL and Filename Safe Alphabet. +class Base64URLEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base64URLEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param insertLineBreaks a BufferedTrasformation to attach to this object + /// \param maxLineLength the length of a line if line breaks are used + /// \details Base64URLEncoder() constructs a default encoder using a web safe alphabet. The constructor ignores + /// insertLineBreaks and maxLineLength because the web and URL safe specifications don't use them. They are + /// present in the constructor for API compatibility with Base64Encoder so it is a drop-in replacement. The + /// constructor also disables padding on the encoder for the same reason. + /// \details If you need line breaks or padding, then you must use IsolatedInitialize() to set them + /// after constructing a Base64URLEncoder. + /// \sa Base64Encoder for an encoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize + /// for an example of modifying an encoder after construction. + Base64URLEncoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = false, int maxLineLength = -1) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + CRYPTOPP_UNUSED(insertLineBreaks), CRYPTOPP_UNUSED(maxLineLength); + IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), false)(Name::MaxLineLength(), -1)(Name::Pad(),false)); + } + + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base64URLEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Name::Pad(), true)(Name::InsertLineBreaks(), true);
+	///     encoder.IsolatedInitialize(params);
+ /// \sa Base64Encoder for an encoder that provides a classic alphabet. + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base64 decodes data using a web safe alphabet +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding +/// with URL and Filename Safe Alphabet. +class Base64URLDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base64URLDecoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \details Base64URLDecoder() constructs a default decoder using a web safe alphabet. + /// \sa Base64Decoder for a decoder that provides a classic alphabet. + Base64URLDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on + /// attached transformations. If initialization should be propagated, then use the Initialize() function. + /// \sa Base64Decoder for a decoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize + /// for an example of modifying an encoder after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/basecode.h b/include/cryptlib/basecode.h new file mode 100644 index 0000000..c4866df --- /dev/null +++ b/include/cryptlib/basecode.h @@ -0,0 +1,139 @@ +// basecode.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Base classes for working with encoders and decoders. + +#ifndef CRYPTOPP_BASECODE_H +#define CRYPTOPP_BASECODE_H + +#include "cryptlib.h" +#include "filters.h" +#include "algparam.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Encoder for bases that are a power of 2 +class CRYPTOPP_DLL BaseN_Encoder : public Unflushable +{ +public: + /// \brief Construct a BaseN_Encoder + /// \param attachment a BufferedTransformation to attach to this object + BaseN_Encoder(BufferedTransformation *attachment=NULLPTR) + : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + {Detach(attachment);} + + /// \brief Construct a BaseN_Encoder + /// \param alphabet table of ASCII characters to use as the alphabet + /// \param log2base the log2base + /// \param attachment a BufferedTransformation to attach to this object + /// \param padding the character to use as padding + /// \pre log2base must be between 1 and 7 inclusive + /// \throws InvalidArgument if log2base is not between 1 and 7 + BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULLPTR, int padding=-1) + : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + { + Detach(attachment); + IsolatedInitialize(MakeParameters(Name::EncodingLookupArray(), alphabet) + (Name::Log2Base(), log2base) + (Name::Pad(), padding != -1) + (Name::PaddingByte(), byte(padding))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + +private: + const byte *m_alphabet; + int m_padding, m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +/// \brief Decoder for bases that are a power of 2 +class CRYPTOPP_DLL BaseN_Decoder : public Unflushable +{ +public: + /// \brief Construct a BaseN_Decoder + /// \param attachment a BufferedTransformation to attach to this object + /// \details padding is set to -1, which means use default padding. If not + /// required, then the value must be set via IsolatedInitialize(). + BaseN_Decoder(BufferedTransformation *attachment=NULLPTR) + : m_lookup(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + {Detach(attachment);} + + /// \brief Construct a BaseN_Decoder + /// \param lookup table of values + /// \param log2base the log2base + /// \param attachment a BufferedTransformation to attach to this object + /// \details log2base is the exponent (like 5 in 25), and not + /// the number of elements (like 32). + /// \details padding is set to -1, which means use default padding. If not + /// required, then the value must be set via IsolatedInitialize(). + BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULLPTR) + : m_lookup(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + { + Detach(attachment); + IsolatedInitialize(MakeParameters(Name::DecodingLookupArray(), lookup)(Name::Log2Base(), log2base)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + + /// \brief Initializes BaseN lookup array + /// \param lookup table of values + /// \param alphabet table of ASCII characters + /// \param base the base for the encoder + /// \param caseInsensitive flag indicating whether the alphabet is case sensitivie + /// \pre COUNTOF(lookup) == 256 + /// \pre COUNTOF(alphabet) == base + /// \details Internally, the function sets the first 256 elements in the lookup table to + /// their value from the alphabet array or -1. base is the number of element (like 32), + /// and not an exponent (like 5 in 25) + static void CRYPTOPP_API InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive); + +private: + const int *m_lookup; + int m_padding, m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +/// \brief Filter that breaks input stream into groups of fixed size +class CRYPTOPP_DLL Grouper : public Bufferless +{ +public: + /// \brief Construct a Grouper + /// \param attachment a BufferedTransformation to attach to this object + Grouper(BufferedTransformation *attachment=NULLPTR) + : m_groupSize(0), m_counter(0) {Detach(attachment);} + + /// \brief Construct a Grouper + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \param attachment a BufferedTransformation to attach to this object + Grouper(int groupSize, const std::string &separator, const std::string &terminator, BufferedTransformation *attachment=NULLPTR) + : m_groupSize(0), m_counter(0) + { + Detach(attachment); + IsolatedInitialize(MakeParameters(Name::GroupSize(), groupSize) + (Name::Separator(), ConstByteArrayParameter(separator)) + (Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + +private: + SecByteBlock m_separator, m_terminator; + size_t m_groupSize, m_counter; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/bench.h b/include/cryptlib/bench.h new file mode 100644 index 0000000..753d9b5 --- /dev/null +++ b/include/cryptlib/bench.h @@ -0,0 +1,57 @@ +// bench.h - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#ifndef CRYPTOPP_BENCH_H +#define CRYPTOPP_BENCH_H + +#include "cryptlib.h" + +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +// More granular control over benchmarks +enum TestClass { + UnkeyedRNG=(1<<0),UnkeyedHash=(1<<1),UnkeyedOther=(1<<2), + SharedKeyMAC=(1<<3),SharedKeyStream=(1<<4),SharedKeyBlock=(1<<5),SharedKeyOther=(1<<6), + PublicKeyAgreement=(1<<7),PublicKeyEncryption=(1<<8),PublicKeySignature=(1<<9),PublicKeyOther=(1<<10), + Unkeyed=UnkeyedRNG|UnkeyedHash|UnkeyedOther, + SharedKey=SharedKeyMAC|SharedKeyStream|SharedKeyBlock|SharedKeyOther, + PublicKey=PublicKeyAgreement|PublicKeyEncryption|PublicKeySignature|PublicKeyOther, + All=Unkeyed|SharedKey|PublicKey, + TestFirst=(0), TestLast=(1<<11) +}; + +extern const double CLOCK_TICKS_PER_SECOND; +extern double g_allocatedTime; +extern double g_hertz; +extern double g_logTotal; +extern unsigned int g_logCount; +extern const byte defaultKey[]; + +// Test book keeping +extern time_t g_testBegin; +extern time_t g_testEnd; + +// Command handler +void BenchmarkWithCommand(int argc, const char* const argv[]); +// Top level, prints preamble and postamble +void Benchmark(Test::TestClass suites, double t, double hertz); +// Unkeyed systems +void Benchmark1(double t, double hertz); +// Shared key systems +void Benchmark2(double t, double hertz); +// Public key systems +void Benchmark3(double t, double hertz); + +void OutputResultBytes(const char *name, double length, double timeTaken); +void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken); + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +#endif diff --git a/include/cryptlib/blake2.h b/include/cryptlib/blake2.h new file mode 100644 index 0000000..cec1952 --- /dev/null +++ b/include/cryptlib/blake2.h @@ -0,0 +1,309 @@ +// blake2.h - written and placed in the public domain by Jeffrey Walton and Zooko +// Wilcox-O'Hearn. Based on Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +// reference BLAKE2 implementation at http://github.com/BLAKE2/BLAKE2. + +/// \file blake2.h +/// \brief Classes for BLAKE2b and BLAKE2s message digests and keyed message digests +/// \details This implementation follows Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// Static algorithm name return either "BLAKE2b" or "BLAKE2s". An object algorithm name follows +/// the naming described in RFC 7693, The +/// BLAKE2 Cryptographic Hash and Message Authentication Code (MAC). +/// \details The library provides specialized SSE2, SSE4 and NEON version of the BLAKE2 compression +/// function. For best results under ARM NEON, specify both an architecture and cpu. For example: +///
CXXFLAGS="-DNDEBUG -march=armv8-a+crc -mcpu=cortex-a53 ..."
+/// \since Crypto++ 5.6.4 + +#ifndef CRYPTOPP_BLAKE2_H +#define CRYPTOPP_BLAKE2_H + +#include "cryptlib.h" +#include "secblock.h" +#include "seckey.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief BLAKE2 hash information +/// \tparam T_64bit flag indicating 64-bit +/// \since Crypto++ 5.6.4 +template +struct BLAKE2_Info : public VariableKeyLength<(T_64bit ? 64 : 32),0,(T_64bit ? 64 : 32),1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + typedef VariableKeyLength<(T_64bit ? 64 : 32),0,(T_64bit ? 64 : 32),1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase; + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH) + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH) + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH) + + CRYPTOPP_CONSTANT(BLOCKSIZE = (T_64bit ? 128 : 64)) + CRYPTOPP_CONSTANT(DIGESTSIZE = (T_64bit ? 64 : 32)) + CRYPTOPP_CONSTANT(SALTSIZE = (T_64bit ? 16 : 8)) + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = (T_64bit ? 16 : 8)) + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return (T_64bit ? "BLAKE2b" : "BLAKE2s");} +}; + +/// \brief BLAKE2 parameter block +/// \tparam T_64bit flag indicating 64-bit +/// \details BLAKE2b uses BLAKE2_ParameterBlock, while BLAKE2s +/// uses BLAKE2_ParameterBlock. +/// \since Crypto++ 5.6.4 +template +struct CRYPTOPP_NO_VTABLE BLAKE2_ParameterBlock +{ +}; + +/// \brief BLAKE2b parameter block specialization +template<> +struct CRYPTOPP_NO_VTABLE BLAKE2_ParameterBlock +{ + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2_Info::SALTSIZE) + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2_Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2_Info::PERSONALIZATIONSIZE) + + BLAKE2_ParameterBlock() + { + memset(this, 0x00, sizeof(*this)); + digestLength = DIGESTSIZE; + fanout = depth = 1; + } + + BLAKE2_ParameterBlock(size_t digestSize) + { + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + memset(this, 0x00, sizeof(*this)); + digestLength = (byte)digestSize; + fanout = depth = 1; + } + + BLAKE2_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength); + + byte digestLength; + byte keyLength, fanout, depth; + byte leafLength[4]; + byte nodeOffset[8]; + byte nodeDepth, innerLength, rfu[14]; + byte salt[SALTSIZE]; + byte personalization[PERSONALIZATIONSIZE]; +}; + +/// \brief BLAKE2s parameter block specialization +template<> +struct CRYPTOPP_NO_VTABLE BLAKE2_ParameterBlock +{ + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2_Info::SALTSIZE) + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2_Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2_Info::PERSONALIZATIONSIZE) + + BLAKE2_ParameterBlock() + { + memset(this, 0x00, sizeof(*this)); + digestLength = DIGESTSIZE; + fanout = depth = 1; + } + + BLAKE2_ParameterBlock(size_t digestSize) + { + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + memset(this, 0x00, sizeof(*this)); + digestLength = (byte)digestSize; + fanout = depth = 1; + } + + BLAKE2_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength); + + byte digestLength; + byte keyLength, fanout, depth; + byte leafLength[4]; + byte nodeOffset[6]; + byte nodeDepth, innerLength; + byte salt[SALTSIZE]; + byte personalization[PERSONALIZATIONSIZE]; +}; + +/// \brief BLAKE2 state information +/// \tparam W word type +/// \tparam T_64bit flag indicating 64-bit +/// \details BLAKE2b uses BLAKE2_State, while BLAKE2s +/// uses BLAKE2_State. +/// \since Crypto++ 5.6.4 +template +struct CRYPTOPP_NO_VTABLE BLAKE2_State +{ + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2_Info::BLOCKSIZE) + + BLAKE2_State() + { + // Set all members except scratch buffer[] + h[0]=h[1]=h[2]=h[3]=h[4]=h[5]=h[6]=h[7] = 0; + t[0]=t[1]=f[0]=f[1] = 0; + length = 0; + } + + // SSE2, SSE4 and NEON depend upon t[] and f[] being side-by-side + W h[8], t[2], f[2]; + byte buffer[BLOCKSIZE]; + size_t length; +}; + +/// \brief BLAKE2 hash implementation +/// \tparam W word type +/// \tparam T_64bit flag indicating 64-bit +/// \details BLAKE2b uses BLAKE2_Base, while BLAKE2s +/// uses BLAKE2_Base. +/// \since Crypto++ 5.6.4 +template +class BLAKE2_Base : public SimpleKeyingInterfaceImpl > +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2_Info::DEFAULT_KEYLENGTH) + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2_Info::MIN_KEYLENGTH) + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2_Info::MAX_KEYLENGTH) + + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2_Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2_Info::BLOCKSIZE) + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2_Info::SALTSIZE) + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2_Info::PERSONALIZATIONSIZE) + + typedef BLAKE2_State State; + typedef BLAKE2_ParameterBlock ParameterBlock; + typedef SecBlock > AlignedState; + typedef SecBlock > AlignedParameterBlock; + + virtual ~BLAKE2_Base() {} + + /// \brief Retrieve the static algorithm name + /// \returns the algorithm name (BLAKE2s or BLAKE2b) + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return BLAKE2_Info::StaticAlgorithmName();} + + /// \brief Retrieve the object's name + /// \returns the object's algorithm name following RFC 7693 + /// \details Object algorithm name follows the naming described in + /// RFC 7693, The BLAKE2 Cryptographic Hash and + /// Message Authentication Code (MAC). For example, "BLAKE2b-512" and "BLAKE2s-256". + std::string AlgorithmName() const {return std::string(StaticAlgorithmName()) + "-" + IntToString(this->DigestSize()*8);} + + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return (CRYPTOPP_BOOL_ALIGN16 ? 16 : GetAlignmentOf());} + + void Update(const byte *input, size_t length); + void Restart(); + + /// \brief Restart a hash with parameter block and counter + /// \param block parameter block + /// \param counter counter array + /// \details Parameter block is persisted across calls to Restart(). + void Restart(const BLAKE2_ParameterBlock& block, const W counter[2]); + + /// \brief Set tree mode + /// \param mode the new tree mode + /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1]. + /// If treeMode=false (default), then State::f[1] is never set. If + /// treeMode=true, then State::f[1] is set when State::f[0] is set. + /// Tree mode is persisted across calls to Restart(). + void SetTreeMode(bool mode) {m_treeMode=mode;} + + /// \brief Get tree mode + /// \returns the current tree mode + /// \details Tree mode is persisted across calls to Restart(). + bool GetTreeMode() const {return m_treeMode;} + + void TruncatedFinal(byte *hash, size_t size); + +protected: + BLAKE2_Base(); + BLAKE2_Base(bool treeMode, unsigned int digestSize); + BLAKE2_Base(const byte *key, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength, + bool treeMode, unsigned int digestSize); + + // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's. + void Compress(const byte *input); + inline void IncrementCounter(size_t count=BLOCKSIZE); + + void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params); + +private: + AlignedState m_state; + AlignedParameterBlock m_block; + AlignedSecByteBlock m_key; + word32 m_digestSize; + bool m_treeMode; +}; + +/// \brief The BLAKE2b cryptographic hash function +/// \details BLAKE2b can function as both a hash and keyed hash. If you want only the hash, +/// then use the BLAKE2b constructor that accepts no parameters or digest size. If you +/// want a keyed hash, then use the constructor that accpts the key as a parameter. +/// Once a key and digest size are selected, its effectively immutable. The Restart() +/// method that accepts a ParameterBlock does not allow you to change it. +/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// \since Crypto++ 5.6.4 +class BLAKE2b : public BLAKE2_Base +{ +public: + typedef BLAKE2_Base ThisBase; // Early Visual Studio workaround + typedef BLAKE2_ParameterBlock ParameterBlock; + CRYPTOPP_COMPILE_ASSERT(sizeof(ParameterBlock) == 64); + + /// \brief Construct a BLAKE2b hash + /// \param digestSize the digest size, in bytes + /// \param treeMode flag indicating tree mode + BLAKE2b(bool treeMode=false, unsigned int digestSize = DIGESTSIZE) : ThisBase(treeMode, digestSize) {} + + /// \brief Construct a BLAKE2b hash + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array + /// \param salt a byte array used as salt + /// \param saltLength the size of the byte array + /// \param personalization a byte array used as prsonalization string + /// \param personalizationLength the size of the byte array + /// \param treeMode flag indicating tree mode + /// \param digestSize the digest size, in bytes + BLAKE2b(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0, + const byte* personalization = NULLPTR, size_t personalizationLength = 0, + bool treeMode=false, unsigned int digestSize = DIGESTSIZE) + : ThisBase(key, keyLength, salt, saltLength, personalization, personalizationLength, treeMode, digestSize) {} +}; + +/// \brief The BLAKE2s cryptographic hash function +/// \details BLAKE2s can function as both a hash and keyed hash. If you want only the hash, +/// then use the BLAKE2s constructor that accepts no parameters or digest size. If you +/// want a keyed hash, then use the constructor that accpts the key as a parameter. +/// Once a key and digest size are selected, its effectively immutable. The Restart() +/// method that accepts a ParameterBlock does not allow you to change it. +/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// \since Crypto++ 5.6.4 +class BLAKE2s : public BLAKE2_Base +{ +public: + typedef BLAKE2_Base ThisBase; // Early Visual Studio workaround + typedef BLAKE2_ParameterBlock ParameterBlock; + CRYPTOPP_COMPILE_ASSERT(sizeof(ParameterBlock) == 32); + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \param treeMode flag indicating tree mode + BLAKE2s(bool treeMode=false, unsigned int digestSize = DIGESTSIZE) : ThisBase(treeMode, digestSize) {} + + /// \brief Construct a BLAKE2s hash + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array + /// \param salt a byte array used as salt + /// \param saltLength the size of the byte array + /// \param personalization a byte array used as prsonalization string + /// \param personalizationLength the size of the byte array + /// \param treeMode flag indicating tree mode + /// \param digestSize the digest size, in bytes + BLAKE2s(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0, + const byte* personalization = NULLPTR, size_t personalizationLength = 0, + bool treeMode=false, unsigned int digestSize = DIGESTSIZE) + : ThisBase(key, keyLength, salt, saltLength, personalization, personalizationLength, treeMode, digestSize) {} +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/blowfish.h b/include/cryptlib/blowfish.h new file mode 100644 index 0000000..8032491 --- /dev/null +++ b/include/cryptlib/blowfish.h @@ -0,0 +1,54 @@ +// blowfish.h - originally written and placed in the public domain by Wei Dai + +/// \file blowfish.h +/// \brief Classes for the Blowfish block cipher + +#ifndef CRYPTOPP_BLOWFISH_H +#define CRYPTOPP_BLOWFISH_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Blowfish block cipher information +struct Blowfish_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 4, 56>, public FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Blowfish";} +}; + +// Blowfish + +/// \brief Blowfish block cipher +/// \since Crypto++ 1.0 +class Blowfish : public Blowfish_Info, public BlockCipherDocumentation +{ + /// \brief Class specific implementation and overrides used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void UncheckedSetKey(const byte *key_string, unsigned int keylength, const NameValuePairs ¶ms); + + private: + void crypt_block(const word32 in[2], word32 out[2]) const; + + static const word32 p_init[ROUNDS+2]; + static const word32 s_init[4*256]; + + FixedSizeSecBlock pbox; + FixedSizeSecBlock sbox; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Blowfish::Encryption BlowfishEncryption; +typedef Blowfish::Decryption BlowfishDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/blumshub.h b/include/cryptlib/blumshub.h new file mode 100644 index 0000000..2c5b6d5 --- /dev/null +++ b/include/cryptlib/blumshub.h @@ -0,0 +1,58 @@ +// blumshub.h - originally written and placed in the public domain by Wei Dai + +/// \file blumshub.h +/// \brief Classes for Blum Blum Shub generator + +#ifndef CRYPTOPP_BLUMSHUB_H +#define CRYPTOPP_BLUMSHUB_H + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// BlumBlumShub without factorization of the modulus +class PublicBlumBlumShub : public RandomNumberGenerator, + public StreamTransformation +{ +public: + virtual ~PublicBlumBlumShub() {} + + PublicBlumBlumShub(const Integer &n, const Integer &seed); + + unsigned int GenerateBit(); + byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); + void ProcessData(byte *outString, const byte *inString, size_t length); + + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + +protected: + ModularArithmetic modn; + Integer current; + word maxBits, bitsLeft; +}; + +/// BlumBlumShub with factorization of the modulus +class BlumBlumShub : public PublicBlumBlumShub +{ +public: + virtual ~BlumBlumShub() {} + + // Make sure p and q are both primes congruent to 3 mod 4 and at least 512 bits long, + // seed is the secret key and should be about as big as p*q + BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed); + + bool IsRandomAccess() const {return true;} + void Seek(lword index); + +protected: + const Integer p, q; + const Integer x0; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/camellia.h b/include/cryptlib/camellia.h new file mode 100644 index 0000000..2d551dc --- /dev/null +++ b/include/cryptlib/camellia.h @@ -0,0 +1,49 @@ +// camellia.h - originally written and placed in the public domain by Wei Dai + +/// \file camellia.h +/// \brief Classes for the Camellia block cipher + +#ifndef CRYPTOPP_CAMELLIA_H +#define CRYPTOPP_CAMELLIA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Camellia block cipher information +struct Camellia_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Camellia";} +}; + +/// \brief Camellia block cipher +/// \sa Camellia +class Camellia : public Camellia_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + CRYPTOPP_ALIGN_DATA(4) static const byte s1[256]; + static const word32 SP[4][256]; + + unsigned int m_rounds; + SecBlock m_key; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Camellia::Encryption CamelliaEncryption; +typedef Camellia::Decryption CamelliaDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/cast.h b/include/cryptlib/cast.h new file mode 100644 index 0000000..424cf62 --- /dev/null +++ b/include/cryptlib/cast.h @@ -0,0 +1,109 @@ +// cast.h - originally written and placed in the public domain by Wei Dai + +/// \file cast.h +/// \brief Classes for the CAST-128 and CAST-256 block ciphers +/// \since Crypto++ 2.2 + +#ifndef CRYPTOPP_CAST_H +#define CRYPTOPP_CAST_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CAST block cipher base +/// \since Crypto++ 2.2 +class CAST +{ +protected: + static const word32 S[8][256]; +}; + +/// \brief CAST128 block cipher information +/// \since Crypto++ 2.2 +struct CAST128_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 5, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-128";} +}; + +/// \brief CAST128 block cipher +/// \sa CAST-128 +/// \since Crypto++ 2.2 +class CAST128 : public CAST128_Info, public BlockCipherDocumentation +{ + /// \brief CAST128 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + bool reduced; + FixedSizeSecBlock K; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief CAST128 block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief CAST128 block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief CAST256 block cipher information +/// \since Crypto++ 4.0 +struct CAST256_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 4> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-256";} +}; + +/// \brief CAST256 block cipher +/// \sa CAST-256 +/// \since Crypto++ 4.0 +class CAST256 : public CAST256_Info, public BlockCipherDocumentation +{ + /// \brief CAST256 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + static const word32 t_m[8][24]; + static const unsigned int t_r[8][24]; + + static void Omega(int i, word32 kappa[8]); + + FixedSizeSecBlock K; + mutable FixedSizeSecBlock kappa; + mutable FixedSizeSecBlock m_t; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef CAST128::Encryption CAST128Encryption; +typedef CAST128::Decryption CAST128Decryption; + +typedef CAST256::Encryption CAST256Encryption; +typedef CAST256::Decryption CAST256Decryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/cbcmac.h b/include/cryptlib/cbcmac.h new file mode 100644 index 0000000..3ad6e8b --- /dev/null +++ b/include/cryptlib/cbcmac.h @@ -0,0 +1,59 @@ +// cbcmac.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for CBC MAC +/// \since Crypto++ 3.1 + +#ifndef CRYPTOPP_CBCMAC_H +#define CRYPTOPP_CBCMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CBC-MAC base class +/// \since Crypto++ 3.1 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_MAC_Base : public MessageAuthenticationCode +{ +public: + CBC_MAC_Base() : m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return const_cast(this)->AccessCipher().BlockSize();} + +protected: + virtual BlockCipher & AccessCipher() =0; + +private: + void ProcessBuf(); + SecByteBlock m_reg; + unsigned int m_counter; +}; + +/// \brief CBC-MAC +/// \tparam T BlockCipherDocumentation derived class +/// \details CBC-MAC is compatible with FIPS 113. The MAC is secure only for fixed +/// length messages. For variable length messages use CMAC or DMAC. +/// \sa CBC-MAC +/// \since Crypto++ 3.1 +template +class CBC_MAC : public MessageAuthenticationCodeImpl >, public SameKeyLengthAs +{ +public: + CBC_MAC() {} + CBC_MAC(const byte *key, size_t length=SameKeyLengthAs::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("CBC-MAC(") + T::StaticAlgorithmName() + ")";} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + typename T::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/ccm.h b/include/cryptlib/ccm.h new file mode 100644 index 0000000..d2ef892 --- /dev/null +++ b/include/cryptlib/ccm.h @@ -0,0 +1,121 @@ +// ccm.h - originally written and placed in the public domain by Wei Dai + +/// \file ccm.h +/// \brief CCM block cipher mode of operation +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_CCM_H +#define CRYPTOPP_CCM_H + +#include "authenc.h" +#include "modes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CCM block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CCM_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CCM_Base() + : m_digestSize(0), m_L(0), m_messageLength(0), m_aadLength(0) {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + std::string("/CCM");} + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength();} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength();} + size_t GetValidKeyLength(size_t keylength) const + {return GetBlockCipher().GetValidKeyLength(keylength);} + bool IsValidKeyLength(size_t keylength) const + {return GetBlockCipher().IsValidKeyLength(keylength);} + unsigned int OptimalDataAlignment() const + {return GetBlockCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 8;} + unsigned int MinIVLength() const + {return 7;} + unsigned int MaxIVLength() const + {return 13;} + unsigned int DigestSize() const + {return m_digestSize;} + lword MaxHeaderLength() const + {return W64LIT(0)-1;} + lword MaxMessageLength() const + {return m_L<8 ? (W64LIT(1)<<(8*m_L))-1 : W64LIT(0)-1;} + bool NeedsPrespecifiedDataLengths() const + {return true;} + void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return true;} + unsigned int AuthenticationBlockSize() const + {return GetBlockCipher().BlockSize();} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + + virtual BlockCipher & AccessBlockCipher() =0; + virtual int DefaultDigestSize() const =0; + + const BlockCipher & GetBlockCipher() const {return const_cast(this)->AccessBlockCipher();}; + byte *CBC_Buffer() {return m_buffer+REQUIRED_BLOCKSIZE;} + + enum {REQUIRED_BLOCKSIZE = 16}; + int m_digestSize, m_L; + word64 m_messageLength, m_aadLength; + CTR_Mode_ExternalCipher::Encryption m_ctr; +}; + +/// \brief CCM block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_DefaultDigestSize default digest size, in bytes +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class CCM_Final : public CCM_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/CCM");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + BlockCipher & AccessBlockCipher() {return m_cipher;} + int DefaultDigestSize() const {return T_DefaultDigestSize;} + typename T_BlockCipher::Encryption m_cipher; +}; + +/// \brief CCM block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \tparam T_DefaultDigestSize default digest size, in bytes +/// \details \p CCM provides the \p Encryption and \p Decryption typedef. See GCM_Base +/// and GCM_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa CCM Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct CCM : public AuthenticatedSymmetricCipherDocumentation +{ + typedef CCM_Final Encryption; + typedef CCM_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/chacha.h b/include/cryptlib/chacha.h new file mode 100644 index 0000000..fbbd1de --- /dev/null +++ b/include/cryptlib/chacha.h @@ -0,0 +1,85 @@ +// chacha.h - written and placed in the public domain by Jeffrey Walton. +// Based on Wei Dai's Salsa20 and Bernstein's reference ChaCha +// family implementation at http://cr.yp.to/chacha.html. + +/// \file chacha.h +/// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers +/// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from ChaCha, +/// a variant of Salsa20 (2008.01.28). Bernstein's implementation is _slightly_ different from the TLS working group's +/// implementation for cipher suites TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \since Crypto++ 5.6.4 + +#ifndef CRYPTOPP_CHACHA_H +#define CRYPTOPP_CHACHA_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ChaCha stream cipher information +/// \since Crypto++ 5.6.4 +template +struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8>, public FixedRounds +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { + return (R==8?"ChaCha8":(R==12?"ChaCha12":(R==20?"ChaCha20":"ChaCha"))); + } +}; + +/// \brief ChaCha stream cipher implementation +/// \since Crypto++ 5.6.4 +template +class CRYPTOPP_NO_VTABLE ChaCha_Policy : public AdditiveCipherConcretePolicy +{ +protected: + CRYPTOPP_CONSTANT(ROUNDS=FixedRounds::ROUNDS) + + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return false;} // TODO + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + FixedSizeAlignedSecBlock m_state; +}; + +/// \brief ChaCha8 stream cipher +/// \sa ChaCha, a variant of Salsa20 (2008.01.28). +/// \since Crypto++ 5.6.4 +struct ChaCha8 : public ChaCha_Info<8>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, ChaCha_Info<8> > Encryption; + typedef Encryption Decryption; +}; + +/// \brief ChaCha12 stream cipher +/// \details Bernstein and ECRYPT's ChaCha is _slightly_ different from the TLS working group's implementation for +/// cipher suites TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \sa ChaCha, a variant of Salsa20 (2008.01.28). +/// \since Crypto++ 5.6.4 +struct ChaCha12 : public ChaCha_Info<12>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, ChaCha_Info<12> > Encryption; + typedef Encryption Decryption; +}; + +/// \brief ChaCha20 stream cipher +/// \sa ChaCha, a variant of Salsa20 (2008.01.28). +/// \details Bernstein and ECRYPT's ChaCha is _slightly_ different from the TLS working group's implementation for +/// cipher suites TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \since Crypto++ 5.6.4 +struct ChaCha20 : public ChaCha_Info<20>, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, ChaCha_Info<20> > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_CHACHA_H diff --git a/include/cryptlib/channels.h b/include/cryptlib/channels.h new file mode 100644 index 0000000..d7aecd2 --- /dev/null +++ b/include/cryptlib/channels.h @@ -0,0 +1,142 @@ +// channels.h - originally written and placed in the public domain by Wei Dai + +/// \file channels.h +/// \brief Classes for multiple named channels + +#ifndef CRYPTOPP_CHANNELS_H +#define CRYPTOPP_CHANNELS_H + +#include "cryptlib.h" +#include "simple.h" +#include "smartptr.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if 0 +/// Route input on default channel to different and/or multiple channels based on message sequence number +class MessageSwitch : public Sink +{ +public: + void AddDefaultRoute(BufferedTransformation &destination, const std::string &channel); + void AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel); + + void Put(byte inByte); + void Put(const byte *inString, unsigned int length); + + void Flush(bool completeFlush, int propagation=-1); + void MessageEnd(int propagation=-1); + void PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1); + void MessageSeriesEnd(int propagation=-1); + +private: + typedef std::pair Route; + struct RangeRoute + { + RangeRoute(unsigned int begin, unsigned int end, const Route &route) + : begin(begin), end(end), route(route) {} + bool operator<(const RangeRoute &rhs) const {return begin < rhs.begin;} + unsigned int begin, end; + Route route; + }; + + typedef std::list RouteList; + typedef std::list DefaultRouteList; + + RouteList m_routes; + DefaultRouteList m_defaultRoutes; + unsigned int m_nCurrentMessage; +}; +#endif + +class ChannelSwitchTypedefs +{ +public: + typedef std::pair Route; + typedef std::multimap RouteMap; + + typedef std::pair > DefaultRoute; + typedef std::list DefaultRouteList; + + // SunCC workaround: can't use const_iterator here + typedef RouteMap::iterator MapIterator; + typedef DefaultRouteList::iterator ListIterator; +}; + +class ChannelSwitch; + +class ChannelRouteIterator : public ChannelSwitchTypedefs +{ +public: + ChannelRouteIterator(ChannelSwitch &cs) : m_cs(cs), m_useDefault(false) {} + + void Reset(const std::string &channel); + bool End() const; + void Next(); + BufferedTransformation & Destination(); + const std::string & Channel(); + + ChannelSwitch& m_cs; + std::string m_channel; + bool m_useDefault; + MapIterator m_itMapCurrent, m_itMapEnd; + ListIterator m_itListCurrent, m_itListEnd; + +protected: + // Hide this to see if we break something... + ChannelRouteIterator(); +}; + +/// Route input to different and/or multiple channels based on channel ID +class CRYPTOPP_DLL ChannelSwitch : public Multichannel, public ChannelSwitchTypedefs +{ +public: + ChannelSwitch() : m_it(*this), m_blocked(false) {} + ChannelSwitch(BufferedTransformation &destination) : m_it(*this), m_blocked(false) + { + AddDefaultRoute(destination); + } + ChannelSwitch(BufferedTransformation &destination, const std::string &outChannel) : m_it(*this), m_blocked(false) + { + AddDefaultRoute(destination, outChannel); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking); + + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + + void AddDefaultRoute(BufferedTransformation &destination); + void RemoveDefaultRoute(BufferedTransformation &destination); + void AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + void RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + +private: + RouteMap m_routeMap; + DefaultRouteList m_defaultRoutes; + + ChannelRouteIterator m_it; + bool m_blocked; + + friend class ChannelRouteIterator; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/cmac.h b/include/cryptlib/cmac.h new file mode 100644 index 0000000..1c69c29 --- /dev/null +++ b/include/cryptlib/cmac.h @@ -0,0 +1,66 @@ +// cmac.h - originally written and placed in the public domain by Wei Dai + +/// \file cmac.h +/// \brief Classes for CMAC message authentication code +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_CMAC_H +#define CRYPTOPP_CMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CMAC base implementation +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CMAC_Base : public MessageAuthenticationCode +{ +public: + CMAC_Base() : m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return GetCipher().BlockSize();} + unsigned int OptimalBlockSize() const {return GetCipher().BlockSize();} + unsigned int OptimalDataAlignment() const {return GetCipher().OptimalDataAlignment();} + +protected: + friend class EAX_Base; + + const BlockCipher & GetCipher() const {return const_cast(this)->AccessCipher();} + virtual BlockCipher & AccessCipher() =0; + + void ProcessBuf(); + SecByteBlock m_reg; + unsigned int m_counter; +}; + +/// \brief CMAC message authentication code +/// \tparam T block cipher +/// \details Template parameter T should be a class derived from BlockCipherDocumentation, for example AES, with a block size of 8, 16, or 32. +/// \sa CMAC +/// \since Crypto++ 5.6.0 +template +class CMAC : public MessageAuthenticationCodeImpl >, public SameKeyLengthAs +{ +public: + /// \brief Construct a CMAC + CMAC() {} + /// \brief Construct a CMAC + /// \param key the MAC key + /// \param length the key size, in bytes + CMAC(const byte *key, size_t length=SameKeyLengthAs::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("CMAC(") + T::StaticAlgorithmName() + ")";} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + typename T::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/config.h b/include/cryptlib/config.h new file mode 100644 index 0000000..bdd73e1 --- /dev/null +++ b/include/cryptlib/config.h @@ -0,0 +1,1172 @@ +// config.h - originally written and placed in the public domain by Wei Dai + +/// \file config.h +/// \brief Library configuration file + +#ifndef CRYPTOPP_CONFIG_H +#define CRYPTOPP_CONFIG_H + +// ***************** Important Settings ******************** + +// define this if running on a big-endian CPU +#if !defined(CRYPTOPP_LITTLE_ENDIAN) && !defined(CRYPTOPP_BIG_ENDIAN) && (defined(__BIG_ENDIAN__) || (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || (defined(__m68k__) || defined(__MC68K__)) || defined(__sparc) || defined(__sparc__) || defined(__hppa__) || defined(__MIPSEB__) || defined(__ARMEB__) || (defined(__MWERKS__) && !defined(__INTEL__))) +# define CRYPTOPP_BIG_ENDIAN 1 +#endif + +// define this if running on a little-endian CPU +// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not defined +#if !defined(CRYPTOPP_BIG_ENDIAN) && !defined(CRYPTOPP_LITTLE_ENDIAN) +# define CRYPTOPP_LITTLE_ENDIAN 1 +#endif + +// Sanity checks. Some processors have more than big, little and bi-endian modes. PDP mode, where order results in "4312", should +// raise red flags immediately. Additionally, mis-classified machines, like (previosuly) S/390, should raise red flags immediately. +#if defined(CRYPTOPP_BIG_ENDIAN) && defined(__GNUC__) && defined(__BYTE_ORDER__) && (__BYTE_ORDER__ != __ORDER_BIG_ENDIAN__) +# error "CRYPTOPP_BIG_ENDIAN is set, but __BYTE_ORDER__ is not __ORDER_BIG_ENDIAN__" +#endif +#if defined(CRYPTOPP_LITTLE_ENDIAN) && defined(__GNUC__) && defined(__BYTE_ORDER__) && (__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__) +# error "CRYPTOPP_LITTLE_ENDIAN is set, but __BYTE_ORDER__ is not __ORDER_LITTLE_ENDIAN__" +#endif + +// Define this if you want to disable all OS-dependent features, +// such as sockets and OS-provided random number generators +// #define NO_OS_DEPENDENCE + +// Define this to use features provided by Microsoft's CryptoAPI. +// Currently the only feature used is Windows random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +// #define USE_MS_CRYPTOAPI + +// Define this to use features provided by Microsoft's CryptoNG API. +// CryptoNG API is available in Vista and above and its cross platform, +// including desktop apps and store apps. Currently the only feature +// used is Windows random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +// #define USE_MS_CNGAPI + +// If the user did not make a choice, then select CryptoNG if +// targeting Windows 8 or above. +#if !defined(USE_MS_CRYPTOAPI) && !defined(USE_MS_CNGAPI) +# if !defined(_USING_V110_SDK71_) && ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)) +# define USE_MS_CNGAPI +# else +# define USE_MS_CRYPTOAPI +# endif +#endif + +// Define this to disable ASM, intrinsics and built-ins. The library will be +// compiled using C++ only. The library code will not include SSE2 (and +// above), NEON, Aarch32, Aarch64, Power4, Power7 or Power8. Note the compiler +// may use higher ISAs depending on compiler options, but the library will not +// explictly use the ISAs. +// #define CRYPTOPP_DISABLE_ASM 1 + +// Define CRYPTOPP_NO_CXX11 to avoid C++11 related features shown at the +// end of this file. Some compilers and standard C++ headers advertise C++11 +// but they are really just C++03 with some additional C++11 headers and +// non-conforming classes. You might also consider `-std=c++03` or +// `-std=gnu++03`, but they are required options when building the library +// and all programs. CRYPTOPP_NO_CXX11 is probably easier to manage but it may +// cause -Wterminate warnings under GCC. MSVC++ has a similar warning. +// Also see https://github.com/weidai11/cryptopp/issues/529 +// #define CRYPTOPP_NO_CXX11 1 + +// Define CRYPTOPP_NO_CXX17 to avoid C++17 related features shown at the end of +// this file. At the moment it should only affect std::uncaught_exceptions. +// #define CRYPTOPP_NO_CXX17 1 + +// Define this to allow unaligned data access. If you experience a break with +// GCC at -O3, you should immediately suspect unaligned data accesses. +// #define CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS 1 + +// ***************** Less Important Settings *************** + +// Library version macro. Since this macro is in a header, it reflects +// the version of the library the headers came from. It is not +// necessarily the version of the library built as a shared object if +// versions are inadvertently mixed and matched. +#define CRYPTOPP_VERSION 700 + +// Define this if you want to set a prefix for TestData/ and TestVectors/ +// Be mindful of the trailing slash since its simple concatenation. +// g++ ... -DCRYPTOPP_DATA_DIR='"/tmp/cryptopp_test/share/"' +#ifndef CRYPTOPP_DATA_DIR +# define CRYPTOPP_DATA_DIR "" +#endif + +// Define this if you want or need the library's memcpy_s and memmove_s. +// See http://github.com/weidai11/cryptopp/issues/28. +// #if !defined(CRYPTOPP_WANT_SECURE_LIB) +// # define CRYPTOPP_WANT_SECURE_LIB +// #endif + +// File system code to write to GZIP archive. +// http://www.gzip.org/format.txt +#if !defined(GZIP_OS_CODE) +# if defined(__macintosh__) +# define GZIP_OS_CODE 7 +# elif defined(__unix__) || defined(__linux__) +# define GZIP_OS_CODE 3 +# else +# define GZIP_OS_CODE 0 +# endif +#endif + +// Try this if your CPU has 256K internal cache or a slow multiply instruction +// and you want a (possibly) faster IDEA implementation using log tables +// #define IDEA_LARGECACHE + +// Define this if, for the linear congruential RNG, you want to use +// the original constants as specified in S.K. Park and K.W. Miller's +// CACM paper. +// #define LCRNG_ORIGINAL_NUMBERS + +// Define this if you want Integer's operator<< to honor std::showbase (and +// std::noshowbase). If defined, Integer will use a suffix of 'b', 'o', 'h' +// or '.' (the last for decimal) when std::showbase is in effect. If +// std::noshowbase is set, then the suffix is not added to the Integer. If +// not defined, existing behavior is preserved and Integer will use a suffix +// of 'b', 'o', 'h' or '.' (the last for decimal). +// #define CRYPTOPP_USE_STD_SHOWBASE + +// Define this if ARMv8 shifts are slow. ARM Cortex-A53 and Cortex-A57 shift +// operation perform poorly, so NEON and ASIMD code that relies on shifts +// or rotates often performs worse than C/C++ code. Also see +// http://github.com/weidai11/cryptopp/issues/367. +#define CRYPTOPP_SLOW_ARMV8_SHIFT 1 + +// Define this if you want to decouple AlgorithmParameters and Integer +// The decoupling should make it easier for the linker to remove Integer +// related code for those who do not need Integer, and avoid a potential +// race during AssignIntToInteger pointer initialization. Also +// see http://github.com/weidai11/cryptopp/issues/389. +// #define CRYPTOPP_NO_ASSIGN_TO_INTEGER + +// choose which style of sockets to wrap (mostly useful for MinGW which has both) +#if !defined(NO_BERKELEY_STYLE_SOCKETS) && !defined(PREFER_BERKELEY_STYLE_SOCKETS) +# define PREFER_BERKELEY_STYLE_SOCKETS +#endif + +// #if !defined(NO_WINDOWS_STYLE_SOCKETS) && !defined(PREFER_WINDOWS_STYLE_SOCKETS) +// # define PREFER_WINDOWS_STYLE_SOCKETS +// #endif + +// set the name of Rijndael cipher, was "Rijndael" before version 5.3 +#define CRYPTOPP_RIJNDAEL_NAME "AES" + +// CRYPTOPP_DEBUG enables the library's CRYPTOPP_ASSERT. CRYPTOPP_ASSERT +// raises a SIGTRAP (Unix) or calls DebugBreak() (Windows). CRYPTOPP_ASSERT +// is only in effect when CRYPTOPP_DEBUG, DEBUG or _DEBUG is defined. Unlike +// Posix assert, CRYPTOPP_ASSERT is not affected by NDEBUG (or failure to +// define it). +// Also see http://github.com/weidai11/cryptopp/issues/277, CVE-2016-7420 +#if (defined(DEBUG) || defined(_DEBUG)) && !defined(CRYPTOPP_DEBUG) +# define CRYPTOPP_DEBUG 1 +#endif + +// ***************** Important Settings Again ******************** +// But the defaults should be ok. + +// namespace support is now required +#ifdef NO_NAMESPACE +# error namespace support is now required +#endif + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +// Document the namespce exists. Put it here before CryptoPP is undefined below. +/// \namespace CryptoPP +/// \brief Crypto++ library namespace +/// \details Nearly all classes are located in the CryptoPP namespace. Within +/// the namespace, there are two additional namespaces. +///
    +///
  • Name - namespace for names used with \p NameValuePairs and documented in argnames.h +///
  • NaCl - namespace for NaCl library functions like crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open +///
  • Test - namespace for testing and benchmarks classes +///
  • Weak - namespace for weak and wounded algorithms, like ARC4, MD5 and Pananma +///
+namespace CryptoPP { } +// Bring in the symbols found in the weak namespace; and fold Weak1 into Weak +# define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +# define Weak1 Weak +// Avoid putting "CryptoPP::" in front of everything in Doxygen output +# define CryptoPP +# define NAMESPACE_BEGIN(x) +# define NAMESPACE_END +// Get Doxygen to generate better documentation for these typedefs +# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; +// Make "protected" "private" so the functions and members are not documented +# define protected private +#else +# define NAMESPACE_BEGIN(x) namespace x { +# define NAMESPACE_END } +# define DOCUMENTED_TYPEDEF(x, y) typedef x y; +#endif +#define ANONYMOUS_NAMESPACE_BEGIN namespace { +#define ANONYMOUS_NAMESPACE_END } +#define USING_NAMESPACE(x) using namespace x; +#define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x { +#define DOCUMENTED_NAMESPACE_END } + +// What is the type of the third parameter to bind? +// For Unix, the new standard is ::socklen_t (typically unsigned int), and the old standard is int. +// Unfortunately there is no way to tell whether or not socklen_t is defined. +// To work around this, TYPE_OF_SOCKLEN_T is a macro so that you can change it from the makefile. +#ifndef TYPE_OF_SOCKLEN_T +# if defined(_WIN32) || defined(__CYGWIN__) +# define TYPE_OF_SOCKLEN_T int +# else +# define TYPE_OF_SOCKLEN_T ::socklen_t +# endif +#endif + +#if defined(__CYGWIN__) && defined(PREFER_WINDOWS_STYLE_SOCKETS) +# define __USE_W32_SOCKETS +#endif + +// Originally in global namespace to avoid ambiguity with other byte typedefs. +// Moved to Crypto++ namespace due to C++17, std::byte and potential compile problems. Also see +// http://www.cryptopp.com/wiki/std::byte and http://github.com/weidai11/cryptopp/issues/442 +// typedef unsigned char byte; +#define CRYPTOPP_NO_GLOBAL_BYTE 1 + +NAMESPACE_BEGIN(CryptoPP) + +// Signed words added at Issue 609 for early versions of and Visual Studio and +// the NaCl gear. Also see https://github.com/weidai11/cryptopp/issues/609. + +typedef unsigned char byte; +typedef unsigned short word16; +typedef unsigned int word32; + +typedef signed char sbyte; +typedef signed short sword16; +typedef signed int sword32; + +#if defined(_MSC_VER) || defined(__BORLANDC__) + typedef signed __int64 sword64; + typedef unsigned __int64 word64; + #define SW64LIT(x) x##i64 + #define W64LIT(x) x##ui64 +#elif (_LP64 || __LP64__) + typedef signed long sword64; + typedef unsigned long word64; + #define SW64LIT(x) x##L + #define W64LIT(x) x##UL +#else + typedef signed long long sword64; + typedef unsigned long long word64; + #define SW64LIT(x) x##LL + #define W64LIT(x) x##ULL +#endif + +// define large word type, used for file offsets and such +typedef word64 lword; +const lword LWORD_MAX = W64LIT(0xffffffffffffffff); + +// Clang pretends to be VC++, too. +// See http://github.com/weidai11/cryptopp/issues/147 +#if defined(_MSC_VER) && defined(__clang__) +# error: "Unsupported configuration" +#endif + +#ifdef __GNUC__ + #define CRYPTOPP_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if defined(__xlc__) || defined(__xlC__) + #define CRYPTOPP_XLC_VERSION ((__xlC__ / 256) * 10000 + (__xlC__ % 256) * 100) +#endif + +// Apple and LLVM's Clang. Apple Clang version 7.0 roughly equals LLVM Clang version 3.7 +#if defined(__clang__) && defined(__apple_build_version__) + #define CRYPTOPP_APPLE_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) + #define CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER 1 +#elif defined(__clang__) + #define CRYPTOPP_LLVM_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) + #define CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER 1 +#endif + +#ifdef _MSC_VER + #define CRYPTOPP_MSC_VERSION (_MSC_VER) +#endif + +// Need GCC 4.6/Clang 1.7/Apple Clang 2.0 or above due to "GCC diagnostic {push|pop}" +#if (CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_LLVM_CLANG_VERSION >= 10700) || (CRYPTOPP_APPLE_CLANG_VERSION >= 20000) + #define CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE 1 +#endif + +// Clang due to "Inline assembly operands don't work with .intel_syntax", http://llvm.org/bugs/show_bug.cgi?id=24232. Still broke as of Clang 3.9. +// TODO: supply the upper version when LLVM fixes it. We set it to 20.0 for compilation purposes. +#if (defined(CRYPTOPP_LLVM_CLANG_VERSION) && (CRYPTOPP_LLVM_CLANG_VERSION <= 200000)) || \ + (defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION <= 200000)) || \ + defined(CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER) + #define CRYPTOPP_DISABLE_INTEL_ASM 1 +#endif + +// define hword, word, and dword. these are used for multiprecision integer arithmetic +// Intel compiler won't have _umul128 until version 10.0. See http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231625.aspx +#if (defined(_MSC_VER) && (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) && (defined(_M_X64) || defined(_M_IA64))) || (defined(__DECCXX) && defined(__alpha__)) || (defined(__INTEL_COMPILER) && defined(__x86_64__)) || (defined(__SUNPRO_CC) && defined(__x86_64__)) + typedef word32 hword; + typedef word64 word; +#else + #define CRYPTOPP_NATIVE_DWORD_AVAILABLE 1 + #if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || defined(__x86_64__) || defined(__mips64) || defined(__sparc64__) + #if ((CRYPTOPP_GCC_VERSION >= 30400) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) && (__SIZEOF_INT128__ >= 16) + // GCC 4.0.1 on MacOS X is missing __umodti3 and __udivti3 + // GCC 4.8.3 and bad uint128_t ops on PPC64/POWER7 (Issue 421) + // mode(TI) division broken on amd64 with GCC earlier than GCC 3.4 + typedef word32 hword; + typedef word64 word; + typedef __uint128_t dword; + typedef __uint128_t word128; + #define CRYPTOPP_WORD128_AVAILABLE 1 + #else + // if we're here, it means we're on a 64-bit CPU but we don't have a way to obtain 128-bit multiplication results + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #endif + #else + // being here means the native register size is probably 32 bits or less + #define CRYPTOPP_BOOL_SLOW_WORD64 1 + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #endif +#endif +#ifndef CRYPTOPP_BOOL_SLOW_WORD64 + #define CRYPTOPP_BOOL_SLOW_WORD64 0 +#endif + +const unsigned int WORD_SIZE = sizeof(word); +const unsigned int WORD_BITS = WORD_SIZE * 8; + +NAMESPACE_END + +#ifndef CRYPTOPP_L1_CACHE_LINE_SIZE + // This should be a lower bound on the L1 cache line size. It's used for defense against timing attacks. + // Also see http://stackoverflow.com/questions/794632/programmatically-get-the-cache-line-size. + #if defined(_M_X64) || defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) + #define CRYPTOPP_L1_CACHE_LINE_SIZE 64 + #else + // L1 cache line size is 32 on Pentium III and earlier + #define CRYPTOPP_L1_CACHE_LINE_SIZE 32 + #endif +#endif + +#ifndef CRYPTOPP_ALIGN_DATA + #if defined(_MSC_VER) + #define CRYPTOPP_ALIGN_DATA(x) __declspec(align(x)) + #elif defined(__GNUC__) + #define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x))) + #else + #define CRYPTOPP_ALIGN_DATA(x) + #endif +#endif + +// The section attribute attempts to initialize CPU flags to avoid Valgrind findings above -O1 +#if ((defined(__MACH__) && defined(__APPLE__)) && ((CRYPTOPP_LLVM_CLANG_VERSION >= 30600) || (CRYPTOPP_APPLE_CLANG_VERSION >= 70100) || (CRYPTOPP_GCC_VERSION >= 40300))) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("__DATA,__data"))) +#elif (defined(__ELF__) && (CRYPTOPP_GCC_VERSION >= 40300)) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon"))) +#else + #define CRYPTOPP_SECTION_INIT +#endif + +#if defined(_MSC_VER) || defined(__fastcall) + #define CRYPTOPP_FASTCALL __fastcall +#else + #define CRYPTOPP_FASTCALL +#endif + +#ifdef _MSC_VER +#define CRYPTOPP_NO_VTABLE __declspec(novtable) +#else +#define CRYPTOPP_NO_VTABLE +#endif + +#ifdef _MSC_VER + // 4127: conditional expression is constant + // 4231: nonstandard extension used : 'extern' before template explicit instantiation + // 4250: dominance + // 4251: member needs to have dll-interface + // 4275: base needs to have dll-interface + // 4505: unreferenced local function + // 4512: assignment operator not generated + // 4660: explicitly instantiating a class that's already implicitly instantiated + // 4661: no suitable definition provided for explicit template instantiation request + // 4786: identifier was truncated in debug information + // 4355: 'this' : used in base member initializer list + // 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation +# pragma warning(disable: 4127 4512 4661 4910) + // Security related, possible defects + // http://blogs.msdn.com/b/vcblog/archive/2010/12/14/off-by-default-compiler-warnings-in-visual-c.aspx +# pragma warning(once: 4191 4242 4263 4264 4266 4302 4826 4905 4906 4928) +#endif + +#ifdef __BORLANDC__ +// 8037: non-const function called for const object. needed to work around BCB2006 bug +# pragma warn -8037 +#endif + +// [GCC Bug 53431] "C++ preprocessor ignores #pragma GCC diagnostic". Clang honors it. +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunknown-pragmas" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +// You may need to force include a C++ header on Android when using STLPort to ensure +// _STLPORT_VERSION is defined: CXXFLAGS="-DNDEBUG -g2 -O2 -std=c++11 -include iosfwd" +// TODO: Figure out C++17 and lack of std::uncaught_exception +#if (defined(_MSC_VER) && _MSC_VER <= 1300) || defined(__MWERKS__) || (defined(_STLPORT_VERSION) && ((_STLPORT_VERSION < 0x450) || defined(_STLP_NO_UNCAUGHT_EXCEPT_SUPPORT))) +#define CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION +#endif + +#ifndef CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION +#define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE +#endif + +// ***************** Platform and CPU features ******************** + +// Linux provides X32, which is 32-bit integers, longs and pointers on x86_64 using the full x86_64 register set. +// Detect via __ILP32__ (http://wiki.debian.org/X32Port). However, __ILP32__ shows up in more places than +// the System V ABI specs calls out, like on some Solaris installations and just about any 32-bit system with Clang. +#if (defined(__ILP32__) || defined(_ILP32)) && defined(__x86_64__) + #define CRYPTOPP_BOOL_X32 1 +#endif + +// see http://predef.sourceforge.net/prearch.html +#if (defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_X86_) || defined(__I86__) || defined(__INTEL__)) && !CRYPTOPP_BOOL_X32 + #define CRYPTOPP_BOOL_X86 1 +#endif + +#if (defined(_M_X64) || defined(__x86_64__)) && !CRYPTOPP_BOOL_X32 + #define CRYPTOPP_BOOL_X64 1 +#endif + +// Undo the ASM and Intrinsic related defines due to X32. +#if CRYPTOPP_BOOL_X32 +# undef CRYPTOPP_BOOL_X64 +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_X64_MASM_AVAILABLE +#endif + +// Microsoft plans to support ARM-64, but its not clear how to detect it. +// TODO: Add MSC_VER and ARM-64 platform define when available +#if defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) + #define CRYPTOPP_BOOL_ARM64 1 +#elif defined(__arm__) || defined(__aarch32__) || defined(_M_ARM) + #define CRYPTOPP_BOOL_ARM32 1 +#endif + +// AltiVec and Power8 crypto +#if defined(__powerpc64__) || defined(_ARCH_PPC64) + #define CRYPTOPP_BOOL_PPC64 1 +#elif defined(__powerpc__) || defined(_ARCH_PPC) + #define CRYPTOPP_BOOL_PPC32 1 +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) +# define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY 1 +#else +# define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY 1 +#endif + +// ***************** IA32 CPU features ******************** + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + +// Apple Clang prior to 5.0 cannot handle SSE2 +#if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 50000) +# define CRYPTOPP_DISABLE_ASM +#endif + +// Sun Studio 12 provides GCC inline assembly, http://blogs.oracle.com/x86be/entry/gcc_style_asm_inlining_support +// We can enable SSE2 for Sun Studio in the makefile with -D__SSE2__, but users may not compile with it. +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(__SSE2__) && defined(__x86_64__) && (__SUNPRO_CC >= 0x5100) +# define __SSE2__ 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_ASM) && ((defined(_MSC_VER) && defined(_M_IX86)) || (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))) + // C++Builder 2010 does not allow "call label" where label is defined within inline assembly + #define CRYPTOPP_X86_ASM_AVAILABLE 1 + + #if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__)) + #define CRYPTOPP_SSE2_ASM_AVAILABLE 1 + #endif + + #if !defined(CRYPTOPP_DISABLE_SSSE3) && (_MSC_VER >= 1500 || defined(__SSSE3__)) + #define CRYPTOPP_SSSE3_ASM_AVAILABLE 1 + #endif +#endif + +#if !defined(CRYPTOPP_DISABLE_ASM) && defined(_MSC_VER) && defined(_M_X64) + #define CRYPTOPP_X64_MASM_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_ASM) && defined(__GNUC__) && defined(__x86_64__) + #define CRYPTOPP_X64_ASM_AVAILABLE 1 +#endif + +// 32-bit SunCC does not enable SSE2 by default. +#if !defined(CRYPTOPP_DISABLE_ASM) && (defined(_MSC_VER) || defined(__SSE2__)) + #define CRYPTOPP_SSE2_INTRIN_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_SSSE3) +# if defined(__SSSE3__) || (_MSC_VER >= 1500) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) + #define CRYPTOPP_SSSE3_AVAILABLE 1 +# endif +#endif + +// Intrinsics availible in GCC 4.3 (http://gcc.gnu.org/gcc-4.3/changes.html) and +// MSVC 2008 (http://msdn.microsoft.com/en-us/library/bb892950%28v=vs.90%29.aspx) +// SunCC could generate SSE4 at 12.1, but the intrinsics are missing until 12.4. +#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \ + (defined(__SSE4_1__) || (CRYPTOPP_MSC_VERSION >= 1500) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)) + #define CRYPTOPP_SSE41_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \ + (defined(__SSE4_2__) || (CRYPTOPP_MSC_VERSION >= 1500) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)) + #define CRYPTOPP_SSE42_AVAILABLE 1 +#endif + +// Couple to CRYPTOPP_DISABLE_AES, but use CRYPTOPP_CLMUL_AVAILABLE so we can selectively +// disable for misbehaving platofrms and compilers, like Solaris or some Clang. +#if defined(CRYPTOPP_DISABLE_AES) + #define CRYPTOPP_DISABLE_CLMUL 1 +#endif + +// Requires Sun Studio 12.3 (SunCC 0x5120) in theory. +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_CLMUL) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__PCLMUL__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) + #define CRYPTOPP_CLMUL_AVAILABLE 1 +#endif + +// Requires Sun Studio 12.3 (SunCC 0x5120) +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_AES) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__AES__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) + #define CRYPTOPP_AESNI_AVAILABLE 1 +#endif + +// Guessing at SHA for SunCC. Its not in Sun Studio 12.6. Also see +// http://stackoverflow.com/questions/45872180/which-xarch-for-sha-extensions-on-solaris +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_SHA) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__SHA__) || (CRYPTOPP_MSC_VERSION >= 1900) || (__SUNPRO_CC >= 0x5160) || \ + (CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1300) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30400) || (CRYPTOPP_APPLE_CLANG_VERSION >= 50100)) + #define CRYPTOPP_SHANI_AVAILABLE 1 +#endif + +#endif // X86, X32, X64 + +// ***************** ARM CPU features ******************** + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64) + +// Requires ARMv7 and ACLE 1.0. Testing shows ARMv7 is really ARMv7a under most toolchains. +// Android still uses ARMv5 and ARMv6 so we have to be conservative when enabling NEON. +#if !defined(CRYPTOPP_ARM_NEON_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM) +# if defined(__ARM_NEON) || defined(__ARM_NEON_FP) || defined(__ARM_FEATURE_NEON) || \ + (__ARM_ARCH >= 7) || (CRYPTOPP_MSC_VERSION >= 1700) +# define CRYPTOPP_ARM_NEON_AVAILABLE 1 +# endif +#endif + +// ARMv8 and ASIMD, which is NEON. It is part of ARMv8 core. +// TODO: Add MSC_VER and ARM-64 platform define when available +#if !defined(CRYPTOPP_ARM_ASIMD_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM) +# if defined(__aarch32__) || defined(__aarch64__) || (CRYPTOPP_MSC_VERSION >= 1910) +# define CRYPTOPP_ARM_ASIMD_AVAILABLE 1 +# endif +#endif + +// Requires ARMv8 and ACLE 2.0. GCC requires 4.8 and above. +// LLVM Clang requires 3.5. Apple Clang is unknown at the moment. +// Microsoft plans to support ARM-64, but its not clear how to detect it. +// TODO: Add Android ARMv8 support for CRC32 +// TODO: Add MSC_VER and ARM-64 platform define when available +#if !defined(CRYPTOPP_ARM_CRC32_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM) && !defined(__apple_build_version__) && !defined(__ANDROID__) +# if (defined(__ARM_FEATURE_CRC32) || (CRYPTOPP_MSC_VERSION >= 1910) || \ + defined(__aarch32__) || defined(__aarch64__)) +# define CRYPTOPP_ARM_CRC32_AVAILABLE 1 +# endif +#endif + +// Requires ARMv8 and ACLE 2.0. GCC requires 4.8 and above. +// LLVM Clang requires 3.5. Apple Clang is unknown at the moment. +// Microsoft plans to support ARM-64, but its not clear how to detect it. +// TODO: Add Android ARMv8 support for PMULL +// TODO: Add MSC_VER and ARM-64 platform define when available +#if !defined(CRYPTOPP_ARM_PMULL_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM) && !defined(__apple_build_version__) && !defined(__ANDROID__) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_MSC_VERSION >= 1910) || \ + defined(__aarch32__) || defined(__aarch64__) +# define CRYPTOPP_ARM_PMULL_AVAILABLE 1 +# endif +#endif + +// Requires ARMv8 and ACLE 2.0. GCC requires 4.8 and above. +// LLVM Clang requires 3.5. Apple Clang is unknown at the moment. +// Microsoft plans to support ARM-64, but its not clear how to detect it. +// TODO: Add Android ARMv8 support for AES and SHA +// TODO: Add MSC_VER and ARM-64 platform define when available +#if !defined(CRYPTOPP_ARM_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM) && !defined(__ANDROID__) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_MSC_VERSION >= 1910) || \ + defined(__aarch32__) || defined(__aarch64__) +# define CRYPTOPP_ARM_AES_AVAILABLE 1 +# endif +#endif + +// Requires ARMv8 and ACLE 2.0. GCC requires 4.8 and above. +// LLVM Clang requires 3.5. Apple Clang is unknown at the moment. +// Microsoft plans to support ARM-64, but its not clear how to detect it. +// TODO: Add Android ARMv8 support for AES and SHA +// TODO: Add MSC_VER and ARM-64 platform define when available +#if !defined(CRYPTOPP_ARM_SHA_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM) && !defined(__ANDROID__) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_MSC_VERSION >= 1910) || \ + defined(__aarch32__) || defined(__aarch64__) +# define CRYPTOPP_ARM_SHA_AVAILABLE 1 +# endif +#endif + +// Limit the include. +#if defined(__aarch32__) || defined(__aarch64__) || (__ARM_ARCH >= 8) || defined(__ARM_ACLE) +# define CRYPTOPP_ARM_ACLE_AVAILABLE 1 +#endif + +// Man, this is borked. Apple Clang defines __ARM_ACLE but then fails +// to compile with "fatal error: 'arm_acle.h' file not found" +#if defined(__ANDROID__) || defined(ANDROID) || defined(__APPLE__) +# undef CRYPTOPP_ARM_ACLE_AVAILABLE +#endif + +#endif // ARM32, ARM64 + +// ***************** AltiVec and Power8 ******************** + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +#if defined(CRYPTOPP_DISABLE_ALTIVEC) || defined(CRYPTOPP_DISABLE_ASM) +# undef CRYPTOPP_DISABLE_ALTIVEC +# undef CRYPTOPP_DISABLE_POWER7 +# undef CRYPTOPP_DISABLE_POWER8 +# define CRYPTOPP_DISABLE_ALTIVEC 1 +# define CRYPTOPP_DISABLE_POWER7 1 +# define CRYPTOPP_DISABLE_POWER8 1 +#endif + +// An old Apple G5 with GCC 4.01 has AltiVec, but its only Power4 or so. +#if !defined(CRYPTOPP_ALTIVEC_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ALTIVEC) +# if defined(_ARCH_PWR4) || defined(__ALTIVEC__) || \ + (CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40001) +# define CRYPTOPP_ALTIVEC_AVAILABLE 1 +# endif +#endif + +// We need Power5 for 'vector unsigned long long' +#if !defined(CRYPTOPP_POWER5_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER5) && defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# if defined(_ARCH_PWR5) || (CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40100) +# define CRYPTOPP_POWER5_AVAILABLE 1 +# endif +#endif + +// We need Power7 for unaligned loads and stores +#if !defined(CRYPTOPP_POWER7_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER7) && defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# if defined(_ARCH_PWR7) || (CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40100) +# define CRYPTOPP_POWER7_AVAILABLE 1 +# endif +#endif + +// We need Power8 for in-core crypto +#if !defined(CRYPTOPP_POWER8_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8) && defined(CRYPTOPP_POWER7_AVAILABLE) +# if defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || (CRYPTOPP_GCC_VERSION >= 40800) +# define CRYPTOPP_POWER8_AVAILABLE 1 +# endif +#endif + +#if !defined(CRYPTOPP_POWER8_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8_AES) && defined(CRYPTOPP_POWER8_AVAILABLE) +# if defined(__CRYPTO__) || defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || (CRYPTOPP_GCC_VERSION >= 40800) +# define CRYPTOPP_POWER8_AES_AVAILABLE 1 +# define CRYPTOPP_POWER8_SHA_AVAILABLE 1 +//# define CRYPTOPP_POWER8_CRC_AVAILABLE 1 +# endif +#endif + +#endif // PPC, PPC64 + +// ***************** Miscellaneous ******************** + +// Nearly all Intel's and AMD's have SSE. Enable it independent of SSE ASM and intrinscs +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) && !defined(CRYPTOPP_DISABLE_ASM) + #define CRYPTOPP_BOOL_ALIGN16 1 +#else + #define CRYPTOPP_BOOL_ALIGN16 0 +#endif + +// How to allocate 16-byte aligned memory (for SSE2) +// posix_memalign see https://forum.kde.org/viewtopic.php?p=66274 +#if defined(_MSC_VER) + #define CRYPTOPP_MM_MALLOC_AVAILABLE +#elif defined(__linux__) || defined(__sun__) || defined(__CYGWIN__) + #define CRYPTOPP_MEMALIGN_AVAILABLE +#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + #define CRYPTOPP_MALLOC_ALIGNMENT_IS_16 +#elif (defined(_GNU_SOURCE) || ((_XOPEN_SOURCE + 0) >= 600)) && (_POSIX_ADVISORY_INFO > 0) + #define CRYPTOPP_POSIX_MEMALIGN_AVAILABLE +#else + #define CRYPTOPP_NO_ALIGNED_ALLOC +#endif + +// how to disable inlining +#if defined(_MSC_VER) +# define CRYPTOPP_NOINLINE_DOTDOTDOT +# define CRYPTOPP_NOINLINE __declspec(noinline) +#elif defined(__xlc__) || defined(__xlC__) +# define CRYPTOPP_NOINLINE_DOTDOTDOT ... +# define CRYPTOPP_NOINLINE __attribute__((noinline)) +#elif defined(__GNUC__) +# define CRYPTOPP_NOINLINE_DOTDOTDOT +# define CRYPTOPP_NOINLINE __attribute__((noinline)) +#else +# define CRYPTOPP_NOINLINE_DOTDOTDOT ... +# define CRYPTOPP_NOINLINE +#endif + +// How to declare class constants +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) || defined(__BORLANDC__) +# define CRYPTOPP_CONSTANT(x) static const int x; +#else +# define CRYPTOPP_CONSTANT(x) enum {x}; +#endif + +// How to disable CPU feature probing. We determine machine +// capabilities by performing an os/platform *query* first, +// like getauxv(). If the *query* fails, we move onto a +// cpu *probe*. The cpu *probe* tries to exeute an instruction +// and then catches a SIGILL on Linux or the exception +// EXCEPTION_ILLEGAL_INSTRUCTION on Windows. Some OSes +// fail to hangle a SIGILL gracefully, like Apple OSes. Apple +// machines corrupt memory and variables around the probe. +#if defined(__APPLE__) +# define CRYPTOPP_NO_CPU_FEATURE_PROBES 1 +#endif + +// ***************** Initialization and Constructor priorities ******************** + +// CRYPTOPP_INIT_PRIORITY attempts to manage initialization of C++ static objects. +// Under GCC, the library uses init_priority attribute in the range +// [CRYPTOPP_INIT_PRIORITY, CRYPTOPP_INIT_PRIORITY+100]. Under Windows, +// CRYPTOPP_INIT_PRIORITY enlists "#pragma init_seg(lib)". The platforms +// with gaps are Apple and Sun because they require linker scripts. Apple and +// Sun will use the library's Singletons to initialize and acquire resources. +// Also see http://cryptopp.com/wiki/Static_Initialization_Order_Fiasco +#ifndef CRYPTOPP_INIT_PRIORITY +# define CRYPTOPP_INIT_PRIORITY 250 +#endif + +// CRYPTOPP_USER_PRIORITY is for other libraries and user code that is using Crypto++ +// and managing C++ static object creation. It is guaranteed not to conflict with +// values used by (or would be used by) the Crypto++ library. +#if defined(CRYPTOPP_INIT_PRIORITY) && (CRYPTOPP_INIT_PRIORITY > 0) +# define CRYPTOPP_USER_PRIORITY (CRYPTOPP_INIT_PRIORITY + 101) +#else +# define CRYPTOPP_USER_PRIORITY 350 +#endif + +// Most platforms allow us to specify when to create C++ objects. Apple and Sun do not. +#if (CRYPTOPP_INIT_PRIORITY > 0) && !(defined(NO_OS_DEPENDENCE) || defined(__APPLE__) || defined(__sun__)) +# if (CRYPTOPP_GCC_VERSION >= 30000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 800) +# define HAVE_GCC_INIT_PRIORITY 1 +# elif (CRYPTOPP_MSC_VERSION >= 1310) +# define HAVE_MSC_INIT_PRIORITY 1 +# endif +#endif // CRYPTOPP_INIT_PRIORITY, NO_OS_DEPENDENCE, Apple, Sun + +// ***************** determine availability of OS features ******************** + +#ifndef NO_OS_DEPENDENCE + +#if defined(_WIN32) || defined(__CYGWIN__) +#define CRYPTOPP_WIN32_AVAILABLE +#endif + +#if defined(__unix__) || defined(__MACH__) || defined(__NetBSD__) || defined(__sun) +#define CRYPTOPP_UNIX_AVAILABLE +#endif + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#define CRYPTOPP_BSD_AVAILABLE +#endif + +#if defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE) +# define HIGHRES_TIMER_AVAILABLE +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if !defined(WINAPI_FAMILY) +# define THREAD_TIMER_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define THREAD_TIMER_AVAILABLE +# endif +# endif +#endif + +#ifdef CRYPTOPP_UNIX_AVAILABLE +# define HAS_BERKELEY_STYLE_SOCKETS +# define SOCKETS_AVAILABLE +#endif + +// Sockets are only available under Windows Runtime desktop partition apps (despite the MSDN literature) +#ifdef CRYPTOPP_WIN32_AVAILABLE +# define HAS_WINDOWS_STYLE_SOCKETS +# if !defined(WINAPI_FAMILY) +# define SOCKETS_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define SOCKETS_AVAILABLE +# endif +# endif +#endif + +#if defined(HAS_WINDOWS_STYLE_SOCKETS) && (!defined(HAS_BERKELEY_STYLE_SOCKETS) || defined(PREFER_WINDOWS_STYLE_SOCKETS)) +# define USE_WINDOWS_STYLE_SOCKETS +#else +# define USE_BERKELEY_STYLE_SOCKETS +#endif + +#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(SOCKETS_AVAILABLE) && !defined(USE_BERKELEY_STYLE_SOCKETS) +# define WINDOWS_PIPES_AVAILABLE +#endif + + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +# define NONBLOCKING_RNG_AVAILABLE +# define BLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# define HAS_PTHREADS +# define THREADS_AVAILABLE +#endif + +// Early IBM XL C on AIX fails to link due to missing pthread gear +#if defined(_AIX) && defined(__xlC__) +# undef HAS_PTHREADS +# undef THREADS_AVAILABLE +#endif + +// Cygwin/Newlib requires _XOPEN_SOURCE=600 +#if defined(CRYPTOPP_UNIX_AVAILABLE) +# define UNIX_SIGNALS_AVAILABLE 1 +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if !defined(WINAPI_FAMILY) +# define HAS_WINTHREADS +# define THREADS_AVAILABLE +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define HAS_WINTHREADS +# define THREADS_AVAILABLE +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# elif !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# if ((WINVER >= 0x0A00 /*_WIN32_WINNT_WIN10*/) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/)) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# endif +# endif +# endif +#endif + +#endif // NO_OS_DEPENDENCE + +// ***************** DLL related ******************** + +#if defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) + +#ifdef CRYPTOPP_EXPORTS +#define CRYPTOPP_IS_DLL +#define CRYPTOPP_DLL __declspec(dllexport) +#elif defined(CRYPTOPP_IMPORTS) +#define CRYPTOPP_IS_DLL +#define CRYPTOPP_DLL __declspec(dllimport) +#else +#define CRYPTOPP_DLL +#endif + +// C++ makes const internal linkage +#define CRYPTOPP_TABLE extern +#define CRYPTOPP_API __cdecl + +#else // not CRYPTOPP_WIN32_AVAILABLE + +// C++ makes const internal linkage +#define CRYPTOPP_TABLE extern +#define CRYPTOPP_DLL +#define CRYPTOPP_API + +#endif // CRYPTOPP_WIN32_AVAILABLE + +#if defined(__MWERKS__) +#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern class CRYPTOPP_DLL +#elif defined(__BORLANDC__) || defined(__SUNPRO_CC) +#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL +#else +#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern template class CRYPTOPP_DLL +#endif + +#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_IMPORTS) +#define CRYPTOPP_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL +#else +#define CRYPTOPP_DLL_TEMPLATE_CLASS CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS +#endif + +#if defined(__MWERKS__) +#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern class +#elif defined(__BORLANDC__) || defined(__SUNPRO_CC) +#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS template class +#else +#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern template class +#endif + +#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_EXPORTS) +#define CRYPTOPP_STATIC_TEMPLATE_CLASS template class +#else +#define CRYPTOPP_STATIC_TEMPLATE_CLASS CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS +#endif + +// ************** Unused variable *************** + +// Portable way to suppress warnings. +// Moved from misc.h due to circular depenedencies. +#define CRYPTOPP_UNUSED(x) ((void)(x)) + +// ************** Deprecated *************** + +#if (CRYPTOPP_GCC_VERSION >= 40500) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40200) +# define CRYPTOPP_DEPRECATED(msg) __attribute__((deprecated (msg))) +#elif (CRYPTOPP_GCC_VERSION) +# define CRYPTOPP_DEPRECATED(msg) __attribute__((deprecated)) +#else +# define CRYPTOPP_DEPRECATED(msg) +#endif + +// ************** Instrumentation *************** + +// GCC does not support; see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=78204 +#if (CRYPTOPP_LLVM_CLANG_VERSION >= 30700) || (CRYPTOPP_APPLE_CLANG_VERSION >= 70000) +# define CRYPTOPP_NO_SANITIZE(x) __attribute__((no_sanitize(x))) +#else +# define CRYPTOPP_NO_SANITIZE(x) +#endif + +// ***************** C++11 related ******************** + +// Visual Studio began at VS2010, http://msdn.microsoft.com/en-us/library/hh567368%28v=vs.110%29.aspx +// and https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance . +// Intel, http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler +// GCC, http://gcc.gnu.org/projects/cxx0x.html +// Clang, http://clang.llvm.org/cxx_status.html + +// Compatibility with non-clang compilers. +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +#if !defined(CRYPTOPP_NO_CXX11) +# if ((_MSC_VER >= 1600) || (__cplusplus >= 201103L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX11 1 +# endif +#endif + +// Hack ahead. Apple's standard library does not have C++'s unique_ptr in C++11. We can't +// test for unique_ptr directly because some of the non-Apple Clangs on OS X fail the same +// way. However, modern standard libraries have , so we test for it instead. +// Thanks to Jonathan Wakely for devising the clever test for modern/ancient versions. +// TODO: test under Xcode 3, where g++ is really g++. +#if defined(__APPLE__) && defined(__clang__) +# if !(defined(__has_include) && __has_include()) +# undef CRYPTOPP_CXX11 +# endif +#endif + +// C++11 or C++14 is available +#if defined(CRYPTOPP_CXX11) + +// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 5.14. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_atomic) || \ + (__INTEL_COMPILER >= 1300) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5140) +# define CRYPTOPP_CXX11_ATOMICS 1 +#endif // atomics + +// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 5.13. +// TODO: verify Clang and Intel versions; find __has_feature(x) extension for Clang +#if (CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 50000) || (__INTEL_COMPILER >= 1200) || \ + (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130) +// Hack ahead. New GCC compilers like GCC 6 on AIX 7.0 or earlier as well as original MinGW +// don't have the synchronization gear. However, Wakely's test used for Apple does not work +// on the GCC/AIX combination. Another twist is we need other stuff from C++11, +// like no-except destructors. Dumping preprocessors shows the following may +// apply: http://stackoverflow.com/q/14191566/608639. +# include +# if !defined(__GLIBCXX__) || defined(_GLIBCXX_HAS_GTHREADS) +# define CRYPTOPP_CXX11_SYNCHRONIZATION 1 +# endif +#endif // synchronization + +// Dynamic Initialization and Destruction with Concurrency ("Magic Statics") +// MS at VS2015 with Vista (19.00); GCC at 4.3; LLVM Clang at 2.9; Apple Clang at 4.0; Intel 11.1; SunCC 5.13. +// Microsoft's implementation only works for Vista and above, so its further +// limited. http://connect.microsoft.com/VisualStudio/feedback/details/1789709 +#if (CRYPTOPP_MSC_VERSION >= 1900) && ((WINVER >= 0x0600) || (_WIN32_WINNT >= 0x0600)) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || \ + (__INTEL_COMPILER >= 1110) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_DYNAMIC_INIT 1 +#endif // Dynamic Initialization compilers + +// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.0; Intel 15.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignas) || \ + (__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40800) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNAS 1 +#endif // alignas + +// alignof: MS at VS2015 (19.00); GCC at 4.5; Clang at 2.9; Intel 15.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignof) || \ + (__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40500) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#endif // alignof + +// lambdas: MS at VS2012 (17.00); GCC at 4.9; Clang at 3.3; Intel 12.0; SunCC 5.14. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_lambdas) || \ + (__INTEL_COMPILER >= 1200) || (CRYPTOPP_GCC_VERSION >= 40900) || (__SUNPRO_CC >= 0x5140) +# define CRYPTOPP_CXX11_LAMBDA 1 +#endif // lambdas + +// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_noexcept) || \ + (__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_NOEXCEPT 1 +#endif // noexcept compilers + +// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1800) || __has_feature(cxx_variadic_templates) || \ + (__INTEL_COMPILER >= 1210) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 +#endif // variadic templates + +// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.1; Intel 16.0; SunCC 5.13. +// Intel has mis-supported the feature since at least ICPC 13.00 +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_constexpr) || \ + (__INTEL_COMPILER >= 1600) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_CONSTEXPR 1 +#endif // constexpr compilers + +// strong typed enums: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Intel 14.0; SunCC 5.12. +// Mircorosft and Intel had partial support earlier, but we require full support. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_strong_enums) || \ + (__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5120) +# define CRYPTOPP_CXX11_ENUM 1 +#endif // constexpr compilers + +// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 10.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1600) || __has_feature(cxx_nullptr) || \ + (__INTEL_COMPILER >= 1000) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_NULLPTR 1 +#endif // nullptr_t compilers + +#endif // CRYPTOPP_CXX11 + +// ***************** C++17 related ******************** + +// C++17 macro version, https://stackoverflow.com/q/38456127/608639 +#if defined(CRYPTOPP_CXX11) && !defined(CRYPTOPP_NO_CXX17) +# if ((_MSC_VER >= 1900) || (__cplusplus >= 201703L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX17 1 +# endif +#endif + +// C++17 is available +#if defined(CRYPTOPP_CXX17) + +// C++17 uncaught_exceptions: MS at VS2015 (19.00); GCC at 6.0; Clang at 3.5; Intel 18.0. +// Clang and __EXCEPTIONS see http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html +#if defined(__clang__) +# if __EXCEPTIONS && __has_feature(cxx_exceptions) +# define CRYPTOPP_CXX17_EXCEPTIONS 1 +# endif +#elif (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1800) || (CRYPTOPP_GCC_VERSION >= 60000) +# define CRYPTOPP_CXX17_EXCEPTIONS 1 +#endif // uncaught_exceptions compilers + +#endif // CRYPTOPP_CXX17 + +// ***************** C++ fixups ******************** + +#if defined(CRYPTOPP_CXX11_NOEXCEPT) +# define CRYPTOPP_THROW noexcept(false) +# define CRYPTOPP_NO_THROW noexcept(true) +#else +# define CRYPTOPP_THROW +# define CRYPTOPP_NO_THROW +#endif // CRYPTOPP_CXX11_NOEXCEPT + +// http://stackoverflow.com/a/13867690/608639 +#if defined(CRYPTOPP_CXX11_CONSTEXPR) +# define CRYPTOPP_STATIC_CONSTEXPR static constexpr +# define CRYPTOPP_CONSTEXPR constexpr +#else +# define CRYPTOPP_STATIC_CONSTEXPR static +# define CRYPTOPP_CONSTEXPR +#endif // CRYPTOPP_CXX11_CONSTEXPR + +// Hack... CRYPTOPP_ALIGN_DATA is defined earlier, before C++11 alignas availability is determined +#if defined(CRYPTOPP_CXX11_ALIGNAS) +# undef CRYPTOPP_ALIGN_DATA +# define CRYPTOPP_ALIGN_DATA(x) alignas(x) +#endif // CRYPTOPP_CXX11_ALIGNAS + +// Hack... CRYPTOPP_CONSTANT is defined earlier, before C++11 constexpr availability is determined +// http://stackoverflow.com/q/35213098/608639 +// #if defined(CRYPTOPP_CXX11_CONSTEXPR) +// # undef CRYPTOPP_CONSTANT +// # define CRYPTOPP_CONSTANT(x) constexpr static int x; +// #endif + +// Hack... CRYPTOPP_CONSTANT is defined earlier, before C++11 constexpr availability is determined +// http://stackoverflow.com/q/35213098/608639 +#if defined(CRYPTOPP_CXX11_ENUM) +# undef CRYPTOPP_CONSTANT +# define CRYPTOPP_CONSTANT(x) enum : int { x }; +#elif defined(CRYPTOPP_CXX11_CONSTEXPR) +# undef CRYPTOPP_CONSTANT +# define CRYPTOPP_CONSTANT(x) constexpr static int x; +#endif + +// Hack... C++11 nullptr_t type safety and analysis +#if defined(CRYPTOPP_CXX11_NULLPTR) && !defined(NULLPTR) +# define NULLPTR nullptr +#elif !defined(NULLPTR) +# define NULLPTR NULL +#endif // CRYPTOPP_CXX11_NULLPTR + +// OK to comment the following out, but please report it so we can fix it. +// C++17 value taken from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf. +#if (defined(__cplusplus) && (__cplusplus >= 199711L) && (__cplusplus < 201402L)) && !defined(CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE) +# error "std::uncaught_exception is not available. This is likely a configuration error." +#endif + +#endif // CRYPTOPP_CONFIG_H diff --git a/include/cryptlib/cpu.h b/include/cryptlib/cpu.h new file mode 100644 index 0000000..d5bbb91 --- /dev/null +++ b/include/cryptlib/cpu.h @@ -0,0 +1,773 @@ +// cpu.h - originally written and placed in the public domain by Wei Dai +// updated for ARM and PowerPC by Jeffrey Walton. +// updated to split CPU_Query() and CPU_Probe() by Jeffrey Walton. + +/// \file cpu.h +/// \brief Functions for CPU features and intrinsics +/// \details The CPU functions are used in IA-32, ARM and PowerPC code paths. The +/// functions provide cpu specific feature testing on IA-32, ARM and PowerPC machines. +/// \details Feature detection uses CPUID on IA-32, like Intel and AMD. On other platforms +/// a two-part strategy is used. First, the library attempts to *Query* the OS for a feature, +/// like using Linux getauxval() or android_getCpuFeatures(). If that fails, then *Probe* +/// the cpu executing an instruction and an observe a SIGILL if unsupported. The general +/// pattern used by the library is: +///
+///     g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32();
+///     g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
+///     g_hasAES  = CPU_QueryAES() || CPU_ProbeAES();
+/// 
+/// \details Generally speaking, CPU_Query() is in the source file cpu.cpp because it +/// does not require special architectural flags. CPU_Probe() is in a source file that recieves +/// architectural flags, like sse-simd.cpp, neon-simd.cpp and +/// ppc-simd.cpp. For example, compiling neon-simd.cpp on an ARM64 machine will +/// have -march=armv8-a applied during a compile to make the instruction set architecture +/// (ISA) available. +/// \details The cpu probes are expensive when compared to a standard OS feature query. The library +/// also avoids probes on Apple platforms because Apple's signal handling for SIGILLs appears to +/// corrupt memory. CPU_Probe() will unconditionally return false for Apple platforms. OpenSSL +/// experienced the same problem and moved away from SIGILL probes on Apple. + +#ifndef CRYPTOPP_CPU_H +#define CRYPTOPP_CPU_H + +#include "config.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +// Applies to both X86/X32/X64 and ARM32/ARM64 +#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER) + #define NEW_LINE "\n" + #define INTEL_PREFIX ".intel_syntax;" + #define INTEL_NOPREFIX ".intel_syntax;" + #define ATT_PREFIX ".att_syntax;" + #define ATT_NOPREFIX ".att_syntax;" +#elif defined(__GNUC__) + #define NEW_LINE + #define INTEL_PREFIX ".intel_syntax prefix;" + #define INTEL_NOPREFIX ".intel_syntax noprefix;" + #define ATT_PREFIX ".att_syntax prefix;" + #define ATT_NOPREFIX ".att_syntax noprefix;" +#else + #define NEW_LINE + #define INTEL_PREFIX + #define INTEL_NOPREFIX + #define ATT_PREFIX + #define ATT_NOPREFIX +#endif + +#ifdef CRYPTOPP_GENERATE_X64_MASM + +#define CRYPTOPP_X86_ASM_AVAILABLE +#define CRYPTOPP_BOOL_X64 1 +#define CRYPTOPP_SSE2_ASM_AVAILABLE 1 +#define NAMESPACE_END + +#else + +NAMESPACE_BEGIN(CryptoPP) + +// ***************************** IA-32 ***************************** // + +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_DOXYGEN_PROCESSING + +#define CRYPTOPP_CPUID_AVAILABLE 1 + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +// These should not be used directly +extern CRYPTOPP_DLL bool g_x86DetectionDone; +extern CRYPTOPP_DLL bool g_hasSSE2; +extern CRYPTOPP_DLL bool g_hasSSSE3; +extern CRYPTOPP_DLL bool g_hasSSE41; +extern CRYPTOPP_DLL bool g_hasSSE42; +extern CRYPTOPP_DLL bool g_hasAESNI; +extern CRYPTOPP_DLL bool g_hasCLMUL; +extern CRYPTOPP_DLL bool g_hasSHA; +extern CRYPTOPP_DLL bool g_hasADX; +extern CRYPTOPP_DLL bool g_isP4; +extern CRYPTOPP_DLL bool g_hasRDRAND; +extern CRYPTOPP_DLL bool g_hasRDSEED; +extern CRYPTOPP_DLL bool g_hasPadlockRNG; +extern CRYPTOPP_DLL bool g_hasPadlockACE; +extern CRYPTOPP_DLL bool g_hasPadlockACE2; +extern CRYPTOPP_DLL bool g_hasPadlockPHE; +extern CRYPTOPP_DLL bool g_hasPadlockPMM; +extern CRYPTOPP_DLL word32 g_cacheLineSize; + +CRYPTOPP_DLL void CRYPTOPP_API DetectX86Features(); +CRYPTOPP_DLL bool CRYPTOPP_API CpuId(word32 func, word32 subfunc, word32 output[4]); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name IA-32 CPU FEATURES +//@{ + +/// \brief Determines SSE2 availability +/// \returns true if SSE2 is determined to be available, false otherwise +/// \details MMX, SSE and SSE2 are core processor features for x86_64, and +/// the function always returns true for the platform. +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE2() +{ +#if CRYPTOPP_BOOL_X64 + return true; +#else + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE2; +#endif +} + +/// \brief Determines SSSE3 availability +/// \returns true if SSSE3 is determined to be available, false otherwise +/// \details HasSSSE3() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSSE3() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSSE3; +} + +/// \brief Determines SSE4.1 availability +/// \returns true if SSE4.1 is determined to be available, false otherwise +/// \details HasSSE41() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE41() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE41; +} + +/// \brief Determines SSE4.2 availability +/// \returns true if SSE4.2 is determined to be available, false otherwise +/// \details HasSSE42() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE42() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE42; +} + +/// \brief Determines AES-NI availability +/// \returns true if AES-NI is determined to be available, false otherwise +/// \details HasAESNI() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAESNI() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAESNI; +} + +/// \brief Determines Carryless Multiply availability +/// \returns true if pclmulqdq is determined to be available, false otherwise +/// \details HasCLMUL() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasCLMUL() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasCLMUL; +} + +/// \brief Determines SHA availability +/// \returns true if SHA is determined to be available, false otherwise +/// \details HasSHA() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSHA() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSHA; +} + +/// \brief Determines ADX availability +/// \returns true if ADX is determined to be available, false otherwise +/// \details HasADX() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasADX() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasADX; +} + +/// \brief Determines if the CPU is an Intel P4 +/// \returns true if the CPU is a P4, false otherwise +/// \details IsP4() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool IsP4() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_isP4; +} + +/// \brief Determines RDRAND availability +/// \returns true if RDRAND is determined to be available, false otherwise +/// \details HasRDRAND() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasRDRAND() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasRDRAND; +} + +/// \brief Determines RDSEED availability +/// \returns true if RDSEED is determined to be available, false otherwise +/// \details HasRDSEED() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasRDSEED() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasRDSEED; +} + +/// \brief Determines Padlock RNG availability +/// \returns true if VIA Padlock RNG is determined to be available, false otherwise +/// \details HasPadlockRNG() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockRNG() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockRNG; +} + +/// \brief Determines Padlock ACE availability +/// \returns true if VIA Padlock ACE is determined to be available, false otherwise +/// \details HasPadlockACE() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockACE() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockACE; +} + +/// \brief Determines Padlock ACE2 availability +/// \returns true if VIA Padlock ACE2 is determined to be available, false otherwise +/// \details HasPadlockACE2() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockACE2() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockACE2; +} + +/// \brief Determines Padlock PHE availability +/// \returns true if VIA Padlock PHE is determined to be available, false otherwise +/// \details HasPadlockPHE() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockPHE() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockPHE; +} + +/// \brief Determines Padlock PMM availability +/// \returns true if VIA Padlock PMM is determined to be available, false otherwise +/// \details HasPadlockPMM() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockPMM() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockPMM; +} + +/// \brief Provides the cache line size +/// \returns lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_cacheLineSize; +} +//@} + +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +// ***************************** ARM-32, Aarch32 and Aarch64 ***************************** // + +#if CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 || CRYPTOPP_DOXYGEN_PROCESSING + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +extern bool g_ArmDetectionDone; +extern bool g_hasNEON, g_hasPMULL, g_hasCRC32, g_hasAES, g_hasSHA1, g_hasSHA2; +void CRYPTOPP_API DetectArmFeatures(); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name ARM A-32, Aarch32 and AArch64 CPU FEATURES +//@{ + +/// \brief Determine if an ARM processor has Advanced SIMD available +/// \returns true if the hardware is capable of Advanced SIMD at runtime, false otherwise. +/// \details Advanced SIMD instructions are available under most ARMv7, Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mfpu=neon (32-bit) or -march=armv8-a +/// (64-bit). Also see ARM's __ARM_NEON preprocessor macro. +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasNEON() +{ + // ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64 +#if defined(__aarch32__) || defined(__aarch64__) + return true; +#else + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasNEON; +#endif +} + +/// \brief Determine if an ARM processor provides Polynomial Multiplication +/// \returns true if the hardware is capable of polynomial multiplications at runtime, false otherwise. +/// \details The multiplication instructions are available under Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasPMULL() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasPMULL; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has CRC32 available +/// \returns true if the hardware is capable of CRC32 at runtime, false otherwise. +/// \details CRC32 instructions provide access to the processor's CRC-32 and CRC-32C instructions. +/// They are provided by ARM C Language Extensions 2.0 (ACLE 2.0) and available under Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crc; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRC32 preprocessor macro. +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasCRC32() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasCRC32; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has AES available +/// \returns true if the hardware is capable of AES at runtime, false otherwise. +/// \details AES is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasAES() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasAES; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA1 available +/// \returns true if the hardware is capable of SHA1 at runtime, false otherwise. +/// \details SHA1 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasSHA1() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA1; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA2 available +/// \returns true if the hardware is capable of SHA2 at runtime, false otherwise. +/// \details SHA2 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasSHA2() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA2; +#else + return false; +#endif +} + +//@} + +#endif // CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 + +// ***************************** PowerPC ***************************** // + +#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_DOXYGEN_PROCESSING + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +extern bool g_PowerpcDetectionDone; +extern bool g_hasAltivec, g_hasPower7, g_hasPower8, g_hasAES, g_hasSHA256, g_hasSHA512; +extern word32 g_cacheLineSize; +void CRYPTOPP_API DetectPowerpcFeatures(); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name POWERPC CPU FEATURES +//@{ + +/// \brief Determine if a PowerPC processor has Altivec available +/// \returns true if the hardware is capable of Altivec at runtime, false otherwise. +/// \details Altivec instructions are available under most modern PowerPCs. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power7; while IBM XL C/C++ compilers require +/// -qarch=pwr7 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \details Atilvec was first available on Power4 platforms. However Crypto++ releies on unaligned +/// loads and stores which is a Power7 feature. If the platform lacks Power7 extensions, then the +/// GNUmakefile sets -DCRYPTOPP_DISABLE_ALTIVEC. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasAltivec() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasAltivec; +} + +/// \brief Determine if a PowerPC processor has Power8 available +/// \returns true if the hardware is capable of Power8 at runtime, false otherwise. +/// \details Altivec instructions are available under most modern PowerPCs. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \details Atilvec was first available on Power4 platforms. However Crypto++ releies on unaligned +/// loads and stores which is a Power7 feature. If the platform lacks Power7 extensions, then the +/// GNUmakefile sets -DCRYPTOPP_DISABLE_ALTIVEC. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower7() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasPower7; +} + +/// \brief Determine if a PowerPC processor has Power8 available +/// \returns true if the hardware is capable of Power8 at runtime, false otherwise. +/// \details Altivec instructions are available under most modern PowerPCs. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \details Atilvec was first available on Power4 platforms. However Crypto++ releies on unaligned +/// loads and stores which is a Power7 feature. If the platform lacks Power7 extensions, then the +/// GNUmakefile sets -DCRYPTOPP_DISABLE_ALTIVEC. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower8() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasPower8; +} + +/// \brief Determine if a PowerPC processor has AES available +/// \returns true if the hardware is capable of AES at runtime, false otherwise. +/// \details AES is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasAES() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasAES; +} + +/// \brief Determine if a PowerPC processor has SHA256 available +/// \returns true if the hardware is capable of SHA256 at runtime, false otherwise. +/// \details SHA is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasSHA256() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasSHA256; +} + +/// \brief Determine if a PowerPC processor has SHA512 available +/// \returns true if the hardware is capable of SHA512 at runtime, false otherwise. +/// \details SHA is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasSHA512() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasSHA512; +} + +/// \brief Provides the cache line size +/// \returns lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_cacheLineSize; +} + +//@} + +#endif // CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 + +// ***************************** L1 cache line ***************************** // + +// Non-Intel systems +#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +/// \brief Provides the cache line size +/// \returns lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + return CRYPTOPP_L1_CACHE_LINE_SIZE; +} +#endif // Non-Intel systems + +#endif // CRYPTOPP_GENERATE_X64_MASM + +// ***************************** Inline ASM Helper ***************************** // + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +#ifdef CRYPTOPP_GENERATE_X64_MASM + #define AS1(x) x*newline* + #define AS2(x, y) x, y*newline* + #define AS3(x, y, z) x, y, z*newline* + #define ASS(x, y, a, b, c, d) x, y, a*64+b*16+c*4+d*newline* + #define ASL(x) label##x:*newline* + #define ASJ(x, y, z) x label##y*newline* + #define ASC(x, y) x label##y*newline* + #define AS_HEX(y) 0##y##h +#elif defined(_MSC_VER) || defined(__BORLANDC__) + #define AS1(x) __asm {x} + #define AS2(x, y) __asm {x, y} + #define AS3(x, y, z) __asm {x, y, z} + #define ASS(x, y, a, b, c, d) __asm {x, y, (a)*64+(b)*16+(c)*4+(d)} + #define ASL(x) __asm {label##x:} + #define ASJ(x, y, z) __asm {x label##y} + #define ASC(x, y) __asm {x label##y} + #define CRYPTOPP_NAKED __declspec(naked) + #define AS_HEX(y) 0x##y +#else + // define these in two steps to allow arguments to be expanded + #define GNU_AS1(x) #x ";" NEW_LINE + #define GNU_AS2(x, y) #x ", " #y ";" NEW_LINE + #define GNU_AS3(x, y, z) #x ", " #y ", " #z ";" NEW_LINE + #define GNU_ASL(x) "\n" #x ":" NEW_LINE + #define GNU_ASJ(x, y, z) #x " " #y #z ";" NEW_LINE + #define AS1(x) GNU_AS1(x) + #define AS2(x, y) GNU_AS2(x, y) + #define AS3(x, y, z) GNU_AS3(x, y, z) + #define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";" + #define ASL(x) GNU_ASL(x) + #define ASJ(x, y, z) GNU_ASJ(x, y, z) + #define ASC(x, y) #x " " #y ";" + #define CRYPTOPP_NAKED + #define AS_HEX(y) 0x##y +#endif + +#define IF0(y) +#define IF1(y) y + +#ifdef CRYPTOPP_GENERATE_X64_MASM +#define ASM_MOD(x, y) ((x) MOD (y)) +#define XMMWORD_PTR XMMWORD PTR +#else +// GNU assembler doesn't seem to have mod operator +#define ASM_MOD(x, y) ((x)-((x)/(y))*(y)) +// GAS 2.15 doesn't support XMMWORD PTR. it seems necessary only for MASM +#define XMMWORD_PTR +#endif + +#if CRYPTOPP_BOOL_X86 + #define AS_REG_1 ecx + #define AS_REG_2 edx + #define AS_REG_3 esi + #define AS_REG_4 edi + #define AS_REG_5 eax + #define AS_REG_6 ebx + #define AS_REG_7 ebp + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d esi + #define AS_REG_4d edi + #define AS_REG_5d eax + #define AS_REG_6d ebx + #define AS_REG_7d ebp + #define WORD_SZ 4 + #define WORD_REG(x) e##x + #define WORD_PTR DWORD PTR + #define AS_PUSH_IF86(x) AS1(push e##x) + #define AS_POP_IF86(x) AS1(pop e##x) + #define AS_JCXZ jecxz +#elif CRYPTOPP_BOOL_X32 + #define AS_REG_1 ecx + #define AS_REG_2 edx + #define AS_REG_3 r8d + #define AS_REG_4 r9d + #define AS_REG_5 eax + #define AS_REG_6 r10d + #define AS_REG_7 r11d + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d r8d + #define AS_REG_4d r9d + #define AS_REG_5d eax + #define AS_REG_6d r10d + #define AS_REG_7d r11d + #define WORD_SZ 4 + #define WORD_REG(x) e##x + #define WORD_PTR DWORD PTR + #define AS_PUSH_IF86(x) AS1(push r##x) + #define AS_POP_IF86(x) AS1(pop r##x) + #define AS_JCXZ jecxz +#elif CRYPTOPP_BOOL_X64 + #ifdef CRYPTOPP_GENERATE_X64_MASM + #define AS_REG_1 rcx + #define AS_REG_2 rdx + #define AS_REG_3 r8 + #define AS_REG_4 r9 + #define AS_REG_5 rax + #define AS_REG_6 r10 + #define AS_REG_7 r11 + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d r8d + #define AS_REG_4d r9d + #define AS_REG_5d eax + #define AS_REG_6d r10d + #define AS_REG_7d r11d + #else + #define AS_REG_1 rdi + #define AS_REG_2 rsi + #define AS_REG_3 rdx + #define AS_REG_4 rcx + #define AS_REG_5 r8 + #define AS_REG_6 r9 + #define AS_REG_7 r10 + #define AS_REG_1d edi + #define AS_REG_2d esi + #define AS_REG_3d edx + #define AS_REG_4d ecx + #define AS_REG_5d r8d + #define AS_REG_6d r9d + #define AS_REG_7d r10d + #endif + #define WORD_SZ 8 + #define WORD_REG(x) r##x + #define WORD_PTR QWORD PTR + #define AS_PUSH_IF86(x) + #define AS_POP_IF86(x) + #define AS_JCXZ jrcxz +#endif + +// helper macro for stream cipher output +#define AS_XMM_OUTPUT4(labelPrefix, inputPtr, outputPtr, x0, x1, x2, x3, t, p0, p1, p2, p3, increment)\ + AS2( test inputPtr, inputPtr)\ + ASC( jz, labelPrefix##3)\ + AS2( test inputPtr, 15)\ + ASC( jnz, labelPrefix##7)\ + AS2( pxor xmm##x0, [inputPtr+p0*16])\ + AS2( pxor xmm##x1, [inputPtr+p1*16])\ + AS2( pxor xmm##x2, [inputPtr+p2*16])\ + AS2( pxor xmm##x3, [inputPtr+p3*16])\ + AS2( add inputPtr, increment*16)\ + ASC( jmp, labelPrefix##3)\ + ASL(labelPrefix##7)\ + AS2( movdqu xmm##t, [inputPtr+p0*16])\ + AS2( pxor xmm##x0, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p1*16])\ + AS2( pxor xmm##x1, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p2*16])\ + AS2( pxor xmm##x2, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p3*16])\ + AS2( pxor xmm##x3, xmm##t)\ + AS2( add inputPtr, increment*16)\ + ASL(labelPrefix##3)\ + AS2( test outputPtr, 15)\ + ASC( jnz, labelPrefix##8)\ + AS2( movdqa [outputPtr+p0*16], xmm##x0)\ + AS2( movdqa [outputPtr+p1*16], xmm##x1)\ + AS2( movdqa [outputPtr+p2*16], xmm##x2)\ + AS2( movdqa [outputPtr+p3*16], xmm##x3)\ + ASC( jmp, labelPrefix##9)\ + ASL(labelPrefix##8)\ + AS2( movdqu [outputPtr+p0*16], xmm##x0)\ + AS2( movdqu [outputPtr+p1*16], xmm##x1)\ + AS2( movdqu [outputPtr+p2*16], xmm##x2)\ + AS2( movdqu [outputPtr+p3*16], xmm##x3)\ + ASL(labelPrefix##9)\ + AS2( add outputPtr, increment*16) + +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +#endif // Not CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif // CRYPTOPP_CPU_H diff --git a/include/cryptlib/crc.h b/include/cryptlib/crc.h new file mode 100644 index 0000000..ff06079 --- /dev/null +++ b/include/cryptlib/crc.h @@ -0,0 +1,74 @@ +// crc.h - originally written and placed in the public domain by Wei Dai + +/// \file crc.h +/// \brief Classes for CRC-32 and CRC-32C checksum algorithm + +#ifndef CRYPTOPP_CRC32_H +#define CRYPTOPP_CRC32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 CRC32_NEGL = 0xffffffffL; + +#ifdef CRYPTOPP_LITTLE_ENDIAN +#define CRC32_INDEX(c) (c & 0xff) +#define CRC32_SHIFTED(c) (c >> 8) +#else +#define CRC32_INDEX(c) (c >> 24) +#define CRC32_SHIFTED(c) (c << 8) +#endif + +/// \brief CRC-32 Checksum Calculation +/// \details Uses CRC polynomial 0xEDB88320 +class CRC32 : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4) + CRC32(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + byte GetCrcByte(size_t i) const {return ((byte *)&(m_crc))[i];} + +protected: + void Reset() {m_crc = CRC32_NEGL;} + +private: + static const word32 m_tab[256]; + word32 m_crc; +}; + +/// \brief CRC-32C Checksum Calculation +/// \details Uses CRC polynomial 0x82F63B78 +/// \since Crypto++ 5.6.4 +class CRC32C : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4) + CRC32C(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32C";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + byte GetCrcByte(size_t i) const {return ((byte *)&(m_crc))[i];} + +protected: + void Reset() {m_crc = CRC32_NEGL;} + +private: + static const word32 m_tab[256]; + word32 m_crc; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/cryptlib.h b/include/cryptlib/cryptlib.h new file mode 100644 index 0000000..6084753 --- /dev/null +++ b/include/cryptlib/cryptlib.h @@ -0,0 +1,3210 @@ +// cryptlib.h - originally written and placed in the public domain by Wei Dai + +/// \file cryptlib.h +/// \brief Abstract base classes that provide a uniform interface to this library. + +/*! \mainpage Crypto++ Library 7.0 API Reference +
+
Abstract Base Classes
+ cryptlib.h +
Authenticated Encryption Modes
+ CCM, EAX, \ref GCM "GCM (2K tables)", \ref GCM "GCM (64K tables)" +
Block Ciphers
+ \ref Rijndael "AES", ARIA, Weak::ARC4, Blowfish, BTEA, Camellia, CAST128, CAST256, DES, + \ref DES_EDE2 "2-key Triple-DES", \ref DES_EDE3 "3-key Triple-DES", \ref DES_XEX3 "DESX", + GOST, IDEA, \ref LR "Luby-Rackoff", Kalyna (128/256/512), MARS, RC2, RC5, RC6, \ref SAFER_K + "SAFER-K", \ref SAFER_SK "SAFER-SK", SEED, Serpent, \ref SHACAL2 "SHACAL-2", SHARK, SKIPJACK, + SM4, Square, TEA, \ref ThreeWay "3-Way", \ref Threefish256 "Threefish (256/512/1024)", Twofish, XTEA +
Stream Ciphers
+ ChaCha (ChaCha-8/12/20), \ref Panama "Panama-LE", \ref Panama "Panama-BE", Salsa20, + \ref SEAL "SEAL-LE", \ref SEAL "SEAL-BE", WAKE, XSalsa20 +
Hash Functions
+ BLAKE2s, BLAKE2b, \ref Keccak "Keccak (F1600)", SHA1, SHA224, SHA256, SHA384, SHA512, + \ref SHA3 "SHA-3", SM3, Tiger, RIPEMD160, RIPEMD320, RIPEMD128, RIPEMD256, SipHash, Whirlpool, + Weak::MD2, Weak::MD4, Weak::MD5 +
Non-Cryptographic Checksums
+ CRC32, Adler32 +
Message Authentication Codes
+ BLAKE2b, BLAKE2s, CBC_MAC, CMAC, DMAC, \ref GCM "GCM (GMAC)", HMAC, Poly1305, TTMAC, VMAC +
Random Number Generators
+ NullRNG(), LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG, + NIST Hash_DRBG and HMAC_DRBG, \ref MersenneTwister "MersenneTwister (MT19937 and MT19937-AR)", RDRAND, RDSEED +
Key Derivation and Password-based Cryptography
+ HKDF, \ref PKCS12_PBKDF "PBKDF (PKCS #12)", \ref PKCS5_PBKDF1 "PBKDF-1 (PKCS #5)", + \ref PKCS5_PBKDF2_HMAC "PBKDF-2/HMAC (PKCS #5)" +
Public Key Cryptosystems
+ DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES +
Public Key Signature Schemes
+ DSA2, GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO, RabinSS, RWSS, ESIGN +
Key Agreement
+ DH, DH2, \ref MQV_Domain "MQV", \ref HMQV_Domain "HMQV", \ref FHMQV_Domain "FHMQV", ECDH, ECMQV, ECHMQV, + ECFHMQV, XTR_DH +
Algebraic Structures
+ Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver, + ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, GF2NP, GF256, GF2_32, EC2N, ECP +
Secret Sharing and Information Dispersal
+ SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery +
Compression
+ Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor +
Input Source Classes
+ StringSource, ArraySource, FileSource, SocketSource, WindowsPipeSource, RandomNumberSource +
Output Sink Classes
+ StringSinkTemplate, StringSink, ArraySink, FileSink, SocketSink, WindowsPipeSink, RandomNumberSink +
Filter Wrappers
+ StreamTransformationFilter, AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashFilter, + HashVerificationFilter, SignerFilter, SignatureVerificationFilter +
Binary to Text Encoders and Decoders
+ HexEncoder, HexDecoder, Base64Encoder, Base64Decoder, Base64URLEncoder, Base64URLDecoder, Base32Encoder, + Base32Decoder +
Wrappers for OS features
+ Timer, Socket, WindowsHandle, ThreadLocalStorage, ThreadUserTimer + +
+ + + +

This reference manual is a work in progress. Some classes lack detailed descriptions. +

Click here to download a zip archive containing this manual. +

Thanks to Ryan Phillips for providing the Doxygen configuration file +and getting us started on the manual. +*/ + +#ifndef CRYPTOPP_CRYPTLIB_H +#define CRYPTOPP_CRYPTLIB_H + +#include "config.h" +#include "stdcpp.h" +#include "trap.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4505 4702) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// forward declarations +class Integer; +class RandomNumberGenerator; +class BufferedTransformation; + +/// \brief Specifies a direction for a cipher to operate +/// \sa BlockTransformation::IsForwardTransformation(), BlockTransformation::IsPermutation(), BlockTransformation::GetCipherDirection() +enum CipherDir { + /// \brief the cipher is performing encryption + ENCRYPTION, + /// \brief the cipher is performing decryption + DECRYPTION}; + +/// \brief Represents infinite time +const unsigned long INFINITE_TIME = ULONG_MAX; + +// VC60 workaround: using enums as template parameters causes problems +/// \brief Converts an enumeration to a type suitable for use as a template parameter +template +struct EnumToType +{ + static ENUM_TYPE ToEnum() {return (ENUM_TYPE)VALUE;} +}; + +/// \brief Provides the byte ordering +/// \details Big-endian and little-endian modes are supported. Bi-endian and PDP-endian modes +/// are not supported. +enum ByteOrder { + /// \brief byte order is little-endian + LITTLE_ENDIAN_ORDER = 0, + /// \brief byte order is big-endian + BIG_ENDIAN_ORDER = 1}; + +/// \brief Provides a constant for LittleEndian +typedef EnumToType LittleEndian; +/// \brief Provides a constant for BigEndian +typedef EnumToType BigEndian; + +/// \brief Base class for all exceptions thrown by the library +/// \details All library exceptions directly or indirectly inherit from the Exception class. +/// The Exception class itself inherits from std::exception. The library does not use +/// std::runtime_error derived classes. +class CRYPTOPP_DLL Exception : public std::exception +{ +public: + /// \enum ErrorType + /// \brief Error types or categories + enum ErrorType { + /// \brief A method was called which was not implemented + NOT_IMPLEMENTED, + /// \brief An invalid argument was detected + INVALID_ARGUMENT, + /// \brief BufferedTransformation received a Flush(true) signal but can't flush buffers + CANNOT_FLUSH, + /// \brief Data integerity check, such as CRC or MAC, failed + DATA_INTEGRITY_CHECK_FAILED, + /// \brief Input data was received that did not conform to expected format + INVALID_DATA_FORMAT, + /// \brief Error reading from input device or writing to output device + IO_ERROR, + /// \brief Some other error occurred not belonging to other categories + OTHER_ERROR + }; + + virtual ~Exception() throw() {} + + /// \brief Construct a new Exception + explicit Exception(ErrorType errorType, const std::string &s) : m_errorType(errorType), m_what(s) {} + + /// \brief Retrieves a C-string describing the exception + const char *what() const throw() {return (m_what.c_str());} + /// \brief Retrieves a string describing the exception + const std::string &GetWhat() const {return m_what;} + /// \brief Sets the error string for the exception + void SetWhat(const std::string &s) {m_what = s;} + /// \brief Retrieves the error type for the exception + ErrorType GetErrorType() const {return m_errorType;} + /// \brief Sets the error type for the exceptions + void SetErrorType(ErrorType errorType) {m_errorType = errorType;} + +private: + ErrorType m_errorType; + std::string m_what; +}; + +/// \brief An invalid argument was detected +class CRYPTOPP_DLL InvalidArgument : public Exception +{ +public: + explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {} +}; + +/// \brief Input data was received that did not conform to expected format +class CRYPTOPP_DLL InvalidDataFormat : public Exception +{ +public: + explicit InvalidDataFormat(const std::string &s) : Exception(INVALID_DATA_FORMAT, s) {} +}; + +/// \brief A decryption filter encountered invalid ciphertext +class CRYPTOPP_DLL InvalidCiphertext : public InvalidDataFormat +{ +public: + explicit InvalidCiphertext(const std::string &s) : InvalidDataFormat(s) {} +}; + +/// \brief A method was called which was not implemented +class CRYPTOPP_DLL NotImplemented : public Exception +{ +public: + explicit NotImplemented(const std::string &s) : Exception(NOT_IMPLEMENTED, s) {} +}; + +/// \brief Flush(true) was called but it can't completely flush its buffers +class CRYPTOPP_DLL CannotFlush : public Exception +{ +public: + explicit CannotFlush(const std::string &s) : Exception(CANNOT_FLUSH, s) {} +}; + +/// \brief The operating system reported an error +class CRYPTOPP_DLL OS_Error : public Exception +{ +public: + virtual ~OS_Error() throw() {} + OS_Error(ErrorType errorType, const std::string &s, const std::string& operation, int errorCode) + : Exception(errorType, s), m_operation(operation), m_errorCode(errorCode) {} + + /// \brief Retrieve the operating system API that reported the error + const std::string & GetOperation() const {return m_operation;} + /// \brief Retrieve the error code returned by the operating system + int GetErrorCode() const {return m_errorCode;} + +protected: + std::string m_operation; + int m_errorCode; +}; + +/// \brief Returns a decoding results +struct CRYPTOPP_DLL DecodingResult +{ + /// \brief Constructs a DecodingResult + /// \details isValidCoding is initialized to false and messageLength is initialized to 0. + explicit DecodingResult() : isValidCoding(false), messageLength(0) {} + /// \brief Constructs a DecodingResult + /// \param len the message length + /// \details isValidCoding is initialized to true. + explicit DecodingResult(size_t len) : isValidCoding(true), messageLength(len) {} + + /// \brief Compare two DecodingResult + /// \param rhs the other DecodingResult + /// \return true if both isValidCoding and messageLength are equal, false otherwise + bool operator==(const DecodingResult &rhs) const {return isValidCoding == rhs.isValidCoding && messageLength == rhs.messageLength;} + /// \brief Compare two DecodingResult + /// \param rhs the other DecodingResult + /// \return true if either isValidCoding or messageLength is \a not equal, false otherwise + /// \details Returns !operator==(rhs). + bool operator!=(const DecodingResult &rhs) const {return !operator==(rhs);} + + /// \brief Flag to indicate the decoding is valid + bool isValidCoding; + /// \brief Recovered message length if isValidCoding is true, undefined otherwise + size_t messageLength; +}; + +/// \brief Interface for retrieving values given their names +/// \details This class is used to safely pass a variable number of arbitrarily typed arguments to functions +/// and to read values from keys and crypto parameters. +/// \details To obtain an object that implements NameValuePairs for the purpose of parameter +/// passing, use the MakeParameters() function. +/// \details To get a value from NameValuePairs, you need to know the name and the type of the value. +/// Call GetValueNames() on a NameValuePairs object to obtain a list of value names that it supports. +/// then look at the Name namespace documentation to see what the type of each value is, or +/// alternatively, call GetIntValue() with the value name, and if the type is not int, a +/// ValueTypeMismatch exception will be thrown and you can get the actual type from the exception object. +/// \sa NullNameValuePairs, g_nullNameValuePairs, +/// NameValuePairs on the Crypto++ wiki +class NameValuePairs +{ +public: + virtual ~NameValuePairs() {} + + /// \brief Thrown when an unexpected type is encountered + /// \details Exception thrown when trying to retrieve a value using a different type than expected + class CRYPTOPP_DLL ValueTypeMismatch : public InvalidArgument + { + public: + /// \brief Construct a ValueTypeMismatch + /// \param name the name of the value + /// \param stored the \a actual type of the value stored + /// \param retrieving the \a presumed type of the value retrieved + ValueTypeMismatch(const std::string &name, const std::type_info &stored, const std::type_info &retrieving) + : InvalidArgument("NameValuePairs: type mismatch for '" + name + "', stored '" + stored.name() + "', trying to retrieve '" + retrieving.name() + "'") + , m_stored(stored), m_retrieving(retrieving) {} + + /// \brief Provides the stored type + /// \return the C++ mangled name of the type + const std::type_info & GetStoredTypeInfo() const {return m_stored;} + + /// \brief Provides the retrieveing type + /// \return the C++ mangled name of the type + const std::type_info & GetRetrievingTypeInfo() const {return m_retrieving;} + + private: + const std::type_info &m_stored; + const std::type_info &m_retrieving; + }; + + /// \brief Get a copy of this object or subobject + /// \tparam T class or type + /// \param object reference to a variable that receives the value + template + bool GetThisObject(T &object) const + { + return GetValue((std::string("ThisObject:")+typeid(T).name()).c_str(), object); + } + + /// \brief Get a pointer to this object + /// \tparam T class or type + /// \param ptr reference to a pointer to a variable that receives the value + template + bool GetThisPointer(T *&ptr) const + { + return GetValue((std::string("ThisPointer:")+typeid(T).name()).c_str(), ptr); + } + + /// \brief Get a named value + /// \tparam T class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \returns true if the value was retrieved, false otherwise + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + bool GetValue(const char *name, T &value) const + { + return GetVoidValue(name, typeid(T), &value); + } + + /// \brief Get a named value + /// \tparam T class or type + /// \param name the name of the object or value to retrieve + /// \param defaultValue the default value of the class or type if it does not exist + /// \return the object or value + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + T GetValueWithDefault(const char *name, T defaultValue) const + { + T value; + bool result = GetValue(name, value); + // No assert... this recovers from failure + if (result) {return value;} + return defaultValue; + } + + /// \brief Get a list of value names that can be retrieved + /// \return a list of names available to retrieve + /// \details the items in the list are delimited with a colon. + CRYPTOPP_DLL std::string GetValueNames() const + {std::string result; GetValue("ValueNames", result); return result;} + + /// \brief Get a named value with type int + /// \param name the name of the value to retrieve + /// \param value the value retrieved upon success + /// \return true if an int value was retrieved, false otherwise + /// \details GetIntValue() is used to ensure we don't accidentally try to get an + /// unsigned int or some other type when we mean int (which is the most common case) + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL bool GetIntValue(const char *name, int &value) const + {return GetValue(name, value);} + + /// \brief Get a named value with type int, with default + /// \param name the name of the value to retrieve + /// \param defaultValue the default value if the name does not exist + /// \return the value retrieved on success or the default value + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL int GetIntValueWithDefault(const char *name, int defaultValue) const + {return GetValueWithDefault(name, defaultValue);} + + /// \brief Ensures an expected name and type is present + /// \param name the name of the value + /// \param stored the type that was stored for the name + /// \param retrieving the type that is being retrieved for the name + /// \throws ValueTypeMismatch + /// \details ThrowIfTypeMismatch() effectively performs a type safety check. + /// stored and retrieving are C++ mangled names for the type. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL static void CRYPTOPP_API ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving) + {if (stored != retrieving) throw ValueTypeMismatch(name, stored, retrieving);} + + /// \brief Retrieves a required name/value pair + /// \tparam T class or type + /// \param className the name of the class + /// \param name the name of the value + /// \param value reference to a variable to receive the value + /// \throws InvalidArgument + /// \details GetRequiredParameter() throws InvalidArgument if the name + /// is not present or not of the expected type T. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + void GetRequiredParameter(const char *className, const char *name, T &value) const + { + if (!GetValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + /// \brief Retrieves a required name/value pair + /// \param className the name of the class + /// \param name the name of the value + /// \param value reference to a variable to receive the value + /// \throws InvalidArgument + /// \details GetRequiredParameter() throws InvalidArgument if the name + /// is not present or not of the expected type T. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL void GetRequiredIntParameter(const char *className, const char *name, int &value) const + { + if (!GetIntValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \returns true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const =0; +}; + +/// \brief Interface for retrieving values given their names +/// \details This class is used when no names or values are present. Typically a program uses +/// g_nullNameValuePairs rather than creating its own NullNameValuePairs object. +/// \details NullNameValuePairs always existed in cryptlib.cpp. Crypto++ 6.0 moved NullNameValuePairs +/// into the header. This allowed the library to define g_nullNameValuePairs in the header rather +/// than declaring it as extern and placing the definition in the source file. As an external definition +/// the string g_nullNameValuePairs was subject to static initialization order fiasco problems. +/// \sa NameValuePairs, g_nullNameValuePairs, +/// NameValuePairs on the Crypto++ wiki +class NullNameValuePairs : public NameValuePairs +{ +public: + NullNameValuePairs() {} // Clang complains a default ctor must be avilable + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + {CRYPTOPP_UNUSED(name); CRYPTOPP_UNUSED(valueType); CRYPTOPP_UNUSED(pValue); return false;} +}; + +// More static initialization order fiasco workarounds. These definitions cannot be extern and +// cannot be static class members because they require a single definition in a source file. +// User programs should use g_nullNameValuePairs rather than s_nullNameValuePairs. +static const NullNameValuePairs s_nullNameValuePairs; + +// Doxygen cannot handle initialization +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Default channel for BufferedTransformation +/// \details DEFAULT_CHANNEL is equal to an empty string +/// \details Crypto++ 6.0 placed DEFAULT_CHANNEL in the header, rather than declaring it as extern and +/// placing the definition in the source file. As an external definition the string DEFAULT_CHANNEL +/// was subject to static initialization order fiasco problems. +const std::string DEFAULT_CHANNEL; + +/// \brief Channel for additional authenticated data +/// \details AAD_CHANNEL is equal to "AAD" +/// \details Crypto++ 6.0 placed AAD_CHANNEL in the header, rather than declaring it as extern and +/// placing the definition in the source file. As an external definition the string AAD_CHANNEL +/// was subject to static initialization order fiasco problems. +const std::string AAD_CHANNEL; + +/// \brief An empty set of name-value pairs +/// \details Crypto++ 6.0 placed g_nullNameValuePairs in the header, rather than declaring it as extern +/// and placing the definition in the source file. As an external definition the g_nullNameValuePairs +/// was subject to static initialization order fiasco problems. +const NameValuePairs g_nullNameValuePairs; + +// Sun Studio 12.3 and earlier can't handle NameValuePairs initialization +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130) +static const std::string DEFAULT_CHANNEL; +static const std::string AAD_CHANNEL = "AAD"; +static const NameValuePairs& g_nullNameValuePairs = s_nullNameValuePairs; + +// We don't really want static here since it detracts from public symbol visibility, but the Windows +// DLL fails to compile when the symbols are only const. Apparently Microsoft compilers don't treat +// const the same as static in a translation unit for visibility under C++. +#else +static const std::string DEFAULT_CHANNEL; +static const std::string AAD_CHANNEL("AAD"); +static const NameValuePairs& g_nullNameValuePairs(s_nullNameValuePairs); +#endif + +// Document additional name spaces which show up elsewhere in the sources. +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Namespace containing value name definitions. +/// \details Name is part of the CryptoPP namespace. +/// \details The semantics of value names, types are: +///

+///     ThisObject:ClassName (ClassName, copy of this object or a subobject)
+///     ThisPointer:ClassName (const ClassName *, pointer to this object or a subobject)
+/// 
+DOCUMENTED_NAMESPACE_BEGIN(Name) +// more names defined in argnames.h +DOCUMENTED_NAMESPACE_END + +/// \brief Namespace containing weak and wounded algorithms. +/// \details Weak is part of the CryptoPP namespace. Schemes and algorithms are moved into Weak +/// when their security level is reduced to an unacceptable level by contemporary standards. +/// \details To use an algorithm in the Weak namespace, you must \c \#define +/// CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 before including a header for a weak or wounded +/// algorithm. For example: +///
+///     \c \#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
+///     \c \#include 
+///     ...
+///     CryptoPP::Weak::MD5 md5;
+///   
+DOCUMENTED_NAMESPACE_BEGIN(Weak) +// weak and wounded algorithms +DOCUMENTED_NAMESPACE_END +#endif + +/// \brief Namespace containing NaCl library functions +/// \details TweetNaCl is a compact and portable reimplementation of the NaCl library. +DOCUMENTED_NAMESPACE_BEGIN(NaCl) +// crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open (and friends) +DOCUMENTED_NAMESPACE_END + +/// \brief Namespace containing testing and benchmark classes. +/// \details Source files for classes in the Test namespaces include +/// test.cpp, validat#.cpp and bench#.cpp. +DOCUMENTED_NAMESPACE_BEGIN(Test) +// testing and benchmark classes +DOCUMENTED_NAMESPACE_END + +// ******************************************************** + +/// \brief Interface for cloning objects +/// \note this is \a not implemented by most classes +/// \sa ClonableImpl, NotCopyable +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Clonable +{ +public: + virtual ~Clonable() {} + + /// \brief Copies this object + /// \return a copy of this object + /// \throws NotImplemented + /// \note this is \a not implemented by most classes + /// \sa NotCopyable + virtual Clonable* Clone() const {throw NotImplemented("Clone() is not implemented yet.");} // TODO: make this =0 +}; + +/// \brief Interface for all crypto algorithms +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Algorithm : public Clonable +{ +public: + virtual ~Algorithm() {} + + /// \brief Interface for all crypto algorithms + /// \param checkSelfTestStatus determines whether the object can proceed if the self + /// tests have not been run or failed. + /// \details When FIPS 140-2 compliance is enabled and checkSelfTestStatus == true, + /// this constructor throws SelfTestFailure if the self test hasn't been run or fails. + /// \details FIPS 140-2 compliance is disabled by default. It is only used by certain + /// versions of the library when the library is built as a DLL on Windows. Also see + /// CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 in config.h. + Algorithm(bool checkSelfTestStatus = true); + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + /// \note AlgorithmName is not universally implemented yet + virtual std::string AlgorithmName() const {return "unknown";} +}; + +/// \brief Interface for algorithms that take byte strings as keys +/// \sa FixedKeyLength(), VariableKeyLength(), SameKeyLengthAs(), SimpleKeyingInterfaceImpl() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyingInterface +{ +public: + virtual ~SimpleKeyingInterface() {} + + /// \brief Returns smallest valid key length + /// \returns the minimum key length, in bytes + virtual size_t MinKeyLength() const =0; + /// \brief Returns largest valid key length + /// \returns the maximum key length, in bytes + virtual size_t MaxKeyLength() const =0; + /// \brief Returns default key length + /// \returns the default (recommended) key length, in bytes + virtual size_t DefaultKeyLength() const =0; + + /// \brief Returns a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \returns the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + virtual size_t GetValidKeyLength(size_t keylength) const =0; + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + virtual bool IsValidKeyLength(size_t keylength) const + {return keylength == GetValidKeyLength(keylength);} + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param params additional initialization parameters to configure this object + virtual void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param rounds the number of rounds to apply the transformation function, + /// if applicable + /// \details SetKeyWithRounds() calls SetKey() with a NameValuePairs + /// object that only specifies rounds. rounds is an integer parameter, + /// and -1 means use the default number of rounds. + void SetKeyWithRounds(const byte *key, size_t length, int rounds); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param iv the intiialization vector to use when keying the object + /// \param ivLength the size of the iv, in bytes + /// \details SetKeyWithIV() calls SetKey() with a NameValuePairs + /// that only specifies IV. The IV is a byte buffer with size ivLength. + /// ivLength is an integer parameter, and -1 means use IVSize(). + void SetKeyWithIV(const byte *key, size_t length, const byte *iv, size_t ivLength); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param iv the intiialization vector to use when keying the object + /// \details SetKeyWithIV() calls SetKey() with a NameValuePairs() object + /// that only specifies iv. iv is a byte buffer, and it must have + /// a size IVSize(). + void SetKeyWithIV(const byte *key, size_t length, const byte *iv) + {SetKeyWithIV(key, length, iv, IVSize());} + + /// \brief Secure IVs requirements as enumerated values. + /// \details Provides secure IV requirements as a monotonically increasing enumerated values. Requirements can be + /// compared using less than (<) and greater than (>). For example, UNIQUE_IV < RANDOM_IV + /// and UNPREDICTABLE_RANDOM_IV > RANDOM_IV. + /// \sa IsResynchronizable(), CanUseRandomIVs(), CanUsePredictableIVs(), CanUseStructuredIVs() + enum IV_Requirement { + /// \brief The IV must be unique + UNIQUE_IV = 0, + /// \brief The IV must be random and possibly predictable + RANDOM_IV, + /// \brief The IV must be random and unpredictable + UNPREDICTABLE_RANDOM_IV, + /// \brief The IV is set by the object + INTERNALLY_GENERATED_IV, + /// \brief The object does not use an IV + NOT_RESYNCHRONIZABLE + }; + + /// \brief Minimal requirement for secure IVs + /// \return the secure IV requirement of the algorithm + virtual IV_Requirement IVRequirement() const =0; + + /// \brief Determines if the object can be resynchronized + /// \return true if the object can be resynchronized (i.e. supports initialization vectors), false otherwise + /// \note If this function returns true, and no IV is passed to SetKey() and CanUseStructuredIVs()==true, + /// an IV of all 0's will be assumed. + bool IsResynchronizable() const {return IVRequirement() < NOT_RESYNCHRONIZABLE;} + + /// \brief Determines if the object can use random IVs + /// \return true if the object can use random IVs (in addition to ones returned by GetNextIV), false otherwise + bool CanUseRandomIVs() const {return IVRequirement() <= UNPREDICTABLE_RANDOM_IV;} + + /// \brief Determines if the object can use random but possibly predictable IVs + /// \return true if the object can use random but possibly predictable IVs (in addition to ones returned by + /// GetNextIV), false otherwise + bool CanUsePredictableIVs() const {return IVRequirement() <= RANDOM_IV;} + + /// \brief Determines if the object can use structured IVs + /// \returns true if the object can use structured IVs, false otherwise + /// \details CanUseStructuredIVs() indicates whether the object can use structured IVs; for example a counter + /// (in addition to ones returned by GetNextIV). + bool CanUseStructuredIVs() const {return IVRequirement() <= UNIQUE_IV;} + + /// \brief Returns length of the IV accepted by this object + /// \return the size of an IV, in bytes + /// \throws NotImplemented() if the object does not support resynchronization + /// \details The default implementation throws NotImplemented + virtual unsigned int IVSize() const + {throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");} + + /// \brief Provides the default size of an IV + /// \return default length of IVs accepted by this object, in bytes + unsigned int DefaultIVLength() const {return IVSize();} + + /// \brief Provides the minimum size of an IV + /// \return minimal length of IVs accepted by this object, in bytes + /// \throws NotImplemented() if the object does not support resynchronization + virtual unsigned int MinIVLength() const {return IVSize();} + + /// \brief Provides the maximum size of an IV + /// \return maximal length of IVs accepted by this object, in bytes + /// \throws NotImplemented() if the object does not support resynchronization + virtual unsigned int MaxIVLength() const {return IVSize();} + + /// \brief Resynchronize with an IV + /// \param iv the initialization vector + /// \param ivLength the size of the initialization vector, in bytes + /// \details Resynchronize() resynchronizes with an IV provided by the caller. ivLength=-1 means use IVSize(). + /// \throws NotImplemented() if the object does not support resynchronization + virtual void Resynchronize(const byte *iv, int ivLength=-1) { + CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(ivLength); + throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization"); + } + + /// \brief Retrieves a secure IV for the next message + /// \param rng a RandomNumberGenerator to produce keying material + /// \param iv a block of bytes to receive the IV + /// \details The IV must be at least IVSize() in length. + /// \details This method should be called after you finish encrypting one message and are ready + /// to start the next one. After calling it, you must call SetKey() or Resynchronize(). + /// before using this object again. + /// \details Internally, the base class implementation calls RandomNumberGenerator's GenerateBlock() + /// \note This method is not implemented on decryption objects. + virtual void GetNextIV(RandomNumberGenerator &rng, byte *iv); + +protected: + /// \brief Returns the base class Algorithm + /// \return the base class Algorithm + virtual const Algorithm & GetAlgorithm() const =0; + + /// \brief Sets the key for this object without performing parameter validation + /// \param key a byte buffer used to key the cipher + /// \param length the length of the byte buffer + /// \param params additional parameters passed as NameValuePairs + /// \details key must be at least DEFAULT_KEYLENGTH in length. + virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) =0; + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + /// \throws InvalidKeyLength if the key length is invalid + void ThrowIfInvalidKeyLength(size_t length); + + /// \brief Validates the object + /// \throws InvalidArgument if the IV is present + /// \details Internally, the default implementation calls IsResynchronizable() and throws + /// InvalidArgument if the function returns true. + /// \note called when no IV is passed + void ThrowIfResynchronizable(); + + /// \brief Validates the IV + /// \param iv the IV with a length of IVSize, in bytes + /// \throws InvalidArgument on failure + /// \details Internally, the default implementation checks the iv. If iv is not NULL or nullptr, + /// then the function succeeds. If iv is NULL, then IVRequirement is checked against + /// UNPREDICTABLE_RANDOM_IV. If IVRequirement is UNPREDICTABLE_RANDOM_IV, then + /// then the function succeeds. Otherwise, an exception is thrown. + void ThrowIfInvalidIV(const byte *iv); + + /// \brief Validates the IV length + /// \param length the size of an IV, in bytes + /// \throws InvalidArgument if the IV length is invalid + size_t ThrowIfInvalidIVLength(int length); + + /// \brief Retrieves and validates the IV + /// \param params NameValuePairs with the IV supplied as a ConstByteArrayParameter + /// \param size the length of the IV, in bytes + /// \return a pointer to the first byte of the IV + /// \throws InvalidArgument if the number of rounds are invalid + const byte * GetIVAndThrowIfInvalid(const NameValuePairs ¶ms, size_t &size); + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + inline void AssertValidKeyLength(size_t length) const + {CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(IsValidKeyLength(length));} +}; + +/// \brief Interface for the data processing part of block ciphers +/// \details Classes derived from BlockTransformation are block ciphers +/// in ECB mode (for example the DES::Encryption class), which are stateless. +/// These classes should not be used directly, but only in combination with +/// a mode class (see CipherModeDocumentation in modes.h). +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockTransformation : public Algorithm +{ +public: + virtual ~BlockTransformation() {} + + /// \brief Encrypt or decrypt a block + /// \param inBlock the input message before processing + /// \param outBlock the output message after processing + /// \param xorBlock an optional XOR mask + /// \details ProcessAndXorBlock encrypts or decrypts inBlock, xor with xorBlock, and write to outBlock. + /// \details The size of the block is determined by the block cipher and its documentation. Use + /// BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \note The message can be transformed in-place, or the buffers must \a not overlap + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + virtual void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const =0; + + /// \brief Encrypt or decrypt a block + /// \param inBlock the input message before processing + /// \param outBlock the output message after processing + /// \details ProcessBlock encrypts or decrypts inBlock and write to outBlock. + /// \details The size of the block is determined by the block cipher and its documentation. + /// Use BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + /// \note The message can be transformed in-place, or the buffers must \a not overlap + void ProcessBlock(const byte *inBlock, byte *outBlock) const + {ProcessAndXorBlock(inBlock, NULLPTR, outBlock);} + + /// \brief Encrypt or decrypt a block in place + /// \param inoutBlock the input message before processing + /// \details ProcessBlock encrypts or decrypts inoutBlock in-place. + /// \details The size of the block is determined by the block cipher and its documentation. + /// Use BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + void ProcessBlock(byte *inoutBlock) const + {ProcessAndXorBlock(inoutBlock, NULLPTR, inoutBlock);} + + /// Provides the block size of the cipher + /// \return the block size of the cipher, in bytes + virtual unsigned int BlockSize() const =0; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Determines if the transformation is a permutation + /// \returns true if this is a permutation (i.e. there is an inverse transformation) + virtual bool IsPermutation() const {return true;} + + /// \brief Determines if the cipher is being operated in its forward direction + /// \returns true if DIR is ENCRYPTION, false otherwise + /// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection() + virtual bool IsForwardTransformation() const =0; + + /// \brief Determines the number of blocks that can be processed in parallel + /// \return the number of blocks that can be processed in parallel, for bit-slicing implementations + /// \details Bit-slicing is often used to improve throughput and minimize timing attacks. + virtual unsigned int OptimalNumberOfParallelBlocks() const {return 1;} + + /// \brief Bit flags that control AdvancedProcessBlocks() behavior + enum FlagsForAdvancedProcessBlocks { + /// \brief inBlock is a counter + BT_InBlockIsCounter=1, + /// \brief should not modify block pointers + BT_DontIncrementInOutPointers=2, + /// \brief Xor inputs before transformation + BT_XorInput=4, + /// \brief perform the transformation in reverse + BT_ReverseDirection=8, + /// \brief Allow parallel transformations + BT_AllowParallel=16}; + + /// \brief Encrypt and xor multiple blocks using additional flags + /// \param inBlocks the input message before processing + /// \param xorBlocks an optional XOR mask + /// \param outBlocks the output message after processing + /// \param length the size of the blocks, in bytes + /// \param flags additional flags to control processing + /// \details Encrypt and xor multiple blocks according to FlagsForAdvancedProcessBlocks flags. + /// \note If BT_InBlockIsCounter is set, then the last byte of inBlocks may be modified. + virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; + + /// \brief Provides the direction of the cipher + /// \return ENCRYPTION if IsForwardTransformation() is true, DECRYPTION otherwise + /// \sa IsForwardTransformation(), IsPermutation() + inline CipherDir GetCipherDirection() const {return IsForwardTransformation() ? ENCRYPTION : DECRYPTION;} +}; + +/// \brief Interface for the data processing portion of stream ciphers +/// \sa StreamTransformationFilter() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE StreamTransformation : public Algorithm +{ +public: + virtual ~StreamTransformation() {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + StreamTransformation& Ref() {return *this;} + + /// \brief Provides the mandatory block size of the cipher + /// \return The block size of the cipher if input must be processed in blocks, 1 otherwise + /// \details Stream ciphers and some block ciphers modes of operation return 1. Modes that + /// return 1 must be able to process a single byte at a time, like counter mode. If a + /// mode of operation or block cipher cannot stream then it must not return 1. + /// \details When filters operate the mode or cipher, ProcessData will be called with a + /// string of bytes that is determined by MandatoryBlockSize and OptimalBlockSize. When a + /// policy is set, like 16-byte strings for a 16-byte block cipher, the filter will buffer + /// bytes until the specified number of bytes is available to the object. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual unsigned int MandatoryBlockSize() const {return 1;} + + /// \brief Provides the input block size most efficient for this cipher + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + virtual unsigned int OptimalBlockSize() const {return MandatoryBlockSize();} + + /// \brief Provides the number of bytes used in the current block when processing at optimal block size. + /// \return the number of bytes used in the current block when processing at the optimal block size + virtual unsigned int GetOptimalBlockSizeUsed() const {return 0;} + + /// \brief Provides input and output data alignment for optimal performance + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Encrypt or decrypt an array of bytes + /// \param outString the output byte buffer + /// \param inString the input byte buffer + /// \param length the size of the input and output byte buffers, in bytes + /// \details ProcessData is called with a string of bytes whose size depends on MandatoryBlockSize. + /// Either inString == outString, or they must not overlap. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual void ProcessData(byte *outString, const byte *inString, size_t length) =0; + + /// \brief Encrypt or decrypt the last block of data + /// \param outString the output byte buffer + /// \param outLength the size of the output byte buffer, in bytes + /// \param inString the input byte buffer + /// \param inLength the size of the input byte buffer, in bytes + /// \returns the number of bytes used in outString + /// \details ProcessLastBlock is used when the last block of data is special and requires handling + /// by the cipher. The current implementation provides an output buffer with a size + /// inLength+2*MandatoryBlockSize(). The return value allows the cipher to expand cipher + /// text during encryption or shrink plain text during decryption. + /// \details This member function is used by CBC-CTS and OCB modes. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + /// \brief Provides the size of the last block + /// \returns the minimum size of the last block + /// \details MinLastBlockSize() returns the minimum size of the last block. 0 indicates the last + /// block is not special. + /// \details MandatoryBlockSize() enlists one of two behaviors. First, if MandatoryBlockSize() + /// returns 1, then the cipher can be streamed and ProcessData() is called with the tail bytes. + /// Second, if MandatoryBlockSize() returns non-0, then the string of bytes is padded to + /// MandatoryBlockSize() according to the padding mode. Then, ProcessData() is called with the + /// padded string of bytes. + /// \details Some authenticated encryption modes are not expressed well with MandatoryBlockSize() + /// and MinLastBlockSize(). For example, AES/OCB uses 16-byte blocks (MandatoryBlockSize = 16) + /// and the last block requires special processing (MinLastBlockSize = 0). However, 0 is a valid + /// last block size for OCB and the special processing is custom padding, and not standard PKCS + /// padding. In response an unambiguous IsLastBlockSpecial() was added. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual unsigned int MinLastBlockSize() const {return 0;} + + /// \brief Determines if the last block receives special processing + /// \returns true if the last block reveives special processing, false otherwise. + /// \details Some authenticated encryption modes are not expressed well with + /// MandatoryBlockSize() and MinLastBlockSize(). For example, AES/OCB uses + /// 16-byte blocks (MandatoryBlockSize = 16) and the last block requires special processing + /// (MinLastBlockSize = 0). However, 0 is a valid last block size for OCB and the special + /// processing is custom padding, and not standard PKCS padding. In response an + /// unambiguous IsLastBlockSpecial() was added. + /// \details When IsLastBlockSpecial() returns false nothing special happens. All the former + /// rules and behaviors apply. This is the default behavior of IsLastBlockSpecial(). + /// \details When IsLastBlockSpecial() returns true four things happen. First, MinLastBlockSize = 0 + /// means 0 is a valid block size that should be processed. Second, standard block cipher padding is + /// \a not \a applied. Third, the caller supplies an outString is larger than inString by + /// 2*MandatoryBlockSize(). That is, there's a reserve available when processing the last block. + /// Fourth, the cipher is responsible for finalization like custom padding. The cipher will tell + /// the library how many bytes were processed or used by returning the appropriate value from + /// ProcessLastBlock(). + /// \details The return value of ProcessLastBlock() indicates how many bytes were written to + /// outString. A filter pipelining data will send outString and up to outLength + /// to an AttachedTransformation() for additional processing. Below is an example of the code + /// used in StreamTransformationFilter::LastPut. + ///
  if (m_cipher.IsLastBlockSpecial())
+	///   {
+	///     size_t reserve = 2*m_cipher.MandatoryBlockSize();
+	///     space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length+reserve);
+	///     length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
+	///     AttachedTransformation()->Put(space, length);
+	///     return;
+	///   }
+ /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + /// \since Crypto++ 6.0 + virtual bool IsLastBlockSpecial() const {return false;} + + /// \brief Encrypt or decrypt a string of bytes + /// \param inoutString the string to process + /// \param length the size of the inoutString, in bytes + /// \details Internally, the base class implementation calls ProcessData(). + inline void ProcessString(byte *inoutString, size_t length) + {ProcessData(inoutString, inoutString, length);} + + /// \brief Encrypt or decrypt a string of bytes + /// \param outString the output string to process + /// \param inString the input string to process + /// \param length the size of the input and output strings, in bytes + /// \details Internally, the base class implementation calls ProcessData(). + inline void ProcessString(byte *outString, const byte *inString, size_t length) + {ProcessData(outString, inString, length);} + + /// \brief Encrypt or decrypt a byte + /// \param input the input byte to process + /// \details Internally, the base class implementation calls ProcessData() with a size of 1. + inline byte ProcessByte(byte input) + {ProcessData(&input, &input, 1); return input;} + + /// \brief Determines whether the cipher supports random access + /// \returns true if the cipher supports random access, false otherwise + virtual bool IsRandomAccess() const =0; + + /// \brief Seek to an absolute position + /// \param pos position to seek + /// \throws NotImplemented + /// \details The base class implementation throws NotImplemented. The function + /// \ref CRYPTOPP_ASSERT "asserts" IsRandomAccess() in debug builds. + virtual void Seek(lword pos) + { + CRYPTOPP_UNUSED(pos); + CRYPTOPP_ASSERT(!IsRandomAccess()); + throw NotImplemented("StreamTransformation: this object doesn't support random access"); + } + + /// \brief Determines whether the cipher is self-inverting + /// \returns true if the cipher is self-inverting, false otherwise + /// \details IsSelfInverting determines whether this transformation is + /// self-inverting (e.g. xor with a keystream). + virtual bool IsSelfInverting() const =0; + + /// \brief Determines if the cipher is being operated in its forward direction + /// \returns true if DIR is ENCRYPTION, false otherwise + /// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection() + virtual bool IsForwardTransformation() const =0; +}; + +/// \brief Interface for hash functions and data processing part of MACs +/// \details HashTransformation objects are stateful. They are created in an initial state, +/// change state as Update() is called, and return to the initial +/// state when Final() is called. This interface allows a large message to +/// be hashed in pieces by calling Update() on each piece followed by +/// calling Final(). +/// \sa HashFilter(), HashVerificationFilter() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HashTransformation : public Algorithm +{ +public: + virtual ~HashTransformation() {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + HashTransformation& Ref() {return *this;} + + /// \brief Updates a hash with additional input + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + virtual void Update(const byte *input, size_t length) =0; + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL or nullptr. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. + virtual byte * CreateUpdateSpace(size_t &size) {size=0; return NULLPTR;} + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \details Final() restarts the hash for a new message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual void Final(byte *digest) + {TruncatedFinal(digest, DigestSize());} + + /// \brief Restart the hash + /// \details Discards the current state, and restart for a new message + virtual void Restart() + {TruncatedFinal(NULLPTR, 0);} + + /// Provides the digest size of the hash + /// \return the digest size of the hash. + virtual unsigned int DigestSize() const =0; + + /// Provides the tag size of the hash + /// \return the tag size of the hash. + /// \details Same as DigestSize(). + unsigned int TagSize() const {return DigestSize();} + + /// \brief Provides the block size of the compression function + /// \return the block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based. For example, + /// SHA3 is a recursive hash (not an iterative hash), and it does not have a block size. + virtual unsigned int BlockSize() const {return 0;} + + /// \brief Provides the input block size most efficient for this hash. + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \details Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + virtual unsigned int OptimalBlockSize() const {return 1;} + + /// \brief Provides input and output data alignment for optimal performance + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Updates the hash with additional input and computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and Final() separately + /// \details CalculateDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual void CalculateDigest(byte *digest, const byte *input, size_t length) + {Update(input, length); Final(digest);} + + /// \brief Verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throws ThrowIfInvalidTruncatedSize() if the existing hash's size exceeds DigestSize() + /// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is + /// a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details Verify() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual bool Verify(const byte *digest) + {return TruncatedVerify(digest, DigestSize());} + + /// \brief Updates the hash with additional input and verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throws ThrowIfInvalidTruncatedSize() if the existing hash's size exceeds DigestSize() + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and Verify() separately + /// \details VerifyDigest() performs a bitwise compare on the buffers using VerifyBufsEqual(), + /// which is a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details VerifyDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual bool VerifyDigest(const byte *digest, const byte *input, size_t length) + {Update(input, length); return Verify(digest);} + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() call Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + virtual void TruncatedFinal(byte *digest, size_t digestSize) =0; + + /// \brief Updates the hash with additional input and computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the length of the truncated hash, in bytes + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and CalculateDigest() separately. + /// \details CalculateTruncatedDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual void CalculateTruncatedDigest(byte *digest, size_t digestSize, const byte *input, size_t length) + {Update(input, length); TruncatedFinal(digest, digestSize);} + + /// \brief Verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param digestLength the size of the truncated hash, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throws ThrowIfInvalidTruncatedSize() if digestLength exceeds DigestSize() + /// \details TruncatedVerify() is a truncated version of Verify(). It can operate on a + /// buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize(). + /// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is + /// a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details TruncatedVerify() restarts the hash for the next message. + virtual bool TruncatedVerify(const byte *digest, size_t digestLength); + + /// \brief Updates the hash with additional input and verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param digestLength the size of the truncated hash, in bytes + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throws ThrowIfInvalidTruncatedSize() if digestLength exceeds DigestSize() + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and TruncatedVerify() separately. + /// \details VerifyTruncatedDigest() is a truncated version of VerifyDigest(). It can operate + /// on a buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize(). + /// \details VerifyTruncatedDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual bool VerifyTruncatedDigest(const byte *digest, size_t digestLength, const byte *input, size_t length) + {Update(input, length); return TruncatedVerify(digest, digestLength);} + +protected: + /// \brief Validates a truncated digest size + /// \param size the requested digest size + /// \throws InvalidArgument if the algorithm's digest size cannot be truncated to the requested size + /// \details Throws an exception when the truncated digest size is greater than DigestSize() + void ThrowIfInvalidTruncatedSize(size_t size) const; +}; + +/// \brief Interface for one direction (encryption or decryption) of a block cipher +/// \details These objects usually should not be used directly. See BlockTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockCipher : public SimpleKeyingInterface, public BlockTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for one direction (encryption or decryption) of a stream cipher or cipher mode +/// \details These objects usually should not be used directly. See StreamTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SymmetricCipher : public SimpleKeyingInterface, public StreamTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for message authentication codes +/// \details These objects usually should not be used directly. See HashTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE MessageAuthenticationCode : public SimpleKeyingInterface, public HashTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for authenticated encryption modes of operation +/// \details AuthenticatedSymmetricCipher() provides the interface for one direction +/// (encryption or decryption) of a stream cipher or block cipher mode with authentication. The +/// StreamTransformation() part of this interface is used to encrypt or decrypt the data. The +/// MessageAuthenticationCode() part of the interface is used to input additional authenticated +/// data (AAD), which is MAC'ed but not encrypted. The MessageAuthenticationCode() part is also +/// used to generate and verify the MAC. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes implement AuthenticatedSymmetricCipher() and the motivation for +/// the API, like calling AAD a "header", can be found in Bellare, Rogaway and +/// Wagner's The EAX Mode of +/// Operation. The EAX paper suggested a basic API to help standardize AEAD schemes in +/// software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipher : public MessageAuthenticationCode, public StreamTransformation +{ +public: + virtual ~AuthenticatedSymmetricCipher() {} + + /// \brief Exception thrown when the object is in the wrong state for the operation + /// \details this indicates that a member function was called in the wrong state, for example trying to encrypt + /// a message before having set the key or IV + class BadState : public Exception + { + public: + explicit BadState(const std::string &name, const char *message) : Exception(OTHER_ERROR, name + ": " + message) {} + explicit BadState(const std::string &name, const char *function, const char *state) : Exception(OTHER_ERROR, name + ": " + function + " was called before " + state) {} + }; + + /// \brief Provides the maximum length of AAD that can be input + /// \return the maximum length of AAD that can be input before the encrypted data + virtual lword MaxHeaderLength() const =0; + /// \brief Provides the maximum length of encrypted data + /// \return the maximum length of encrypted data + virtual lword MaxMessageLength() const =0; + /// \brief Provides the the maximum length of AAD + /// \return the maximum length of AAD that can be input after the encrypted data + virtual lword MaxFooterLength() const {return 0;} + /// \brief Determines if data lengths must be specified prior to inputting data + /// \return true if the data lengths are required before inputting data, false otherwise + /// \details if this function returns true, SpecifyDataLengths() must be called before attempting to input data. + /// This is the case for some schemes, such as CCM. + /// \sa SpecifyDataLengths() + virtual bool NeedsPrespecifiedDataLengths() const {return false;} + /// \brief Prespecifies the data lengths + /// \details this function only needs to be called if NeedsPrespecifiedDataLengths() returns true + /// \sa NeedsPrespecifiedDataLengths() + void SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength=0); + /// \brief Encrypts and calculates a MAC in one call + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function will truncate MAC if + /// macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *message, size_t messageLength); + /// \brief Decrypts and verifies a MAC in one call + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. The function returns true iff MAC is valid. + /// DecryptAndVerify() will assume MAC is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *ciphertext, size_t ciphertextLength); + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + virtual std::string AlgorithmName() const; + +protected: + const Algorithm & GetAlgorithm() const + {return *static_cast(this);} + virtual void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) + {CRYPTOPP_UNUSED(headerLength); CRYPTOPP_UNUSED(messageLength); CRYPTOPP_UNUSED(footerLength);} +}; + +/// \brief Interface for random number generators +/// \details The library provides a number of random number generators, from software based +/// to hardware based generators. +/// \details All generated values are uniformly distributed over the range specified. +/// \since Crypto++ 3.1 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomNumberGenerator : public Algorithm +{ +public: + virtual ~RandomNumberGenerator() {} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \throws NotImplemented + /// \details A generator may or may not accept additional entropy. Call CanIncorporateEntropy() + /// to test for the ability to use additional entropy. + /// \details If a derived class does not override IncorporateEntropy(), then the base class + /// throws NotImplemented. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + throw NotImplemented("RandomNumberGenerator: IncorporateEntropy not implemented"); + } + + /// \brief Determines if a generator can accept additional entropy + /// \return true if IncorporateEntropy() is implemented + virtual bool CanIncorporateEntropy() const {return false;} + + /// \brief Generate new random byte and return it + /// \return a random 8-bit byte + /// \details Default implementation calls GenerateBlock() with one byte. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual byte GenerateByte(); + + /// \brief Generate new random bit and return it + /// \return a random bit + /// \details The default implementation calls GenerateByte() and return its lowest bit. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual unsigned int GenerateBit(); + + /// \brief Generate a random 32 bit word in the range min to max, inclusive + /// \param min the lower bound of the range + /// \param max the upper bound of the range + /// \return a random 32-bit word + /// \details The default implementation calls Crop() on the difference between max and + /// min, and then returns the result added to min. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual word32 GenerateWord32(word32 min=0, word32 max=0xffffffffUL); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + /// \note A derived generator \a must override either GenerateBlock() or + /// GenerateIntoBufferedTransformation(). They can override both, or have one call the other. + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate random bytes into a BufferedTransformation + /// \param target the BufferedTransformation object which receives the bytes + /// \param channel the channel on which the bytes should be pumped + /// \param length the number of bytes to generate + /// \details The default implementation calls GenerateBlock() and pumps the result into + /// the DEFAULT_CHANNEL of the target. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + /// \note A derived generator \a must override either GenerateBlock() or + /// GenerateIntoBufferedTransformation(). They can override both, or have one call the other. + virtual void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + virtual void DiscardBytes(size_t n); + + /// \brief Randomly shuffle the specified array + /// \param begin an iterator to the first element in the array + /// \param end an iterator beyond the last element in the array + /// \details The resulting permutation is uniformly distributed. + template void Shuffle(IT begin, IT end) + { + // TODO: What happens if there are more than 2^32 elements? + for (; begin != end; ++begin) + std::iter_swap(begin, begin + GenerateWord32(0, static_cast(end-begin-1))); + } +}; + +/// \brief Interface for key derivation functions +/// \since Crypto++ 6.2 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyDerivationFunction : public Algorithm +{ +public: + virtual ~KeyDerivationFunction() {} + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + virtual std::string AlgorithmName() const =0; + + /// \brief Determine minimum number of bytes + /// \returns Minimum number of bytes which can be derived + virtual size_t MinDerivedLength() const; + + /// \brief Determine maximum number of bytes + /// \returns Maximum number of bytes which can be derived + virtual size_t MaxDerivedLength() const; + + /// \brief Returns a valid key length for the derivation function + /// \param keylength the size of the derived key, in bytes + /// \returns the valid key length, in bytes + virtual size_t GetValidDerivedLength(size_t keylength) const =0; + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if the derived keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + virtual bool IsValidDerivedLength(size_t keylength) const { + return keylength == GetValidDerivedLength(keylength); + } + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param params additional initialization parameters to configure this object + /// \returns the number of iterations performed + /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a secret seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details the number of iterations performed by DeriveKey() may be 1. For example, a + /// scheme like HKDF does not use the iteration count so it returns 1. + virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs& params = g_nullNameValuePairs) const =0; + + /// \brief Set or change parameters + /// \param params additional initialization parameters to configure this object + /// \details SetParameters() is useful for setting common parameters when an object is + /// reused. Some derivation function classes may choose to implement it. + virtual void SetParameters(const NameValuePairs& params); + +protected: + /// \brief Returns the base class Algorithm + /// \return the base class Algorithm + virtual const Algorithm & GetAlgorithm() const =0; + + /// \brief Validates the derived key length + /// \param length the size of the derived key material, in bytes + /// \throws InvalidKeyLength if the key length is invalid + void ThrowIfInvalidDerivedLength(size_t length) const; +}; + +/// \brief Interface for password based key derivation functions +/// \since Crypto++ 6.2 +struct PasswordBasedKeyDerivationFunction : public KeyDerivationFunction +{ +}; + +/// \brief Random Number Generator that does not produce random numbers +/// \return reference that can be passed to functions that require a RandomNumberGenerator +/// \details NullRNG() returns a reference that can be passed to functions that require a +/// RandomNumberGenerator but don't actually use it. The NullRNG() throws NotImplemented +/// when a generation function is called. +/// \sa ClassNullRNG, PK_SignatureScheme::IsProbabilistic() +CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG(); + +class WaitObjectContainer; +class CallStack; + +/// \brief Interface for objects that can be waited on. +class CRYPTOPP_NO_VTABLE Waitable +{ +public: + virtual ~Waitable() {} + + /// \brief Maximum number of wait objects that this object can return + /// \return the maximum number of wait objects + virtual unsigned int GetMaxWaitObjectCount() const =0; + + /// \brief Retrieves waitable objects + /// \param container the wait container to receive the references to the objects. + /// \param callStack CallStack() object used to select waitable objects + /// \details GetWaitObjects() is usually called in one of two ways. First, it can + /// be called like something.GetWaitObjects(c, CallStack("my func after X", 0));. + /// Second, if in an outer GetWaitObjects() method that itself takes a callStack + /// parameter, it can be called like + /// innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));. + virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) =0; + + /// \brief Wait on this object + /// \return true if the wait succeeded, false otherwise + /// \details Wait() is the same as creating an empty container, calling GetWaitObjects(), and then calling + /// Wait() on the container. + bool Wait(unsigned long milliseconds, CallStack const& callStack); +}; + +/// \brief Interface for buffered transformations +/// \details BufferedTransformation is a generalization of BlockTransformation, +/// StreamTransformation and HashTransformation. +/// \details A buffered transformation is an object that takes a stream of bytes as input (this may +/// be done in stages), does some computation on them, and then places the result into an internal +/// buffer for later retrieval. Any partial result already in the output buffer is not modified +/// by further input. +/// \details If a method takes a "blocking" parameter, and you pass false for it, then the method +/// will return before all input has been processed if the input cannot be processed without waiting +/// (for network buffers to become available, for example). In this case the method will return true +/// or a non-zero integer value. When this happens you must continue to call the method with the same +/// parameters until it returns false or zero, before calling any other method on it or attached +/// /p BufferedTransformation. The integer return value in this case is approximately +/// the number of bytes left to be processed, and can be used to implement a progress bar. +/// \details For functions that take a "propagation" parameter, propagation != 0 means pass on +/// the signal to attached BufferedTransformation objects, with propagation decremented at each +/// step until it reaches 0. -1 means unlimited propagation. +/// \details \a All of the retrieval functions, like Get() and GetWord32(), return the actual +/// number of bytes retrieved, which is the lesser of the request number and MaxRetrievable(). +/// \details \a Most of the input functions, like Put() and PutWord32(), return the number of +/// bytes remaining to be processed. A 0 value means all bytes were processed, and a non-0 value +/// means bytes remain to be processed. +/// \nosubgrouping +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BufferedTransformation : public Algorithm, public Waitable +{ +public: + virtual ~BufferedTransformation() {} + + /// \brief Construct a BufferedTransformation + BufferedTransformation() : Algorithm(false) {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + BufferedTransformation& Ref() {return *this;} + + /// \name INPUT + //@{ + + /// \brief Input a byte for processing + /// \param inByte the 8-bit byte (octet) to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Put(byte) calls Put(byte*, size_t). + size_t Put(byte inByte, bool blocking=true) + {return Put(&inByte, 1, blocking);} + + /// \brief Input a byte buffer for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, Put() calls Put2(). + size_t Put(const byte *inString, size_t length, bool blocking=true) + {return Put2(inString, length, 0, blocking);} + + /// Input a 16-bit word for processing. + /// \param value the 16-bit value to be processed + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + size_t PutWord16(word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// Input a 32-bit word for processing. + /// \param value the 32-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + size_t PutWord32(word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \return byte pointer to the space to input data + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of + /// an ArraySink, the pointer to the array is returned and the size is remaining size. + virtual byte * CreatePutSpace(size_t &size) + {size=0; return NULLPTR;} + + /// \brief Determines whether input can be modified by the callee + /// \return true if input can be modified, false otherwise + /// \details The base class implementation returns false. + virtual bool CanModifyInput() const + {return false;} + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + size_t PutModifiable(byte *inString, size_t length, bool blocking=true) + {return PutModifiable2(inString, length, 0, blocking);} + + /// \brief Signals the end of messages to the object + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool MessageEnd(int propagation=-1, bool blocking=true) + {return !!Put2(NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing and signal the end of a message + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, PutMessageEnd() calls Put2() with a modified propagation to + /// ensure all attached transformations finish processing the message. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + size_t PutMessageEnd(const byte *inString, size_t length, int propagation=-1, bool blocking=true) + {return Put2(inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Derived classes must implement Put2(). + virtual size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) =0; + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, PutModifiable2() calls Put2(). + virtual size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + {return Put2(inString, length, messageEnd, blocking);} + + /// \brief Exception thrown by objects that have \a not implemented nonblocking input processing + /// \details BlockingInputOnly inherits from NotImplemented + struct BlockingInputOnly : public NotImplemented + {BlockingInputOnly(const std::string &s) : NotImplemented(s + ": Nonblocking input is not implemented by this object.") {}}; + //@} + + /// \name WAITING + //@{ + /// \brief Retrieves the maximum number of waitable objects + unsigned int GetMaxWaitObjectCount() const; + + /// \brief Retrieves waitable objects + /// \param container the wait container to receive the references to the objects + /// \param callStack CallStack() object used to select waitable objects + /// \details GetWaitObjects is usually called in one of two ways. First, it can + /// be called like something.GetWaitObjects(c, CallStack("my func after X", 0));. + /// Second, if in an outer GetWaitObjects() method that itself takes a callStack + /// parameter, it can be called like + /// innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));. + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + //@} // WAITING + + /// \name SIGNALS + //@{ + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs to initialize this object + /// \throws NotImplemented + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details IsolatedInitialize() does not call Initialize() on attached transformations. If initialization + /// should be propagated, then use the Initialize() function. + /// \details If a derived class does not override IsolatedInitialize(), then the base class throws + /// NotImplemented. + virtual void IsolatedInitialize(const NameValuePairs ¶meters) { + CRYPTOPP_UNUSED(parameters); + throw NotImplemented("BufferedTransformation: this object can't be reinitialized"); + } + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + virtual bool IsolatedFlush(bool hardFlush, bool blocking) =0; + + /// \brief Marks the end of a series of messages, without signal propagation + /// \param blocking specifies whether the object should block when completing the processing on + /// the current series of messages + virtual bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); return false;} + + /// \brief Initialize or reinitialize this object, with signal propagation + /// \param parameters a set of NameValuePairs to initialize or reinitialize this object + /// \param propagation the number of attached transformations the Initialize() signal should be passed + /// \details Initialize() is used to initialize or reinitialize an object using a variable number of + /// arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + + /// \brief Set propagation of automatically generated and transferred signals + /// \param propagation then new value + /// \details Setting propagation to 0 means do not automatically generate signals. Setting + /// propagation to -1 means unlimited propagation. + virtual void SetAutoSignalPropagation(int propagation) + {CRYPTOPP_UNUSED(propagation);} + + /// \brief Retrieve automatic signal propagation value + /// \return the number of attached transformations the signal is propagated to. 0 indicates + /// the signal is only witnessed by this object + virtual int GetAutoSignalPropagation() const {return 0;} +public: + + /// \name RETRIEVAL OF ONE MESSAGE + //@{ + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + /// \details All retrieval functions return the actual number of bytes retrieved, which is + /// the lesser of the request number and MaxRetrievable() + virtual lword MaxRetrievable() const; + + /// \brief Determines whether bytes are ready for retrieval + /// \returns true if bytes are available for retrieval, false otherwise + virtual bool AnyRetrievable() const; + + /// \brief Retrieve a 8-bit byte + /// \param outByte the 8-bit value to be retrieved + /// \return the number of bytes consumed during the call. + /// \details Use the return value of Get to detect short reads. + virtual size_t Get(byte &outByte); + + /// \brief Retrieve a block of bytes + /// \param outString a block of bytes + /// \param getMax the number of bytes to Get + /// \return the number of bytes consumed during the call. + /// \details Use the return value of Get to detect short reads. + virtual size_t Get(byte *outString, size_t getMax); + + /// \brief Peek a 8-bit byte + /// \param outByte the 8-bit value to be retrieved + /// \return the number of bytes read during the call. + /// \details Peek does not remove bytes from the object. Use the return value of + /// Get() to detect short reads. + virtual size_t Peek(byte &outByte) const; + + /// \brief Peek a block of bytes + /// \param outString a block of bytes + /// \param peekMax the number of bytes to Peek + /// \return the number of bytes read during the call. + /// \details Peek does not remove bytes from the object. Use the return value of + /// Get() to detect short reads. + virtual size_t Peek(byte *outString, size_t peekMax) const; + + /// \brief Retrieve a 16-bit word + /// \param value the 16-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord16() to detect short reads. + size_t GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Retrieve a 32-bit word + /// \param value the 32-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord16() to detect short reads. + size_t GetWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Peek a 16-bit word + /// \param value the 16-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of GetWord16() to detect short reads. + size_t PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// \brief Peek a 32-bit word + /// \param value the 32-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of GetWord16() to detect short reads. + size_t PeekWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// move transferMax bytes of the buffered output to target as input + + /// \brief Transfer bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param transferMax the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes transferred during the call. + /// \details TransferTo removes bytes from this object and moves them to the destination. + /// \details The function always returns transferMax. If an accurate count is needed, then use TransferTo2(). + lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) + {TransferTo2(target, transferMax, channel); return transferMax;} + + /// \brief Discard skipMax bytes from the output buffer + /// \param skipMax the number of bytes to discard + /// \details Skip() discards bytes from the output buffer, which is the AttachedTransformation(), if present. + /// The function always returns the parameter skipMax. + /// \details If you want to skip bytes from a Source, then perform the following. + ///
+		///     StringSource ss(str, false, new Redirector(TheBitBucket()));
+		///     ss.Pump(10);    // Skip 10 bytes from Source
+		///     ss.Detach(new FilterChain(...));
+		///     ss.PumpAll();
+		/// 
+ virtual lword Skip(lword skipMax=LWORD_MAX); + + /// copy copyMax bytes of the buffered output to target as input + + /// \brief Copy bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param copyMax the number of bytes to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes copied during the call. + /// \details CopyTo copies bytes from this object to the destination. The bytes are not removed from this object. + /// \details The function always returns copyMax. If an accurate count is needed, then use CopyRangeTo2(). + lword CopyTo(BufferedTransformation &target, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const + {return CopyRangeTo(target, 0, copyMax, channel);} + + /// \brief Copy bytes from this object using an index to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param position the 0-based index of the byte stream to begin the copying + /// \param copyMax the number of bytes to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes copied during the call. + /// \details CopyTo copies bytes from this object to the destination. The bytes remain in this + /// object. Copying begins at the index position in the current stream, and not from an absolute + /// position in the stream. + /// \details The function returns the new position in the stream after transferring the bytes starting at the index. + lword CopyRangeTo(BufferedTransformation &target, lword position, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const + {lword i = position; CopyRangeTo2(target, i, i+copyMax, channel); return i-position;} + //@} + + /// \name RETRIEVAL OF MULTIPLE MESSAGES + //@{ + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + virtual lword TotalBytesRetrievable() const; + + /// \brief Provides the number of meesages processed by this object + /// \return the number of meesages processed by this object + /// \details NumberOfMessages returns number of times MessageEnd() has been + /// received minus messages retrieved or skipped + virtual unsigned int NumberOfMessages() const; + + /// \brief Determines if any messages are available for retrieval + /// \returns true if NumberOfMessages() > 0, false otherwise + /// \details AnyMessages returns true if NumberOfMessages() > 0 + virtual bool AnyMessages() const; + + /// \brief Start retrieving the next message + /// \return true if a message is ready for retrieval + /// \details GetNextMessage() returns true if a message is ready for retrieval; false + /// if no more messages exist or this message is not completely retrieved. + virtual bool GetNextMessage(); + + /// \brief Skip a number of meessages + /// \return 0 if the requested number of messages was skipped, non-0 otherwise + /// \details SkipMessages() skips count number of messages. If there is an AttachedTransformation() + /// then SkipMessages() is called on the attached transformation. If there is no attached + /// transformation, then count number of messages are sent to TheBitBucket() using TransferMessagesTo(). + virtual unsigned int SkipMessages(unsigned int count=UINT_MAX); + + /// \brief Transfer messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param count the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// If all bytes are not transferred for a message, then processing stops and the number of remaining + /// bytes is returned. TransferMessagesTo() does not proceed to the next message. + /// \details A return value of 0 indicates all messages were successfully transferred. + unsigned int TransferMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) + {TransferMessagesTo2(target, count, channel); return count;} + + /// \brief Copy messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param count the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details CopyMessagesTo copies messages from this object and copies them to the destination. + /// If all bytes are not transferred for a message, then processing stops and the number of remaining + /// bytes is returned. CopyMessagesTo() does not proceed to the next message. + /// \details A return value of 0 indicates all messages were successfully copied. + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Skip all messages in the series + virtual void SkipAll(); + + /// \brief Transfer all bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// Internally TransferAllTo() calls TransferAllTo2(). + void TransferAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) + {TransferAllTo2(target, channel);} + + /// \brief Copy messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \details CopyAllTo copies messages from this object and copies them to the destination. + void CopyAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Retrieve the next message in a series + /// \return true if a message was retreved, false otherwise + /// \details Internally, the base class implementation returns false. + virtual bool GetNextMessageSeries() {return false;} + /// \brief Provides the number of messages in a series + /// \return the number of messages in this series + virtual unsigned int NumberOfMessagesInThisSeries() const {return NumberOfMessages();} + /// \brief Provides the number of messages in a series + /// \return the number of messages in this series + virtual unsigned int NumberOfMessageSeries() const {return 0;} + //@} + + /// \name NON-BLOCKING TRANSFER OF OUTPUT + //@{ + + // upon return, byteCount contains number of bytes that have finished being transferred, + // and returns the number of bytes left in the current transfer block + + /// \brief Transfer bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param byteCount the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the transfer block (i.e., bytes not transferred) + /// \details TransferTo() removes bytes from this object and moves them to the destination. + /// Transfer begins at the index position in the current stream, and not from an absolute + /// position in the stream. + /// \details byteCount is an \a IN and \a OUT parameter. When the call is made, + /// byteCount is the requested size of the transfer. When the call returns, byteCount is + /// the number of bytes that were transferred. + virtual size_t TransferTo2(BufferedTransformation &target, lword &byteCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) =0; + + // upon return, begin contains the start position of data yet to be finished copying, + // and returns the number of bytes left in the current transfer block + + /// \brief Copy bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param begin the 0-based index of the first byte to copy in the stream + /// \param end the 0-based index of the last byte to copy in the stream + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the copy block (i.e., bytes not copied) + /// \details CopyRangeTo2 copies bytes from this object to the destination. The bytes are not + /// removed from this object. Copying begins at the index position in the current stream, and + /// not from an absolute position in the stream. + /// \details begin is an \a IN and \a OUT parameter. When the call is made, begin is the + /// starting position of the copy. When the call returns, begin is the position of the first + /// byte that was \a not copied (which may be different than end). begin can be used for + /// subsequent calls to CopyRangeTo2(). + virtual size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const =0; + + // upon return, messageCount contains number of messages that have finished being transferred, + // and returns the number of bytes left in the current transfer block + + /// \brief Transfer messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param messageCount the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// \details messageCount is an \a IN and \a OUT parameter. When the call is made, messageCount is the + /// the number of messages requested to be transferred. When the call returns, messageCount is the + /// number of messages actually transferred. + size_t TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + + // returns the number of bytes left in the current transfer block + + /// \brief Transfer all bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + size_t TransferAllTo2(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + //@} + + /// \name CHANNELS + //@{ + /// \brief Exception thrown when a filter does not support named channels + struct NoChannelSupport : public NotImplemented + {NoChannelSupport(const std::string &name) : NotImplemented(name + ": this object doesn't support multiple channels") {}}; + /// \brief Exception thrown when a filter does not recognize a named channel + struct InvalidChannelName : public InvalidArgument + {InvalidChannelName(const std::string &name, const std::string &channel) : InvalidArgument(name + ": unexpected channel name \"" + channel + "\"") {}}; + + /// \brief Input a byte for processing on a channel + /// \param channel the channel to process the data. + /// \param inByte the 8-bit byte (octet) to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true) + {return ChannelPut(channel, &inByte, 1, blocking);} + + /// \brief Input a byte buffer for processing on a channel + /// \param channel the channel to process the data + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPut(const std::string &channel, const byte *inString, size_t length, bool blocking=true) + {return ChannelPut2(channel, inString, length, 0, blocking);} + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutModifiable(const std::string &channel, byte *inString, size_t length, bool blocking=true) + {return ChannelPutModifiable2(channel, inString, length, 0, blocking);} + + /// \brief Input a 16-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 16-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Input a 32-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 32-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Signal the end of a message + /// \param channel the channel to process the data. + /// \param propagation the number of attached transformations the ChannelMessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool ChannelMessageEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return !!ChannelPut2(channel, NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing and signal the end of a message + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param propagation the number of attached transformations the ChannelPutMessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed) + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + size_t ChannelPutMessageEnd(const std::string &channel, const byte *inString, size_t length, int propagation=-1, bool blocking=true) + {return ChannelPut2(channel, inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Request space which can be written into by the caller + /// \param channel the channel to process the data + /// \param size the requested size of the buffer + /// \return a pointer to a memory block with length size + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of + /// an ArraySink(), the pointer to the array is returned and the size is remaining size. + virtual byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain in the block (i.e., bytes not processed) + virtual size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the block (i.e., bytes not processed) + virtual size_t ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true); + + /// \brief Marks the end of a series of messages on a channel + /// \param channel the channel to signal the end of a series of messages + /// \param propagation the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + virtual bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + /// \brief Sets the default retrieval channel + /// \param channel the channel to signal the end of a series of messages + /// \note this function may not be implemented in all objects that should support it. + virtual void SetRetrievalChannel(const std::string &channel); + //@} + + /// \name ATTACHMENT + /// \details Some BufferedTransformation objects (e.g. Filter objects) allow other BufferedTransformation objects to be + /// attached. When this is done, the first object instead of buffering its output, sends that output to the attached + /// object as input. The entire attachment chain is deleted when the anchor object is destructed. + + //@{ + /// \brief Determines whether the object allows attachment + /// \return true if the object allows an attachment, false otherwise + /// \details Sources and Filters will returns true, while Sinks and other objects will return false. + virtual bool Attachable() {return false;} + + /// \brief Returns the object immediately attached to this object + /// \return the attached transformation + /// \details AttachedTransformation() returns NULL if there is no attachment. The non-const + /// version of AttachedTransformation() always returns NULL. + virtual BufferedTransformation *AttachedTransformation() {CRYPTOPP_ASSERT(!Attachable()); return NULLPTR;} + + /// \brief Returns the object immediately attached to this object + /// \return the attached transformation + /// \details AttachedTransformation() returns NULL if there is no attachment. The non-const + /// version of AttachedTransformation() always returns NULL. + virtual const BufferedTransformation *AttachedTransformation() const + {return const_cast(this)->AttachedTransformation();} + + /// \brief Delete the current attachment chain and attach a new one + /// \param newAttachment the new BufferedTransformation to attach + /// \throws NotImplemented + /// \details Detach() deletes the current attachment chain and replace it with an optional newAttachment + /// \details If a derived class does not override Detach(), then the base class throws + /// NotImplemented. + virtual void Detach(BufferedTransformation *newAttachment = NULLPTR) { + CRYPTOPP_UNUSED(newAttachment); CRYPTOPP_ASSERT(!Attachable()); + throw NotImplemented("BufferedTransformation: this object is not attachable"); + } + + /// \brief Add newAttachment to the end of attachment chain + /// \param newAttachment the attachment to add to the end of the chain + virtual void Attach(BufferedTransformation *newAttachment); + //@} + +protected: + /// \brief Decrements the propagation count while clamping at 0 + /// \return the decremented propagation or 0 + static int DecrementPropagation(int propagation) + {return propagation != 0 ? propagation - 1 : 0;} + +private: + byte m_buf[4]; // for ChannelPutWord16 and ChannelPutWord32, to ensure buffer isn't deallocated before non-blocking operation completes +}; + +/// \brief An input discarding BufferedTransformation +/// \return a reference to a BufferedTransformation object that discards all input +CRYPTOPP_DLL BufferedTransformation & TheBitBucket(); + +/// \brief Interface for crypto material, such as public and private keys, and crypto parameters +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoMaterial : public NameValuePairs +{ +public: + /// Exception thrown when invalid crypto material is detected + class CRYPTOPP_DLL InvalidMaterial : public InvalidDataFormat + { + public: + explicit InvalidMaterial(const std::string &s) : InvalidDataFormat(s) {} + }; + + virtual ~CryptoMaterial() {} + + /// \brief Assign values to this object + /// \details This function can be used to create a public key from a private key. + virtual void AssignFrom(const NameValuePairs &source) =0; + + /// \brief Check this object for errors + /// \param rng a RandomNumberGenerator for objects which use randomized testing + /// \param level the level of thoroughness + /// \returns true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + /// \sa ThrowIfInvalid() + virtual bool Validate(RandomNumberGenerator &rng, unsigned int level) const =0; + + /// \brief Check this object for errors + /// \param rng a RandomNumberGenerator for objects which use randomized testing + /// \param level the level of thoroughness + /// \throws InvalidMaterial + /// \details Internally, ThrowIfInvalid() calls Validate() and throws InvalidMaterial() if validation fails. + /// \sa Validate() + virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const + {if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");} + + /// \brief Saves a key to a BufferedTransformation + /// \param bt the destination BufferedTransformation + /// \throws NotImplemented + /// \details Save() writes the material to a BufferedTransformation. + /// \details If the material is a key, then the key is written with ASN.1 DER encoding. The key + /// includes an object identifier with an algorthm id, like a subjectPublicKeyInfo. + /// \details A "raw" key without the "key info" can be saved using a key's DEREncode() method. + /// \details If a derived class does not override Save(), then the base class throws + /// NotImplemented(). + virtual void Save(BufferedTransformation &bt) const + {CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support saving");} + + /// \brief Loads a key from a BufferedTransformation + /// \param bt the source BufferedTransformation + /// \throws KeyingErr + /// \details Load() attempts to read material from a BufferedTransformation. If the + /// material is a key that was generated outside the library, then the following + /// usually applies: + ///
    + ///
  • the key should be ASN.1 BER encoded + ///
  • the key should be a "key info" + ///
+ /// \details "key info" means the key should have an object identifier with an algorthm id, + /// like a subjectPublicKeyInfo. + /// \details To read a "raw" key without the "key info", then call the key's BERDecode() method. + /// \note Load() generally does not check that the key is valid. Call Validate(), if needed. + virtual void Load(BufferedTransformation &bt) + {CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support loading");} + + /// \brief Determines whether the object supports precomputation + /// \return true if the object supports precomputation, false otherwise + /// \sa Precompute() + virtual bool SupportsPrecomputation() const {return false;} + + /// \brief Perform precomputation + /// \param precomputationStorage the suggested number of objects for the precompute table + /// \throws NotImplemented + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + virtual void Precompute(unsigned int precomputationStorage) { + CRYPTOPP_UNUSED(precomputationStorage); CRYPTOPP_ASSERT(!SupportsPrecomputation()); + throw NotImplemented("CryptoMaterial: this object does not support precomputation"); + } + + /// \brief Retrieve previously saved precomputation + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throws NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + /// \brief Save precomputation for later use + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throws NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + /// \brief Perform a quick sanity check + /// \details DoQuickSanityCheck() is for internal library use, and it should not be called by library users. + void DoQuickSanityCheck() const {ThrowIfInvalid(NullRNG(), 0);} + +#if (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) + // Sun Studio 11/CC 5.8 workaround: it generates incorrect code when casting to an empty virtual base class + char m_sunCCworkaround; +#endif +}; + +/// \brief Interface for generatable crypto material, such as private keys and crypto parameters +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GeneratableCryptoMaterial : virtual public CryptoMaterial +{ +public: + virtual ~GeneratableCryptoMaterial() {} + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param params additional initialization parameters + /// \throws KeyingErr if a key can't be generated or algorithm parameters are invalid + /// \details If a derived class does not override GenerateRandom(), then the base class throws + /// NotImplemented. + virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) { + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(params); + throw NotImplemented("GeneratableCryptoMaterial: this object does not support key/parameter generation"); + } + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param keySize the size of the key, in bits + /// \throws KeyingErr if a key can't be generated or algorithm parameters are invalid + /// \details GenerateRandomWithKeySize calls GenerateRandom() with a NameValuePairs + /// object with only "KeySize" + void GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize); +}; + +/// \brief Interface for public keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKey : virtual public CryptoMaterial +{ +}; + +/// \brief Interface for private keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKey : public GeneratableCryptoMaterial +{ +}; + +/// \brief Interface for crypto prameters +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoParameters : public GeneratableCryptoMaterial +{ +}; + +/// \brief Interface for asymmetric algorithms +/// \details BERDecode() and DEREncode() were removed under Issue 569 +/// and Commit 9b174e84de7a. Programs should use AccessMaterial().Load(bt) +/// or AccessMaterial().Save(bt) instead. +/// \sa Issue 569 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AsymmetricAlgorithm : public Algorithm +{ +public: + virtual ~AsymmetricAlgorithm() {} + + /// \brief Retrieves a reference to CryptoMaterial + /// \return a reference to the crypto material + virtual CryptoMaterial & AccessMaterial() =0; + + /// \brief Retrieves a reference to CryptoMaterial + /// \return a const reference to the crypto material + virtual const CryptoMaterial & GetMaterial() const =0; + +#if 0 + /// \brief Loads this object from a BufferedTransformation + /// \param bt a BufferedTransformation object + /// \details Use of BERDecode() changed to Load() at Issue 569. + /// \deprecated for backwards compatibility, calls AccessMaterial().Load(bt) + void BERDecode(BufferedTransformation &bt) + {AccessMaterial().Load(bt);} + + /// \brief Saves this object to a BufferedTransformation + /// \param bt a BufferedTransformation object + /// \details Use of DEREncode() changed to Save() at Issue 569. + /// \deprecated for backwards compatibility, calls GetMaterial().Save(bt) + void DEREncode(BufferedTransformation &bt) const + {GetMaterial().Save(bt);} +#endif +}; + +/// \brief Interface for asymmetric algorithms using public keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~PublicKeyAlgorithm() {} + + // VC60 workaround: no co-variant return type + + /// \brief Retrieves a reference to a Public Key + /// \return a reference to the public key + CryptoMaterial & AccessMaterial() + {return AccessPublicKey();} + /// \brief Retrieves a reference to a Public Key + /// \return a const reference the public key + const CryptoMaterial & GetMaterial() const + {return GetPublicKey();} + + /// \brief Retrieves a reference to a Public Key + /// \return a reference to the public key + virtual PublicKey & AccessPublicKey() =0; + /// \brief Retrieves a reference to a Public Key + /// \return a const reference the public key + virtual const PublicKey & GetPublicKey() const + {return const_cast(this)->AccessPublicKey();} +}; + +/// \brief Interface for asymmetric algorithms using private keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~PrivateKeyAlgorithm() {} + + /// \brief Retrieves a reference to a Private Key + /// \return a reference the private key + CryptoMaterial & AccessMaterial() {return AccessPrivateKey();} + /// \brief Retrieves a reference to a Private Key + /// \return a const reference the private key + const CryptoMaterial & GetMaterial() const {return GetPrivateKey();} + + /// \brief Retrieves a reference to a Private Key + /// \return a reference the private key + virtual PrivateKey & AccessPrivateKey() =0; + /// \brief Retrieves a reference to a Private Key + /// \return a const reference the private key + virtual const PrivateKey & GetPrivateKey() const {return const_cast(this)->AccessPrivateKey();} +}; + +/// \brief Interface for key agreement algorithms +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyAgreementAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~KeyAgreementAlgorithm() {} + + /// \brief Retrieves a reference to Crypto Parameters + /// \return a reference the crypto parameters + CryptoMaterial & AccessMaterial() {return AccessCryptoParameters();} + /// \brief Retrieves a reference to Crypto Parameters + /// \return a const reference the crypto parameters + const CryptoMaterial & GetMaterial() const {return GetCryptoParameters();} + + /// \brief Retrieves a reference to Crypto Parameters + /// \return a reference the crypto parameters + virtual CryptoParameters & AccessCryptoParameters() =0; + /// \brief Retrieves a reference to Crypto Parameters + /// \return a const reference the crypto parameters + virtual const CryptoParameters & GetCryptoParameters() const {return const_cast(this)->AccessCryptoParameters();} +}; + +/// \brief Interface for public-key encryptors and decryptors +/// \details This class provides an interface common to encryptors and decryptors +/// for querying their plaintext and ciphertext lengths. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_CryptoSystem +{ +public: + virtual ~PK_CryptoSystem() {} + + /// \brief Provides the maximum length of plaintext for a given ciphertext length + /// \return the maximum size of the plaintext, in bytes + /// \details This function returns 0 if ciphertextLength is not valid (too long or too short). + virtual size_t MaxPlaintextLength(size_t ciphertextLength) const =0; + + /// \brief Calculate the length of ciphertext given length of plaintext + /// \return the maximum size of the ciphertext, in bytes + /// \details This function returns 0 if plaintextLength is not valid (too long). + virtual size_t CiphertextLength(size_t plaintextLength) const =0; + + /// \brief Determines whether this object supports the use of a named parameter + /// \param name the name of the parameter + /// \return true if the parameter name is supported, false otherwise + /// \details Some possible parameter names: EncodingParameters(), KeyDerivationParameters() + /// and others Parameters listed in argnames.h + virtual bool ParameterSupported(const char *name) const =0; + + /// \brief Provides the fixed ciphertext length, if one exists + /// \return the fixed ciphertext length if one exists, otherwise 0 + /// \details "Fixed" here means length of ciphertext does not depend on length of plaintext. + /// In this case, it usually does depend on the key length. + virtual size_t FixedCiphertextLength() const {return 0;} + + /// \brief Provides the maximum plaintext length given a fixed ciphertext length + /// \return maximum plaintext length given the fixed ciphertext length, if one exists, + /// otherwise return 0. + /// \details FixedMaxPlaintextLength(0 returns the maximum plaintext length given the fixed ciphertext + /// length, if one exists, otherwise return 0. + virtual size_t FixedMaxPlaintextLength() const {return 0;} +}; + +/// \brief Interface for public-key encryptors +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Encryptor : public PK_CryptoSystem, public PublicKeyAlgorithm +{ +public: + /// \brief Exception thrown when trying to encrypt plaintext of invalid length + class CRYPTOPP_DLL InvalidPlaintextLength : public Exception + { + public: + InvalidPlaintextLength() : Exception(OTHER_ERROR, "PK_Encryptor: invalid plaintext length") {} + }; + + /// \brief Encrypt a byte string + /// \param rng a RandomNumberGenerator derived class + /// \param plaintext the plaintext byte buffer + /// \param plaintextLength the size of the plaintext byte buffer + /// \param ciphertext a byte buffer to hold the encrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \pre CiphertextLength(plaintextLength) != 0 ensures the plaintext isn't too large + /// \pre COUNTOF(ciphertext) == CiphertextLength(plaintextLength) ensures the output + /// byte buffer is large enough. + /// \sa PK_Decryptor + virtual void Encrypt(RandomNumberGenerator &rng, + const byte *plaintext, size_t plaintextLength, + byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0; + + /// \brief Create a new encryption filter + /// \param rng a RandomNumberGenerator derived class + /// \param attachment an attached transformation + /// \param parameters a set of NameValuePairs to initialize this object + /// \details \p attachment can be \p NULL. The caller is responsible for deleting the returned pointer. + /// Encoding parameters should be passed in the "EP" channel. + virtual BufferedTransformation * CreateEncryptionFilter(RandomNumberGenerator &rng, + BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +/// \brief Interface for public-key decryptors +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Decryptor : public PK_CryptoSystem, public PrivateKeyAlgorithm +{ +public: + virtual ~PK_Decryptor() {} + + /// \brief Decrypt a byte string + /// \param rng a RandomNumberGenerator derived class + /// \param ciphertext the encrypted byte buffer + /// \param ciphertextLength the size of the encrypted byte buffer + /// \param plaintext a byte buffer to hold the decrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the result of the decryption operation + /// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength + /// is valid and holds the the actual length of the plaintext recovered. The result is undefined + /// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength + /// is undefined. + /// \pre COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength) ensures the output + /// byte buffer is large enough + /// \sa PK_Encryptor + virtual DecodingResult Decrypt(RandomNumberGenerator &rng, + const byte *ciphertext, size_t ciphertextLength, + byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0; + + /// \brief Create a new decryption filter + /// \param rng a RandomNumberGenerator derived class + /// \param attachment an attached transformation + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the newly created decryption filter + /// \note the caller is responsible for deleting the returned pointer + virtual BufferedTransformation * CreateDecryptionFilter(RandomNumberGenerator &rng, + BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const; + + /// \brief Decrypt a fixed size ciphertext + /// \param rng a RandomNumberGenerator derived class + /// \param ciphertext the encrypted byte buffer + /// \param plaintext a byte buffer to hold the decrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the result of the decryption operation + /// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength + /// is valid and holds the the actual length of the plaintext recovered. The result is undefined + /// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength + /// is undefined. + /// \pre COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength) ensures the output + /// byte buffer is large enough + /// \sa PK_Encryptor + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *ciphertext, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + {return Decrypt(rng, ciphertext, FixedCiphertextLength(), plaintext, parameters);} +}; + +/// \brief Interface for public-key signers and verifiers +/// \details This class provides an interface common to signers and verifiers for querying scheme properties +/// \sa DL_SignatureSchemeBase, TF_SignatureSchemeBase, DL_SignerBase, TF_SignerBase +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_SignatureScheme +{ +public: + /// \brief Exception throw when the private or public key has a length that can't be used + /// \details InvalidKeyLength() may be thrown by any function in this class if the private + /// or public key has a length that can't be used + class CRYPTOPP_DLL InvalidKeyLength : public Exception + { + public: + InvalidKeyLength(const std::string &message) : Exception(OTHER_ERROR, message) {} + }; + + /// \brief Exception throw when the private or public key is too short to sign or verify + /// \details KeyTooShort() may be thrown by any function in this class if the private or public + /// key is too short to sign or verify anything + class CRYPTOPP_DLL KeyTooShort : public InvalidKeyLength + { + public: + KeyTooShort() : InvalidKeyLength("PK_Signer: key too short for this signature scheme") {} + }; + + virtual ~PK_SignatureScheme() {} + + /// \brief Provides the signature length if it only depends on the key + /// \return the signature length if it only depends on the key, in bytes + /// \details SignatureLength() returns the signature length if it only depends on the key, otherwise 0. + virtual size_t SignatureLength() const =0; + + /// \brief Provides the maximum signature length produced given the length of the recoverable message part + /// \param recoverablePartLength the length of the recoverable message part, in bytes + /// \return the maximum signature length produced for a given length of recoverable message part, in bytes + /// \details MaxSignatureLength() returns the maximum signature length produced given the length of the + /// recoverable message part. + virtual size_t MaxSignatureLength(size_t recoverablePartLength = 0) const + {CRYPTOPP_UNUSED(recoverablePartLength); return SignatureLength();} + + /// \brief Provides the length of longest message that can be recovered + /// \return the length of longest message that can be recovered, in bytes + /// \details MaxRecoverableLength() returns the length of longest message that can be recovered, or 0 if + /// this signature scheme does not support message recovery. + virtual size_t MaxRecoverableLength() const =0; + + /// \brief Provides the length of longest message that can be recovered from a signature of given length + /// \param signatureLength the length of the signature, in bytes + /// \return the length of longest message that can be recovered from a signature of given length, in bytes + /// \details MaxRecoverableLengthFromSignatureLength() returns the length of longest message that can be + /// recovered from a signature of given length, or 0 if this signature scheme does not support message + /// recovery. + virtual size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const =0; + + /// \brief Determines whether a signature scheme requires a random number generator + /// \return true if the signature scheme requires a RandomNumberGenerator() to sign + /// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + /// RandomNumberGenerator(). + virtual bool IsProbabilistic() const =0; + + /// \brief Determines whether the non-recoverable message part can be signed + /// \return true if the non-recoverable message part can be signed + virtual bool AllowNonrecoverablePart() const =0; + + /// \brief Determines whether the signature must be input before the message + /// \return true if the signature must be input before the message during verifcation + /// \details if SignatureUpfront() returns true, then you must input the signature before the message + /// during verification. Otherwise you can input the signature at anytime. + virtual bool SignatureUpfront() const {return false;} + + /// \brief Determines whether the recoverable part must be input before the non-recoverable part + /// \return true if the recoverable part must be input before the non-recoverable part during signing + /// \details RecoverablePartFirst() determines whether you must input the recoverable part before the + /// non-recoverable part during signing + virtual bool RecoverablePartFirst() const =0; +}; + +/// \brief Interface for accumulating messages to be signed or verified +/// \details Only Update() should be called from the PK_MessageAccumulator() class. No other functions +/// inherited from HashTransformation, like DigestSize() and TruncatedFinal(), should be called. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulator : public HashTransformation +{ +public: + /// \warning DigestSize() should not be called on PK_MessageAccumulator + unsigned int DigestSize() const + {throw NotImplemented("PK_MessageAccumulator: DigestSize() should not be called");} + + /// \warning TruncatedFinal() should not be called on PK_MessageAccumulator + void TruncatedFinal(byte *digest, size_t digestSize) + { + CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(digestSize); + throw NotImplemented("PK_MessageAccumulator: TruncatedFinal() should not be called"); + } +}; + +/// \brief Interface for public-key signers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Signer : public PK_SignatureScheme, public PrivateKeyAlgorithm +{ +public: + virtual ~PK_Signer() {} + + /// \brief Create a new HashTransformation to accumulate the message to be signed + /// \param rng a RandomNumberGenerator derived class + /// \return a pointer to a PK_MessageAccumulator + /// \details NewSignatureAccumulator() can be used with all signing methods. Sign() will autimatically delete the + /// accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference. + virtual PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const =0; + + /// \brief Input a recoverable message to an accumulator + /// \param messageAccumulator a reference to a PK_MessageAccumulator + /// \param recoverableMessage a pointer to the recoverable message part to be signed + /// \param recoverableMessageLength the size of the recoverable message part + virtual void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const =0; + + /// \brief Sign and delete the messageAccumulator + /// \param rng a RandomNumberGenerator derived class + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \details Sign() deletes the messageAccumulator, even if an exception is thrown. + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const; + + /// \brief Sign and restart messageAccumulator + /// \param rng a RandomNumberGenerator derived class + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature a block of bytes for the signature + /// \param restart flag indicating whether the messageAccumulator should be restarted + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const =0; + + /// \brief Sign a message + /// \param rng a RandomNumberGenerator derived class + /// \param message a pointer to the message + /// \param messageLen the size of the message to be signed + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t SignMessage(RandomNumberGenerator &rng, const byte *message, size_t messageLen, byte *signature) const; + + /// \brief Sign a recoverable message + /// \param rng a RandomNumberGenerator derived class + /// \param recoverableMessage a pointer to the recoverable message part to be signed + /// \param recoverableMessageLength the size of the recoverable message part + /// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed + /// \param nonrecoverableMessageLength the size of the non-recoverable message part + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength(recoverableMessageLength) + virtual size_t SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, byte *signature) const; +}; + +/// \brief Interface for public-key signature verifiers +/// \details The Recover* functions throw NotImplemented if the signature scheme does not support +/// message recovery. +/// \details The Verify* functions throw InvalidDataFormat if the scheme does support message +/// recovery and the signature contains a non-empty recoverable message part. The +/// Recover* functions should be used in that case. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Verifier : public PK_SignatureScheme, public PublicKeyAlgorithm +{ +public: + virtual ~PK_Verifier() {} + + /// \brief Create a new HashTransformation to accumulate the message to be verified + /// \return a pointer to a PK_MessageAccumulator + /// \details NewVerificationAccumulator() can be used with all verification methods. Verify() will autimatically delete + /// the accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference. + virtual PK_MessageAccumulator * NewVerificationAccumulator() const =0; + + /// \brief Input signature into a message accumulator + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature the signature on the message + /// \param signatureLength the size of the signature + virtual void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const =0; + + /// \brief Check whether messageAccumulator contains a valid signature and message + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return true if the signature is valid, false otherwise + /// \details Verify() deletes the messageAccumulator, even if an exception is thrown. + virtual bool Verify(PK_MessageAccumulator *messageAccumulator) const; + + /// \brief Check whether messageAccumulator contains a valid signature and message, and restart messageAccumulator + /// \param messageAccumulator a reference to a PK_MessageAccumulator derived class + /// \return true if the signature is valid, false otherwise + /// \details VerifyAndRestart() restarts the messageAccumulator + virtual bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const =0; + + /// \brief Check whether input signature is a valid signature for input message + /// \param message a pointer to the message to be verified + /// \param messageLen the size of the message + /// \param signature a pointer to the signature over the message + /// \param signatureLen the size of the signature + /// \return true if the signature is valid, false otherwise + virtual bool VerifyMessage(const byte *message, size_t messageLen, + const byte *signature, size_t signatureLen) const; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer to the recoverable message part to be verified + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return the result of the verification operation + /// \details Recover() deletes the messageAccumulator, even if an exception is thrown. + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer to the recoverable message part to be verified + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return the result of the verification operation + /// \details RecoverAndRestart() restarts the messageAccumulator + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const =0; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer for the recovered message + /// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed + /// \param nonrecoverableMessageLength the size of the non-recoverable message part + /// \param signature the signature on the message + /// \param signatureLength the size of the signature + /// \return the result of the verification operation + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult RecoverMessage(byte *recoveredMessage, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, + const byte *signature, size_t signatureLength) const; +}; + +/// \brief Interface for domains of simple key agreement protocols +/// \details A key agreement domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~SimpleKeyAgreementDomain() {} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + virtual unsigned int AgreedValueLength() const =0; + + /// \brief Provides the size of the private key + /// \return size of private keys in this domain + virtual unsigned int PrivateKeyLength() const =0; + + /// \brief Provides the size of the public key + /// \return size of public keys in this domain + virtual unsigned int PublicKeyLength() const =0; + + /// \brief Generate private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + virtual void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate a public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicKeyLength() + virtual void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate a private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateKeyPair() is equivalent to calling GeneratePrivateKey() and then GeneratePublicKey(). + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + /// \pre COUNTOF(publicKey) == PublicKeyLength() + virtual void GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Derive agreed value + /// \param agreedValue a byte buffer for the shared secret + /// \param privateKey a byte buffer with your private key in this domain + /// \param otherPublicKey a byte buffer with the other party's public key in this domain + /// \param validateOtherPublicKey a flag indicating if the other party's public key should be validated + /// \return true upon success, false in case of failure + /// \details Agree() derives an agreed value from your private keys and couterparty's public keys. + /// \details The other party's public key is validated by default. If you have previously validated the + /// static public key, use validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + /// \pre COUNTOF(otherPublicKey) == PublicKeyLength() + virtual bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const =0; +}; + +/// \brief Interface for domains of authenticated key agreement protocols +/// \details In an authenticated key agreement protocol, each party has two +/// key pairs. The long-lived key pair is called the static key pair, +/// and the short-lived key pair is called the ephemeral key pair. +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~AuthenticatedKeyAgreementDomain() {} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + virtual unsigned int AgreedValueLength() const =0; + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + virtual unsigned int StaticPrivateKeyLength() const =0; + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + virtual unsigned int StaticPublicKeyLength() const =0; + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + virtual void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + virtual void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate a static private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateStaticKeyPair() is equivalent to calling GenerateStaticPrivateKey() and then GenerateStaticPublicKey(). + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + virtual void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Provides the size of ephemeral private key + /// \return the size of ephemeral private key in this domain + virtual unsigned int EphemeralPrivateKeyLength() const =0; + + /// \brief Provides the size of ephemeral public key + /// \return the size of ephemeral public key in this domain + virtual unsigned int EphemeralPublicKeyLength() const =0; + + /// \brief Generate ephemeral private key + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateEphemeralKeyLength() + virtual void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate ephemeral public key + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicEphemeralKeyLength() + virtual void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateEphemeralKeyPair() is equivalent to calling GenerateEphemeralPrivateKey() and then GenerateEphemeralPublicKey() + virtual void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Derive agreed value + /// \param agreedValue a byte buffer for the shared secret + /// \param staticPrivateKey a byte buffer with your static private key in this domain + /// \param ephemeralPrivateKey a byte buffer with your ephemeral private key in this domain + /// \param staticOtherPublicKey a byte buffer with the other party's static public key in this domain + /// \param ephemeralOtherPublicKey a byte buffer with the other party's ephemeral public key in this domain + /// \param validateStaticOtherPublicKey a flag indicating if the other party's public key should be validated + /// \return true upon success, false in case of failure + /// \details Agree() derives an agreed value from your private keys and couterparty's public keys. + /// \details The other party's ephemeral public key is validated by default. If you have previously validated + /// the static public key, use validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + virtual bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const =0; +}; + +// interface for password authenticated key agreement protocols, not implemented yet +#if 0 +/// \brief Interface for protocol sessions +/*! The methods should be called in the following order: + + InitializeSession(rng, parameters); // or call initialize method in derived class + while (true) + { + if (OutgoingMessageAvailable()) + { + length = GetOutgoingMessageLength(); + GetOutgoingMessage(message); + ; // send outgoing message + } + + if (LastMessageProcessed()) + break; + + ; // receive incoming message + ProcessIncomingMessage(message); + } + ; // call methods in derived class to obtain result of protocol session +*/ +class ProtocolSession +{ +public: + /// Exception thrown when an invalid protocol message is processed + class ProtocolError : public Exception + { + public: + ProtocolError(ErrorType errorType, const std::string &s) : Exception(errorType, s) {} + }; + + /// Exception thrown when a function is called unexpectedly + /*! for example calling ProcessIncomingMessage() when ProcessedLastMessage() == true */ + class UnexpectedMethodCall : public Exception + { + public: + UnexpectedMethodCall(const std::string &s) : Exception(OTHER_ERROR, s) {} + }; + + virtual ~ProtocolSession() {} + + ProtocolSession() : m_rng(NULLPTR), m_throwOnProtocolError(true), m_validState(false) {} + + virtual void InitializeSession(RandomNumberGenerator &rng, const NameValuePairs ¶meters) =0; + + bool GetThrowOnProtocolError() const {return m_throwOnProtocolError;} + void SetThrowOnProtocolError(bool throwOnProtocolError) {m_throwOnProtocolError = throwOnProtocolError;} + + bool HasValidState() const {return m_validState;} + + virtual bool OutgoingMessageAvailable() const =0; + virtual unsigned int GetOutgoingMessageLength() const =0; + virtual void GetOutgoingMessage(byte *message) =0; + + virtual bool LastMessageProcessed() const =0; + virtual void ProcessIncomingMessage(const byte *message, unsigned int messageLength) =0; + +protected: + void HandleProtocolError(Exception::ErrorType errorType, const std::string &s) const; + void CheckAndHandleInvalidState() const; + void SetValidState(bool valid) {m_validState = valid;} + + RandomNumberGenerator *m_rng; + +private: + bool m_throwOnProtocolError, m_validState; +}; + +class KeyAgreementSession : public ProtocolSession +{ +public: + virtual ~KeyAgreementSession() {} + + virtual unsigned int GetAgreedValueLength() const =0; + virtual void GetAgreedValue(byte *agreedValue) const =0; +}; + +class PasswordAuthenticatedKeyAgreementSession : public KeyAgreementSession +{ +public: + virtual ~PasswordAuthenticatedKeyAgreementSession() {} + + void InitializePasswordAuthenticatedKeyAgreementSession(RandomNumberGenerator &rng, + const byte *myId, unsigned int myIdLength, + const byte *counterPartyId, unsigned int counterPartyIdLength, + const byte *passwordOrVerifier, unsigned int passwordOrVerifierLength); +}; + +/// \brief Password based key agreement domain +/// \since Crypto++ 3.0 +class PasswordAuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~PasswordAuthenticatedKeyAgreementDomain() {} + + /// return whether the domain parameters stored in this object are valid + virtual bool ValidateDomainParameters(RandomNumberGenerator &rng) const + {return GetCryptoParameters().Validate(rng, 2);} + + virtual unsigned int GetPasswordVerifierLength(const byte *password, unsigned int passwordLength) const =0; + virtual void GeneratePasswordVerifier(RandomNumberGenerator &rng, const byte *userId, unsigned int userIdLength, const byte *password, unsigned int passwordLength, byte *verifier) const =0; + + enum RoleFlags {CLIENT=1, SERVER=2, INITIATOR=4, RESPONDER=8}; + + virtual bool IsValidRole(unsigned int role) =0; + virtual PasswordAuthenticatedKeyAgreementSession * CreateProtocolSession(unsigned int role) const =0; +}; +#endif + +/// \brief Exception thrown when an ASN.1 BER decoing error is encountered +class CRYPTOPP_DLL BERDecodeErr : public InvalidArgument +{ +public: + BERDecodeErr() : InvalidArgument("BER decode error") {} + BERDecodeErr(const std::string &s) : InvalidArgument(s) {} +}; + +/// \brief Interface for encoding and decoding ASN1 objects +/// \details Each class that derives from ASN1Object should provide a serialization format +/// that controls subobject layout. Most of the time the serialization format is +/// taken from a standard, like P1363 or an RFC. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1Object +{ +public: + virtual ~ASN1Object() {} + + /// \brief Decode this object from a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Basic Encoding Rules (BER) + virtual void BERDecode(BufferedTransformation &bt) =0; + + /// \brief Encode this object into a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Distinguished Encoding Rules (DER) + virtual void DEREncode(BufferedTransformation &bt) const =0; + + /// \brief Encode this object into a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Basic Encoding Rules (BER). + /// \details This may be useful if DEREncode() would be too inefficient. + virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);} +}; + +/// \brief Specifies the build-time version of the library +/// \returns integer representing the build-time version +/// \details LibraryVersion can help detect inadvertent mixing and matching of library +/// versions. When using Crypto++ distributed by a third party, LibraryVersion() +/// records the version of the shared object that was built by the third party. +/// The LibraryVersion() record resides in cryptlib.o on Unix compatibles +/// and cryptlib.obj on Windows. It does not change when an app links +/// to the library. +/// \details LibraryVersion() is declared with C linkage (extern "C") within the +/// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then +/// the library version is 5.7 or above. If it is missing, then the library version is +/// 5.6.5 or below. +/// \details The function could be used as shown below. +///
+///     if (LibraryVersion() != HeaderVersion())
+///     {
+///         cout << "Potential version mismatch" << endl;
+///
+///         const int lmaj = (LibraryVersion() / 100U) % 10;
+///         const int lmin = (LibraryVersion() / 10U) % 10;
+///         const int hmaj = (HeaderVersion() / 100U) % 10;
+///         const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///         if(lmaj != hmaj)
+///             cout << "Major version mismatch" << endl;
+///         else if(lmin != hmin)
+///             cout << "Minor version mismatch" << endl;
+///      }
+/// 
+/// \sa HeaderVersion(), GitHub Issue 371. +/// \since Crypto++ 6.0 +extern "C" { + int LibraryVersion(CRYPTOPP_NOINLINE_DOTDOTDOT); +} // C linkage + +/// \brief Specifies the runtime version of the library +/// \returns integer representing the runtime version +/// \details HeaderVersion() can help detect inadvertent mixing and matching of library +/// versions. When using Crypto++ distributed by a third party, HeaderVersion() +/// records the version of the headers used by the app when the app is compiled. +/// \details HeaderVersion() is declared with C linkage (extern "C") within the +/// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then +/// the library version is 5.7 or above. If it is missing, then the library version is +/// 5.6.5 or below. +/// \details The function could be used as shown below. +///
+///     if (LibraryVersion() != HeaderVersion())
+///     {
+///         cout << "Potential version mismatch" << endl;
+///
+///         const int lmaj = (LibraryVersion() / 100U) % 10;
+///         const int lmin = (LibraryVersion() / 10U) % 10;
+///         const int hmaj = (HeaderVersion() / 100U) % 10;
+///         const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///         if(lmaj != hmaj)
+///             cout << "Major version mismatch" << endl;
+///         else if(lmin != hmin)
+///             cout << "Minor version mismatch" << endl;
+///      }
+/// 
+/// \sa LibraryVersion(), GitHub Issue 371. +/// \since Crypto++ 6.0 +extern "C" { +inline int HeaderVersion() +{ + return CRYPTOPP_VERSION; +} +} // C linkage + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/default.h b/include/cryptlib/default.h new file mode 100644 index 0000000..8b0199e --- /dev/null +++ b/include/cryptlib/default.h @@ -0,0 +1,310 @@ +// default.h - originally written and placed in the public domain by Wei Dai + +/// \file default.h +/// \brief Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC + +#ifndef CRYPTOPP_DEFAULT_H +#define CRYPTOPP_DEFAULT_H + +#include "sha.h" +#include "hmac.h" +#include "aes.h" +#include "des.h" +#include "modes.h" +#include "filters.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Legacy block cipher for LegacyEncryptor, LegacyDecryptor, LegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef DES_EDE2 LegacyBlockCipher; +/// \brief Legacy hash for use with LegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef SHA1 LegacyHashModule; +/// \brief Legacy HMAC for use withLegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef HMAC LegacyMAC; + +/// \brief Default block cipher for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef AES DefaultBlockCipher; +/// \brief Default hash for use with DefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef SHA256 DefaultHashModule; +/// \brief Default HMAC for use withDefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef HMAC DefaultMAC; + +/// \brief Exception thrown when LegacyDecryptorWithMAC or DefaultDecryptorWithMAC decryption error is encountered +class DataDecryptorErr : public Exception +{ +public: + DataDecryptorErr(const std::string &s) + : Exception(DATA_INTEGRITY_CHECK_FAILED, s) {} +}; + +/// \brief Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC +class KeyBadErr : public DataDecryptorErr +{ + public: KeyBadErr() + : DataDecryptorErr("DataDecryptor: cannot decrypt message with this passphrase") {} +}; + +/// \brief Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC +class MACBadErr : public DataDecryptorErr +{ + public: MACBadErr() + : DataDecryptorErr("DataDecryptorWithMAC: MAC check failed") {} +}; + +/// \brief Algorithm information for password-based encryptors and decryptors +template +struct DataParametersInfo +{ + CRYPTOPP_CONSTANT(BLOCKSIZE = BlockSize) + CRYPTOPP_CONSTANT(KEYLENGTH = KeyLength) + CRYPTOPP_CONSTANT(SALTLENGTH = SaltSize) + CRYPTOPP_CONSTANT(DIGESTSIZE = DigestSize) + CRYPTOPP_CONSTANT(ITERATIONS = Iterations) +}; + +typedef DataParametersInfo LegacyParametersInfo; +typedef DataParametersInfo DefaultParametersInfo; + +/// \brief Password-based Encryptor +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam Info Constants used by the algorithms +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor +/// \since Crypto++ 2.0 +template +class DataEncryptor : public ProxyFilter, public Info +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE) + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH) + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH) + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS) + + /// \brief Construct a DataEncryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR); + + /// \brief Construct a DataEncryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR); + +protected: + void FirstPut(const byte *); + void LastPut(const byte *inString, size_t length); + +private: + SecByteBlock m_passphrase; + typename CBC_Mode::Encryption m_cipher; +}; + +/// \brief Password-based Decryptor +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam Info Constants used by the algorithms +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor +/// \since Crypto++ 2.0 +template +class DataDecryptor : public ProxyFilter, public Info +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE) + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH) + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH) + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS) + + /// \brief Constructs a DataDecryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + enum State {WAITING_FOR_KEYCHECK, KEY_GOOD, KEY_BAD}; + State CurrentState() const {return m_state;} + +protected: + void FirstPut(const byte *inString); + void LastPut(const byte *inString, size_t length); + + State m_state; + +private: + void CheckKey(const byte *salt, const byte *keyCheck); + + SecByteBlock m_passphrase; + typename CBC_Mode::Decryption m_cipher; + member_ptr m_decryptor; + bool m_throwException; + +}; + +/// \brief Password-based encryptor with MAC +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam MAC HashTransformation based class used for authentication +/// \tparam Info Constants used by the algorithms +/// \details DataEncryptorWithMAC uses a non-standard mashup function called Mash() to derive key +/// bits from the password. +/// \details The purpose of the function Mash() is to take an arbitrary length input string and +/// *deterministically* produce an arbitrary length output string such that (1) it looks random, +/// (2) no information about the input is deducible from it, and (3) it contains as much entropy +/// as it can hold, or the amount of entropy in the input string, whichever is smaller. +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC +/// \since Crypto++ 2.0 +template +class DataEncryptorWithMAC : public ProxyFilter +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE) + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH) + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH) + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS) + + /// \brief Constructs a DataEncryptorWithMAC + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR); + + /// \brief Constructs a DataEncryptorWithMAC + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR); + +protected: + void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);} + void LastPut(const byte *inString, size_t length); + +private: + member_ptr m_mac; + +}; + +/// \brief Password-based decryptor with MAC +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam MAC HashTransformation based class used for authentication +/// \tparam Info Constants used by the algorithms +/// \details DataDecryptorWithMAC uses a non-standard mashup function called Mash() to derive key +/// bits from the password. +/// \details The purpose of the function Mash() is to take an arbitrary length input string and +/// *deterministically* produce an arbitrary length output string such that (1) it looks random, +/// (2) no information about the input is deducible from it, and (3) it contains as much entropy +/// as it can hold, or the amount of entropy in the input string, whichever is smaller. +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC +/// \since Crypto++ 2.0 +template +class DataDecryptorWithMAC : public ProxyFilter +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE) + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH) + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH) + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE) + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS) + + /// \brief Constructs a DataDecryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + typename DataDecryptor::State CurrentState() const; + bool CheckLastMAC() const; + +protected: + void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);} + void LastPut(const byte *inString, size_t length); + +private: + member_ptr m_mac; + HashVerificationFilter *m_hashVerifier; + bool m_throwException; +}; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Password-based encryptor (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyEncryptor : public DataEncryptor {}; +/// \brief Password-based decryptor (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyDecryptor : public DataDecryptor {}; +/// \brief Password-based encryptor +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultEncryptor : public DataEncryptor {}; +/// \brief Password-based decryptor +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultDecryptor : public DataDecryptor {}; +/// \brief Password-based encryptor with MAC (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyEncryptorWithMAC : public DataEncryptorWithMAC {}; +/// \brief Password-based decryptor with MAC (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyDecryptorWithMAC : public DataDecryptorWithMAC {}; +/// \brief Password-based encryptor with MAC +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultEncryptorWithMAC : public DataEncryptorWithMAC {}; +/// \brief Password-based decryptor with MAC +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultDecryptorWithMAC : public DataDecryptorWithMAC {}; +#else +typedef DataEncryptor LegacyEncryptor; +typedef DataDecryptor LegacyDecryptor; + +typedef DataEncryptor DefaultEncryptor; +typedef DataDecryptor DefaultDecryptor; + +typedef DataEncryptorWithMAC LegacyEncryptorWithMAC; +typedef DataDecryptorWithMAC LegacyDecryptorWithMAC; + +typedef DataEncryptorWithMAC DefaultEncryptorWithMAC; +typedef DataDecryptorWithMAC DefaultDecryptorWithMAC; +#endif + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/des.h b/include/cryptlib/des.h new file mode 100644 index 0000000..10ba059 --- /dev/null +++ b/include/cryptlib/des.h @@ -0,0 +1,163 @@ +// des.h - originally written and placed in the public domain by Wei Dai + +/// \file des.h +/// \brief Classes for DES, 2-key Triple-DES, 3-key Triple-DES and DESX + +#ifndef CRYPTOPP_DES_H +#define CRYPTOPP_DES_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DES block cipher base class +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RawDES +{ +public: + void RawSetKey(CipherDir direction, const byte *userKey); + void RawProcessBlock(word32 &l, word32 &r) const; + +protected: + static const word32 Spbox[8][64]; + + FixedSizeSecBlock k; +}; + +/// \brief DES block cipher information +/// \since Crypto++ 1.0 +struct DES_Info : public FixedBlockSize<8>, public FixedKeyLength<8> +{ + // disable DES in DLL version by not exporting this function + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES";} +}; + +/// \brief DES block cipher +/// \details The DES implementation in Crypto++ ignores the parity bits +/// (the least significant bits of each byte) in the key. However you can use CheckKeyParityBits() +/// and CorrectKeyParityBits() to check or correct the parity bits if you wish. +/// \sa DES +/// \since Crypto++ 1.0 +class DES : public DES_Info, public BlockCipherDocumentation +{ + /// \brief DES block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl, public RawDES + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + /// check DES key parity bits + static bool CheckKeyParityBits(const byte *key); + /// correct DES key parity bits + static void CorrectKeyParityBits(byte *key); + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief 2-key TripleDES block cipher information +/// \since Crypto++ 1.0 +struct DES_EDE2_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE2";} +}; + +/// \brief 2-key TripleDES block cipher +/// \sa DES-EDE2 +/// \since Crypto++ 1.0 +class DES_EDE2 : public DES_EDE2_Info, public BlockCipherDocumentation +{ + /// \brief DES_EDE2 block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + RawDES m_des1, m_des2; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief 3-key TripleDES block cipher information +/// \since Crypto++ 1.0 +struct DES_EDE3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE3";} +}; + +/// \brief 3-key TripleDES block cipher +/// \sa DES-EDE3 +/// \since Crypto++ 1.0 +class DES_EDE3 : public DES_EDE3_Info, public BlockCipherDocumentation +{ + /// \brief DES_EDE3 block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + RawDES m_des1, m_des2, m_des3; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief DESX block cipher information +/// \since Crypto++ 3.2 +struct DES_XEX3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES-XEX3";} +}; + +/// \brief DESX block cipher +/// \sa DES-XEX3, AKA DESX +/// \since Crypto++ 3.2 +class DES_XEX3 : public DES_XEX3_Info, public BlockCipherDocumentation +{ + /// \brief DES_XEX3 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_x1, m_x3; + // VS2005 workaround: calling modules compiled with /clr gets unresolved external symbol DES::Base::ProcessAndXorBlock + // if we use DES::Encryption here directly without value_ptr. + value_ptr m_des; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef DES::Encryption DESEncryption; +typedef DES::Decryption DESDecryption; + +typedef DES_EDE2::Encryption DES_EDE2_Encryption; +typedef DES_EDE2::Decryption DES_EDE2_Decryption; + +typedef DES_EDE3::Encryption DES_EDE3_Encryption; +typedef DES_EDE3::Decryption DES_EDE3_Decryption; + +typedef DES_XEX3::Encryption DES_XEX3_Encryption; +typedef DES_XEX3::Decryption DES_XEX3_Decryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/dh.h b/include/cryptlib/dh.h new file mode 100644 index 0000000..e12adba --- /dev/null +++ b/include/cryptlib/dh.h @@ -0,0 +1,275 @@ +// dh.h - originally written and placed in the public domain by Wei Dai + +/// \file dh.h +/// \brief Classes for Diffie-Hellman key exchange + +#ifndef CRYPTOPP_DH_H +#define CRYPTOPP_DH_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "algebra.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Diffie-Hellman domain +/// \tparam GROUP_PARAMETERS group parameters +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details A Diffie-Hellman domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \details For COFACTOR_OPTION, see CofactorMultiplicationOption. +/// \sa DL_SimpleKeyAgreementDomainBase +/// \since Crypto++ 1.0 +template +class DH_Domain : public DL_SimpleKeyAgreementDomainBase +{ + typedef DL_SimpleKeyAgreementDomainBase Base; + +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef DL_KeyAgreementAlgorithm_DH DH_Algorithm; + typedef DH_Domain Domain; + + virtual ~DH_Domain() {} + + /// \brief Construct a Diffie-Hellman domain + DH_Domain() {} + + /// \brief Construct a Diffie-Hellman domain + /// \param params group parameters and options + DH_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + /// \brief Construct a Diffie-Hellman domain + /// \param bt BufferedTransformation with group parameters and options + DH_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 fourth parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 fourth parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Generate a public key from a private key in this domain + /// \param rng RandomNumberGenerator derived class + /// \param privateKey byte buffer with the previously generated private key + /// \param publicKey byte buffer for the generated public key in this domain + /// \details If using a FIPS 140-2 validated library on Windows, then this class will perform + /// a self test to ensure the key pair is pairwise consistent. Non-FIPS and non-Windows + /// builds of the library do not provide FIPS validated cryptography, so the code should be + /// removed by the optimizer. + /// \pre COUNTOF(publicKey) == PublicKeyLength() + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + Base::GeneratePublicKey(rng, privateKey, publicKey); + + if (FIPS_140_2_ComplianceEnabled()) + { + SecByteBlock privateKey2(this->PrivateKeyLength()); + this->GeneratePrivateKey(rng, privateKey2); + + SecByteBlock publicKey2(this->PublicKeyLength()); + Base::GeneratePublicKey(rng, privateKey2, publicKey2); + + SecByteBlock agreedValue(this->AgreedValueLength()), agreedValue2(this->AgreedValueLength()); + bool agreed1 = this->Agree(agreedValue, privateKey, publicKey2); + bool agreed2 = this->Agree(agreedValue2, privateKey2, publicKey); + + if (!agreed1 || !agreed2 || agreedValue != agreedValue2) + throw SelfTestFailure(this->AlgorithmName() + ": pairwise consistency test failed"); + } + } + + static std::string CRYPTOPP_API StaticAlgorithmName() + {return GroupParameters::StaticAlgorithmNamePrefix() + DH_Algorithm::StaticAlgorithmName();} + std::string AlgorithmName() const {return StaticAlgorithmName();} + +private: + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {return Singleton().Ref();} + DL_GroupParameters & AccessAbstractGroupParameters() + {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DH_Domain; + +/// \brief Diffie-Hellman in GF(p) +/// \details DH() class is a typedef of DH_Domain(). The documentation that follows +/// does not exist. Rather the documentation was created in response to Issue +/// 328, Diffie-Hellman example code not compiling. +/// \details Generally speaking, a DH() object is ephemeral and is intended to execute one instance of the Diffie-Hellman protocol. The +/// private and public key parts are not intended to be set or persisted. Rather, a new set of domain parameters are generated each +/// time an object is created. +/// \details Once a DH() object is created, once can retrieve the ephemeral public key for the other party with code similar to the +/// following. +///
   AutoSeededRandomPool prng;
+///   Integer p, q, g;
+///   PrimeAndGenerator pg;
+///
+///   pg.Generate(1, prng, 512, 511);
+///   p = pg.Prime();
+///   q = pg.SubPrime();
+///   g = pg.Generator();
+///
+///   DH dh(p, q, g);
+///   SecByteBlock t1(dh.PrivateKeyLength()), t2(dh.PublicKeyLength());
+///   dh.GenerateKeyPair(prng, t1, t2);
+///   Integer k1(t1, t1.size()), k2(t2, t2.size());
+///
+///   cout << "Private key:\n";
+///   cout << hex << k1 << endl;
+///
+///   cout << "Public key:\n";
+///   cout << hex << k2 << endl;
+/// +/// \details Output of the program above will be similar to the following. +///
   $ ./cryptest.exe
+///   Private key:
+///   72b45a42371545e9d4880f48589aefh
+///   Public key:
+///   45fdb13f97b1840626f0250cec1dba4a23b894100b51fb5d2dd13693d789948f8bfc88f9200014b2
+///   ba8dd8a6debc471c69ef1e2326c61184a2eca88ec866346bh
+/// \sa Diffie-Hellman on the Crypto++ wiki and +/// Diffie-Hellman in GF(p) with key validation +/// \since Crypto++ 1.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +struct DH : public DH_Domain +{ + typedef DH_Domain GroupParameters; + typedef GroupParameters::Element Element; + + virtual ~DH() {} + + /// \brief Create an uninitialized Diffie-Hellman object + DH() : DH_Domain() {} + + /// \brief Initialize a Diffie-Hellman object + /// \param bt BufferedTransformation with group parameters and options + DH(BufferedTransformation &bt) : DH_Domain(bt) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param params group parameters and options + DH(const GroupParameters ¶ms) : DH_Domain(params) {} + + /// \brief Create a Diffie-Hellman object + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new Diffie-Hellman object because it + /// takes a RandomNumberGenerator() as a parameter. + DH(RandomNumberGenerator &rng, unsigned int modulusBits) : DH_Domain(rng, modulusBits) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param g the generator + DH(const Integer &p, const Integer &g) : DH_Domain(p, g) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + DH(const Integer &p, const Integer &q, const Integer &g) : DH_Domain(p, q, g) {} + + /// \brief Creates a Diffie-Hellman object + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new Diffie-Hellman object because it + /// takes a RandomNumberGenerator() as a parameter. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {AccessGroupParameters().Initialize(rng, modulusBits);} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param g the generator + void Initialize(const Integer &p, const Integer &g) + {AccessGroupParameters().Initialize(p, g);} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + void Initialize(const Integer &p, const Integer &q, const Integer &g) + {AccessGroupParameters().Initialize(p, q, g);} +}; +#else +// The real DH class is a typedef. +typedef DH_Domain DH; +#endif + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/dh2.h b/include/cryptlib/dh2.h new file mode 100644 index 0000000..6cbfe46 --- /dev/null +++ b/include/cryptlib/dh2.h @@ -0,0 +1,70 @@ +// dh2.h - originally written and placed in the public domain by Wei Dai + +/// \file dh2.h +/// \brief Classes for Unified Diffie-Hellman key exchange +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_DH2_H +#define CRYPTOPP_DH2_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Unified Diffie-Hellman in GF(p) +/// \details A Diffie-Hellman domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \sa AuthenticatedKeyAgreementDomain, Unified Diffie-Hellman +/// \since Crypto++ 3.0 +class DH2 : public AuthenticatedKeyAgreementDomain +{ +public: + virtual ~DH2() {} + + /// \brief Construct a DH2 + DH2(SimpleKeyAgreementDomain &domain) + : d1(domain), d2(domain) {} + /// \brief Construct a DH2 + DH2(SimpleKeyAgreementDomain &staticDomain, SimpleKeyAgreementDomain &ephemeralDomain) + : d1(staticDomain), d2(ephemeralDomain) {} + + CryptoParameters & AccessCryptoParameters() {return d1.AccessCryptoParameters();} + + unsigned int AgreedValueLength() const + {return d1.AgreedValueLength() + d2.AgreedValueLength();} + + unsigned int StaticPrivateKeyLength() const + {return d1.PrivateKeyLength();} + unsigned int StaticPublicKeyLength() const + {return d1.PublicKeyLength();} + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d1.GeneratePrivateKey(rng, privateKey);} + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d1.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d1.GenerateKeyPair(rng, privateKey, publicKey);} + + unsigned int EphemeralPrivateKeyLength() const + {return d2.PrivateKeyLength();} + unsigned int EphemeralPublicKeyLength() const + {return d2.PublicKeyLength();} + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d2.GeneratePrivateKey(rng, privateKey);} + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d2.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d2.GenerateKeyPair(rng, privateKey, publicKey);} + + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const; + +protected: + SimpleKeyAgreementDomain &d1, &d2; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/dll.h b/include/cryptlib/dll.h new file mode 100644 index 0000000..8ffbb9d --- /dev/null +++ b/include/cryptlib/dll.h @@ -0,0 +1,72 @@ +// dll.h - originally written and placed in the public domain by Wei Dai + +/// \file dll.h +/// \brief Functions and definitions required for building the FIPS-140 DLL on Windows + +#ifndef CRYPTOPP_DLL_H +#define CRYPTOPP_DLL_H + +#if !defined(CRYPTOPP_IMPORTS) && !defined(CRYPTOPP_EXPORTS) && !defined(CRYPTOPP_DEFAULT_NO_DLL) +#ifdef CRYPTOPP_CONFIG_H +#error To use the DLL version of Crypto++, this file must be included before any other Crypto++ header files. +#endif +#define CRYPTOPP_IMPORTS +#endif + +#include "aes.h" +#include "cbcmac.h" +#include "ccm.h" +#include "cmac.h" +#include "channels.h" +#include "des.h" +#include "dh.h" +#include "dsa.h" +#include "ec2n.h" +#include "eccrypto.h" +#include "ecp.h" +#include "files.h" +#include "fips140.h" +#include "gcm.h" +#include "hex.h" +#include "hmac.h" +#include "modes.h" +#include "mqueue.h" +#include "nbtheory.h" +#include "osrng.h" +#include "pkcspad.h" +#include "pssr.h" +#include "randpool.h" +#include "rsa.h" +#include "rw.h" +#include "sha.h" +#include "skipjack.h" +#include "trdlocal.h" + +#ifdef CRYPTOPP_IMPORTS + +#ifdef _DLL +// cause CRT DLL to be initialized before Crypto++ so that we can use malloc and free during DllMain() +#ifdef CRYPTOPP_DEBUG +# pragma comment(lib, "msvcrtd") +# pragma comment(lib, "cryptopp") +#else +# pragma comment(lib, "msvcrt") +# pragma comment(lib, "cryptopp") +#endif +#endif + +#endif // #ifdef CRYPTOPP_IMPORTS + +#include // for new_handler + +NAMESPACE_BEGIN(CryptoPP) + +typedef void * (CRYPTOPP_API * PNew)(size_t); +typedef void (CRYPTOPP_API * PDelete)(void *); +typedef void (CRYPTOPP_API * PGetNewAndDelete)(PNew &, PDelete &); +typedef std::new_handler (CRYPTOPP_API * PSetNewHandler)(std::new_handler); +typedef void (CRYPTOPP_API * PSetNewAndDelete)(PNew, PDelete, PSetNewHandler); + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/dmac.h b/include/cryptlib/dmac.h new file mode 100644 index 0000000..6dacc3c --- /dev/null +++ b/include/cryptlib/dmac.h @@ -0,0 +1,106 @@ +// dmac.h - originally written and placed in the public domain by Wei Dai + +/// \file dmac.h +/// \brief Classes for DMAC message authentication code + +#ifndef CRYPTOPP_DMAC_H +#define CRYPTOPP_DMAC_H + +#include "cbcmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DMAC message authentication code base class +/// \tparam T class derived from BlockCipherDocumentation +/// \since Crypto++ 3.1 +template +class CRYPTOPP_NO_VTABLE DMAC_Base : public SameKeyLengthAs, public MessageAuthenticationCode +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE) + static std::string StaticAlgorithmName() {return std::string("DMAC(") + T::StaticAlgorithmName() + ")";} + + virtual~DMAC_Base() {} + DMAC_Base() : m_subkeylength(0), m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + +private: + byte *GenerateSubKeys(const byte *key, size_t keylength); + + size_t m_subkeylength; + SecByteBlock m_subkeys; + CBC_MAC m_mac1; + typename T::Encryption m_f2; + unsigned int m_counter; +}; + +/// \brief DMAC message authentication code +/// \tparam T class derived from BlockCipherDocumentation +/// \sa CBC MAC for Real-Time Data Sources (08.15.1997) +/// by Erez Petrank and Charles Rackoff +/// \since Crypto++ 3.1 +template +class DMAC : public MessageAuthenticationCodeFinal > +{ +public: + /// \brief Construct a DMAC + DMAC() {} + + /// \brief Construct a DMAC + /// \param key a byte array used to key the cipher + /// \param length the size of the byte array, in bytes + DMAC(const byte *key, size_t length=DMAC_Base::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} +}; + +template +void DMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + m_subkeylength = T::StaticGetValidKeyLength(T::BLOCKSIZE); + m_subkeys.resize(2*UnsignedMin((unsigned int)T::BLOCKSIZE, m_subkeylength)); + m_mac1.SetKey(GenerateSubKeys(key, length), m_subkeylength, params); + m_f2.SetKey(m_subkeys+m_subkeys.size()/2, m_subkeylength, params); + m_counter = 0; + m_subkeys.resize(0); +} + +template +void DMAC_Base::Update(const byte *input, size_t length) +{ + m_mac1.Update(input, length); + m_counter = (unsigned int)((m_counter + length) % T::BLOCKSIZE); +} + +template +void DMAC_Base::TruncatedFinal(byte *mac, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + byte pad[T::BLOCKSIZE]; + byte padByte = byte(T::BLOCKSIZE-m_counter); + memset(pad, padByte, padByte); + m_mac1.Update(pad, padByte); + m_mac1.TruncatedFinal(mac, size); + m_f2.ProcessBlock(mac); + + m_counter = 0; // reset for next message +} + +template +byte *DMAC_Base::GenerateSubKeys(const byte *key, size_t keylength) +{ + typename T::Encryption cipher(key, keylength); + memset(m_subkeys, 0, m_subkeys.size()); + cipher.ProcessBlock(m_subkeys); + m_subkeys[m_subkeys.size()/2 + T::BLOCKSIZE - 1] = 1; + cipher.ProcessBlock(m_subkeys+m_subkeys.size()/2); + return m_subkeys; +} + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/drbg.h b/include/cryptlib/drbg.h new file mode 100644 index 0000000..07e8cf4 --- /dev/null +++ b/include/cryptlib/drbg.h @@ -0,0 +1,745 @@ +// drbg.h - written and placed in public domain by Jeffrey Walton. + +/// \file drbg.h +/// \brief Classes for NIST DRBGs from SP 800-90A +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_NIST_DRBG_H +#define CRYPTOPP_NIST_DRBG_H + +#include "cryptlib.h" +#include "secblock.h" +#include "hmac.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Interface for NIST DRBGs from SP 800-90A +/// \details NIST_DRBG is the base class interface for NIST DRBGs from SP 800-90A Rev 1 (June 2015) +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +class NIST_DRBG : public RandomNumberGenerator +{ +public: + /// \brief Exception thrown when a NIST DRBG encounters an error + class Err : public Exception + { + public: + explicit Err(const std::string &c, const std::string &m) + : Exception(OTHER_ERROR, c + ": " + m) {} + }; + +public: + virtual ~NIST_DRBG() {} + + /// \brief Determines if a generator can accept additional entropy + /// \return true + /// \details All NIST_DRBG return true + virtual bool CanIncorporateEntropy() const {return true;} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy + /// \details NIST instantiation and reseed requirements demand the generator is constructed + /// with at least MINIMUM_ENTROPY entropy. The byte array for input must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *input, size_t length)=0; + + /// \brief Update RNG state with additional unpredictable values + /// \param entropy the entropy to add to the generator + /// \param entropyLength the size of the input buffer + /// \param additional additional input to add to the generator + /// \param additionaLength the size of the additional input buffer + /// \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy + /// \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST + /// instantiation and reseed requirements demand the generator is constructed with at least + /// MINIMUM_ENTROPY entropy. The byte array for entropy must meet + /// NIST SP 800-90B or + ///! SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \throws NIST_DRBG::Err if a reseed is required + /// \throws NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + virtual void GenerateBlock(byte *output, size_t size)=0; + + /// \brief Generate random array of bytes + /// \param additional additional input to add to the generator + /// \param additionaLength the size of the additional input buffer + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \throws NIST_DRBG::Err if a reseed is required + /// \throws NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + /// \details GenerateBlock() is an overload provided to match NIST requirements. The byte + /// array for additional input is optional. If present the additional randomness + /// is mixed before generating the output bytes. + virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0; + + /// \brief Provides the security strength + /// \returns The security strength of the generator, in bytes + /// \details The equivalent class constant is SECURITY_STRENGTH + virtual unsigned int SecurityStrength() const=0; + + /// \brief Provides the seed length + /// \returns The seed size of the generator, in bytes + /// \details The equivalent class constant is SEED_LENGTH. The size is + /// used to maintain internal state of V and C. + virtual unsigned int SeedLength() const=0; + + /// \brief Provides the minimum entropy size + /// \returns The minimum entropy size required by the generator, in bytes + /// \details The equivalent class constant is MINIMUM_ENTROPY. All NIST DRBGs must + /// be instaniated with at least MINIMUM_ENTROPY bytes of entropy. The bytes must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. + virtual unsigned int MinEntropyLength() const=0; + + /// \brief Provides the maximum entropy size + /// \returns The maximum entropy size that can be consumed by the generator, in bytes + /// \details The equivalent class constant is MAXIMUM_ENTROPY. The bytes must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. MAXIMUM_ENTROPY has been reduced from + /// 235 to INT_MAX to fit the underlying C++ datatype. + virtual unsigned int MaxEntropyLength() const=0; + + /// \brief Provides the minimum nonce size + /// \returns The minimum nonce size recommended for the generator, in bytes + /// \details The equivalent class constant is MINIMUM_NONCE. If a nonce is not + /// required then MINIMUM_NONCE is 0. Hash_DRBG does not require a + /// nonce, while HMAC_DRBG and CTR_DRBG require a nonce. + virtual unsigned int MinNonceLength() const=0; + + /// \brief Provides the maximum nonce size + /// \returns The maximum nonce that can be consumed by the generator, in bytes + /// \details The equivalent class constant is MAXIMUM_NONCE. MAXIMUM_NONCE + /// has been reduced from 235 to INT_MAX to fit the underlying C++ datatype. + /// If a nonce is not required then MINIMUM_NONCE is 0. Hash_DRBG does not + /// require a nonce, while HMAC_DRBG and CTR_DRBG require a nonce. + virtual unsigned int MaxNonceLength() const=0; + + /// \brief Provides the maximum size of a request to GenerateBlock + /// \returns The the maximum size of a request to GenerateBlock(), in bytes + /// \details The equivalent class constant is MAXIMUM_BYTES_PER_REQUEST + virtual unsigned int MaxBytesPerRequest() const=0; + + /// \brief Provides the maximum number of requests before a reseed + /// \returns The the maximum number of requests before a reseed, in bytes + /// \details The equivalent class constant is MAXIMUM_REQUESTS_BEFORE_RESEED. + /// MAXIMUM_REQUESTS_BEFORE_RESEED has been reduced from 248 to INT_MAX + /// to fit the underlying C++ datatype. + virtual unsigned int MaxRequestBeforeReseed() const=0; + +protected: + virtual void DRBG_Instantiate(const byte* entropy, size_t entropyLength, + const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength)=0; + + virtual void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; +}; + +// ************************************************************* + +/// \tparam HASH NIST approved hash derived from HashTransformation +/// \tparam STRENGTH security strength, in bytes +/// \tparam SEEDLENGTH seed length, in bytes +/// \brief Hash_DRBG from SP 800-90A Rev 1 (June 2015) +/// \details The NIST Hash DRBG is instantiated with a number of parameters. Two of the parameters, +/// Security Strength and Seed Length, depend on the hash and are specified as template parameters. +/// The remaining parameters are included in the class. The parameters and their values are listed +/// in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38). +/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto +/// 248 requests before a reseed. However, Hash_DRBG limits it to INT_MAX due +/// to the limited data range of an int. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +template +class Hash_DRBG : public NIST_DRBG, public NotCopyable +{ +public: + CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH) + CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH) + CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH) + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0) + CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0) + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0) + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536) + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX) + + static std::string StaticAlgorithmName() { return std::string("Hash_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } + + /// \brief Construct a Hash DRBG + /// \param entropy the entropy to instantiate the generator + /// \param entropyLength the size of the entropy buffer + /// \param nonce additional input to instantiate the generator + /// \param nonceLength the size of the nonce buffer + /// \param personalization additional input to instantiate the generator + /// \param personalizationLength the size of the personalization buffer + /// \throws NIST_DRBG::Err if the generator is instantiated with insufficient entropy + /// \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy. + /// The byte array for entropy must meet NIST + /// SP 800-90B or SP 800-90C requirements. + /// \details The nonce and personalization are optional byte arrays. If nonce is supplied, + /// then it should be at least MINIMUM_NONCE bytes of entropy. + /// \details An example of instantiating a SHA256 generator is shown below. + /// The example provides more entropy than required for SHA256. The NonblockingRng meets the + /// requirements of NIST SP 800-90B or SP 800-90C. + /// RDRAND() and RDSEED() generators would work as well. + ///
+    ///    SecByteBlock entropy(48), result(128);
+    ///    NonblockingRng prng;
+    ///    RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///    Hash_DRBG drbg(entropy, 32, entropy+32, 16);
+    ///    drbg.GenerateBlock(result, result.size());
+    /// 
+ Hash_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, + size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) + : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH), m_reseed(0) + { + if (entropy != NULLPTR && entropyLength != 0) + DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + } + + unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} + unsigned int SeedLength() const {return SEED_LENGTH;} + unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} + unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} + unsigned int MinNonceLength() const {return MINIMUM_NONCE;} + unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} + unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} + unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} + + void IncorporateEntropy(const byte *input, size_t length) + {return DRBG_Reseed(input, length, NULLPTR, 0);} + + void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength) + {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);} + + void GenerateBlock(byte *output, size_t size) + {return Hash_Generate(NULLPTR, 0, output, size);} + + void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) + {return Hash_Generate(additional, additionaLength, output, size);} + +protected: + // 10.1.1.2 Instantiation of Hash_DRBG (p.39) + void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength); + + // 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40) + void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength); + + // 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41) + void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size); + + // 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49) + void Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, + const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen); + +private: + SecByteBlock m_c, m_v; + word64 m_reseed; +}; + +// typedef Hash_DRBG Hash_SHA1_DRBG; +// typedef Hash_DRBG Hash_SHA256_DRBG; +// typedef Hash_DRBG Hash_SHA384_DRBG; +// typedef Hash_DRBG Hash_SHA512_DRBG; + +// ************************************************************* + +/// \tparam HASH NIST approved hash derived from HashTransformation +/// \tparam STRENGTH security strength, in bytes +/// \tparam SEEDLENGTH seed length, in bytes +/// \brief HMAC_DRBG from SP 800-90A Rev 1 (June 2015) +/// \details The NIST HMAC DRBG is instantiated with a number of parameters. Two of the parameters, +/// Security Strength and Seed Length, depend on the hash and are specified as template parameters. +/// The remaining parameters are included in the class. The parameters and their values are listed +/// in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38). +/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto 248 requests +/// before a reseed. However, HMAC_DRBG limits it to INT_MAX due to the limited data range of an int. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +template +class HMAC_DRBG : public NIST_DRBG, public NotCopyable +{ +public: + CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH) + CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH) + CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH) + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0) + CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0) + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0) + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536) + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX) + + static std::string StaticAlgorithmName() { return std::string("HMAC_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } + + /// \brief Construct a HMAC DRBG + /// \param entropy the entropy to instantiate the generator + /// \param entropyLength the size of the entropy buffer + /// \param nonce additional input to instantiate the generator + /// \param nonceLength the size of the nonce buffer + /// \param personalization additional input to instantiate the generator + /// \param personalizationLength the size of the personalization buffer + /// \throws NIST_DRBG::Err if the generator is instantiated with insufficient entropy + /// \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy. + /// The byte array for entropy must meet NIST + /// SP 800-90B or SP 800-90C requirements. + /// \details The nonce and personalization are optional byte arrays. If nonce is supplied, + /// then it should be at least MINIMUM_NONCE bytes of entropy. + /// \details An example of instantiating a SHA256 generator is shown below. + /// The example provides more entropy than required for SHA256. The NonblockingRng meets the + /// requirements of NIST SP 800-90B or SP 800-90C. + /// RDRAND() and RDSEED() generators would work as well. + ///
+    ///    SecByteBlock entropy(48), result(128);
+    ///    NonblockingRng prng;
+    ///    RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///    HMAC_DRBG drbg(entropy, 32, entropy+32, 16);
+    ///    drbg.GenerateBlock(result, result.size());
+    /// 
+ HMAC_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, + size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) + : NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE), m_reseed(0) + { + if (entropy != NULLPTR && entropyLength != 0) + DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + } + + unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} + unsigned int SeedLength() const {return SEED_LENGTH;} + unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} + unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} + unsigned int MinNonceLength() const {return MINIMUM_NONCE;} + unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} + unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} + unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} + + void IncorporateEntropy(const byte *input, size_t length) + {return DRBG_Reseed(input, length, NULLPTR, 0);} + + void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength) + {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);} + + void GenerateBlock(byte *output, size_t size) + {return HMAC_Generate(NULLPTR, 0, output, size);} + + void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) + {return HMAC_Generate(additional, additionaLength, output, size);} + +protected: + // 10.1.2.3 Instantiation of HMAC_DRBG (p.45) + void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength); + + // 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46) + void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength); + + // 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46) + void HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size); + + // 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44) + void HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3); + +private: + SecByteBlock m_k, m_v; + word64 m_reseed; +}; + +// typedef HMAC_DRBG HMAC_SHA1_DRBG; +// typedef HMAC_DRBG HMAC_SHA256_DRBG; +// typedef HMAC_DRBG HMAC_SHA384_DRBG; +// typedef HMAC_DRBG HMAC_SHA512_DRBG; + +// ************************************************************* + +// 10.1.1.2 Instantiation of Hash_DRBG (p.39) +template +void Hash_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during instantiate"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE); + CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION); + + const byte zero = 0; + SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); + Hash_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength, NULLPTR, 0, t1, t1.size()); + Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size()); + + m_v.swap(t1); m_c.swap(t2); + m_reseed = 1; +} + +// 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40) +template +void Hash_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state.. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during reseed"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + const byte zero = 0, one = 1; + SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); + Hash_Update(&one, 1, m_v, m_v.size(), entropy, entropyLength, additional, additionaLength, t1, t1.size()); + Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size()); + + m_v.swap(t1); m_c.swap(t2); + m_reseed = 1; +} + +// 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41) +template +void Hash_DRBG::Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) +{ + // Step 1 + if (static_cast(m_reseed) >= static_cast(MaxRequestBeforeReseed())) + throw NIST_DRBG::Err("Hash_DRBG", "Reseed required"); + + if (size > MaxBytesPerRequest()) + throw NIST_DRBG::Err("Hash_DRBG", "Request size exceeds limit"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + // Step 2 + if (additional && additionaLength) + { + HASH hash; + const byte two = 2; + SecByteBlock w(HASH::DIGESTSIZE); + + hash.Update(&two, 1); + hash.Update(m_v, m_v.size()); + hash.Update(additional, additionaLength); + hash.Final(w); + + CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); + int carry=0, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; + while (j>=0) + { + carry = m_v[i] + w[j] + carry; + m_v[i] = static_cast(carry); + i--; j--; carry >>= 8; + } + while (i>=0) + { + carry = m_v[i] + carry; + m_v[i] = static_cast(carry); + i--; carry >>= 8; + } + } + + // Step 3 + { + HASH hash; + SecByteBlock data(m_v); + + while (size) + { + hash.Update(data, data.size()); + size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(output, count); + + IncrementCounterByOne(data, static_cast(data.size())); + size -= count; output += count; + } + } + + // Steps 4-7 + { + HASH hash; + const byte three = 3; + SecByteBlock h(HASH::DIGESTSIZE); + + hash.Update(&three, 1); + hash.Update(m_v, m_v.size()); + hash.Final(h); + + CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); + CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed)); + int carry=0, k=sizeof(m_reseed)-1, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; + + // Using Integer class slows things down by about 8 cpb. + // Using word128 and word64 benefits the first loop only by about 2 cpb. +#if defined(CRYPTOPP_WORD128_AVAILABLE) + byte* p1 = m_v.begin()+SEEDLENGTH-8; + byte* p2 = m_c.begin()+SEEDLENGTH-8; + byte* p3 = h.begin()+HASH::DIGESTSIZE-8; + + const word64 w1 = GetWord(false, BIG_ENDIAN_ORDER, p1); + const word64 w2 = GetWord(false, BIG_ENDIAN_ORDER, p2); + const word64 w3 = GetWord(false, BIG_ENDIAN_ORDER, p3); + const word64 w4 = m_reseed; + + word128 r = static_cast(w1) + w2 + w3 + w4; + PutWord(false, BIG_ENDIAN_ORDER, p1, static_cast(r)); + i -= 8; j -= 8; k=0; carry = static_cast(r >> 64); + + // The default implementation and a couple of others cause a crash in + // VS2005, VS2008 and VS2105. This seems to work with all MS compilers. +#elif defined(CRYPTOPP_MSC_VERSION) + byte* p1 = m_v.begin()+SEEDLENGTH-8; + byte* p2 = m_c.begin()+SEEDLENGTH-8; + byte* p3 = h.begin()+HASH::DIGESTSIZE-8; + + const word64 w1 = GetWord(false, BIG_ENDIAN_ORDER, p1); + const word64 w2 = GetWord(false, BIG_ENDIAN_ORDER, p2); + const word64 w3 = GetWord(false, BIG_ENDIAN_ORDER, p3); + const word64 w4 = m_reseed; + + const word64 r1 = (w1 & 0xffffffff) + (w2 & 0xffffffff) + (w3 & 0xffffffff) + (w4 & 0xffffffff); + carry = static_cast(r1 >> 32); + const word64 r2 = (w1 >> 32) + (w2 >> 32) + (w3 >> 32) + (w4 >> 32) + carry; + carry = static_cast(r2 >> 32); + + const word64 r = (r2 << 32) + (r1 & 0xffffffff); + PutWord(false, BIG_ENDIAN_ORDER, p1, r); + i -= 8; j -= 8; k=0; + + // Default implementation, but slower on some machines. +#else + while (k>=0) + { + carry = m_v[i] + m_c[i] + h[j] + GetByte(BIG_ENDIAN_ORDER, m_reseed, k) + carry; + m_v[i] = static_cast(carry); + i--; j--; k--; carry >>= 8; + } +#endif + + while (j>=0) + { + carry = m_v[i] + m_c[i] + h[j] + carry; + m_v[i] = static_cast(carry); + i--; j--; carry >>= 8; + } + + while (i>=0) + { + carry = m_v[i] + m_c[i] + carry; + m_v[i] = static_cast(carry); + i--; carry >>= 8; + } + + // CRYPTOPP_WORD128_AVAILABLE causes -Wunused-but-set-variable + CRYPTOPP_UNUSED(k); + } + + m_reseed++; +} + +// 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49) +template +void Hash_DRBG::Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, + const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen) +{ + HASH hash; + byte counter = 1; + word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast(outlen*8)); + + while (outlen) + { + hash.Update(&counter, 1); + hash.Update(reinterpret_cast(&bits), 4); + + if (input1 && inlen1) + hash.Update(input1, inlen1); + if (input2 && inlen2) + hash.Update(input2, inlen2); + if (input3 && inlen3) + hash.Update(input3, inlen3); + if (input4 && inlen4) + hash.Update(input4, inlen4); + + size_t count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(output, count); + + output += count; outlen -= count; + counter++; + } +} + +// ************************************************************* + +// 10.1.2.3 Instantiation of HMAC_DRBG (p.45) +template +void HMAC_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during instantiate"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE); + CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION); + + std::fill(m_k.begin(), m_k.begin()+m_k.size(), byte(0)); + std::fill(m_v.begin(), m_v.begin()+m_v.size(), byte(1)); + + HMAC_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + m_reseed = 1; +} + +// 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46) +template +void HMAC_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state.. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during reseed"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + HMAC_Update(entropy, entropyLength, additional, additionaLength, NULLPTR, 0); + m_reseed = 1; +} + +// 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46) +template +void HMAC_DRBG::HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) +{ + // Step 1 + if (static_cast(m_reseed) >= static_cast(MaxRequestBeforeReseed())) + throw NIST_DRBG::Err("HMAC_DRBG", "Reseed required"); + + if (size > MaxBytesPerRequest()) + throw NIST_DRBG::Err("HMAC_DRBG", "Request size exceeds limit"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + // Step 2 + if (additional && additionaLength) + HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0); + + // Step 3 + HMAC hmac; + hmac.SetKey(m_k, m_k.size()); + + while (size) + { + hmac.Update(m_v, m_v.size()); + hmac.TruncatedFinal(m_v, m_v.size()); + + size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); + memcpy(output, m_v, count); + + size -= count; output += count; + } + + HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0); + m_reseed++; +} + +// 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44) +template +void HMAC_DRBG::HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3) +{ + const byte zero = 0, one = 1; + HMAC hmac; + + // Step 1 + hmac.SetKey(m_k, m_k.size()); + hmac.Update(m_v, m_v.size()); + hmac.Update(&zero, 1); + + if (input1 && inlen1) + hmac.Update(input1, inlen1); + if (input2 && inlen2) + hmac.Update(input2, inlen2); + if (input3 && inlen3) + hmac.Update(input3, inlen3); + + hmac.TruncatedFinal(m_k, m_k.size()); + + // Step 2 + hmac.SetKey(m_k, m_k.size()); + hmac.Update(m_v, m_v.size()); + + hmac.TruncatedFinal(m_v, m_v.size()); + + // Step 3 + if ((inlen1 | inlen2 | inlen3) == 0) + return; + + // Step 4 + hmac.SetKey(m_k, m_k.size()); + hmac.Update(m_v, m_v.size()); + hmac.Update(&one, 1); + + if (input1 && inlen1) + hmac.Update(input1, inlen1); + if (input2 && inlen2) + hmac.Update(input2, inlen2); + if (input3 && inlen3) + hmac.Update(input3, inlen3); + + hmac.TruncatedFinal(m_k, m_k.size()); + + // Step 5 + hmac.SetKey(m_k, m_k.size()); + hmac.Update(m_v, m_v.size()); + + hmac.TruncatedFinal(m_v, m_v.size()); +} + +NAMESPACE_END + +#endif // CRYPTOPP_NIST_DRBG_H diff --git a/include/cryptlib/dsa.h b/include/cryptlib/dsa.h new file mode 100644 index 0000000..e66feed --- /dev/null +++ b/include/cryptlib/dsa.h @@ -0,0 +1,42 @@ +// dsa.h - originally written and placed in the public domain by Wei Dai + +/// \file dsa.h +/// \brief Classes for the DSA signature algorithm + +#ifndef CRYPTOPP_DSA_H +#define CRYPTOPP_DSA_H + +#include "cryptlib.h" +#include "gfpcrypt.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DSA Signature Format +/// \details The DSA signature format used by Crypto++ is as defined by IEEE P1363. +/// Java and .Net use the DER format, and OpenPGP uses the OpenPGP format. +enum DSASignatureFormat { + /// \brief Crypto++ native signature encoding format + DSA_P1363, + /// \brief signature encoding format used by Java and .Net + DSA_DER, + /// \brief OpenPGP signature encoding format + DSA_OPENPGP +}; + +/// \brief Converts between signature encoding formats +/// \param buffer byte buffer for the converted signature encoding +/// \param bufferSize the length of the converted signature encoding buffer +/// \param toFormat the source signature format +/// \param signature byte buffer for the existing signature encoding +/// \param signatureLen the length of the existing signature encoding buffer +/// \param fromFormat the source signature format +/// \details This function converts between these formats, and returns length +/// of signature in the target format. If toFormat == DSA_P1363, then +/// bufferSize must equal publicKey.SignatureLength() +/// \since Crypto++ 1.0 +size_t DSAConvertSignatureFormat(byte *buffer, size_t bufferSize, DSASignatureFormat toFormat, + const byte *signature, size_t signatureLen, DSASignatureFormat fromFormat); + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/eax.h b/include/cryptlib/eax.h new file mode 100644 index 0000000..5487212 --- /dev/null +++ b/include/cryptlib/eax.h @@ -0,0 +1,108 @@ +// eax.h - originally written and placed in the public domain by Wei Dai + +/// \file eax.h +/// \brief EAX block cipher mode of operation + +#ifndef CRYPTOPP_EAX_H +#define CRYPTOPP_EAX_H + +#include "authenc.h" +#include "modes.h" +#include "cmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief EAX block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_NO_VTABLE EAX_Base : public AuthenticatedSymmetricCipherBase +{ +public: + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetMAC().GetCipher().AlgorithmName() + std::string("/EAX");} + size_t MinKeyLength() const + {return GetMAC().MinKeyLength();} + size_t MaxKeyLength() const + {return GetMAC().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetMAC().DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const + {return GetMAC().GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const + {return GetMAC().IsValidKeyLength(n);} + unsigned int OptimalDataAlignment() const + {return GetMAC().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return GetMAC().TagSize();} + unsigned int MinIVLength() const + {return 0;} + unsigned int MaxIVLength() const + {return UINT_MAX;} + unsigned int DigestSize() const + {return GetMAC().TagSize();} + lword MaxHeaderLength() const + {return LWORD_MAX;} + lword MaxMessageLength() const + {return LWORD_MAX;} + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return false;} + unsigned int AuthenticationBlockSize() const + {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + const CMAC_Base & GetMAC() const {return const_cast(this)->AccessMAC();} + virtual CMAC_Base & AccessMAC() =0; + + CTR_Mode_ExternalCipher::Encryption m_ctr; +}; + +/// \brief EAX block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class EAX_Final : public EAX_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/EAX");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + CMAC_Base & AccessMAC() {return m_cmac;} + CMAC m_cmac; +}; + +#ifdef EAX // EAX is defined to 11 on GCC 3.4.3, OpenSolaris 8.11 +#undef EAX +#endif + +/// \brief EAX block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \details \p EAX provides the \p Encryption and \p Decryption typedef. See EAX_Base +/// and EAX_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa EAX Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct EAX : public AuthenticatedSymmetricCipherDocumentation +{ + typedef EAX_Final Encryption; + typedef EAX_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/ec2n.h b/include/cryptlib/ec2n.h new file mode 100644 index 0000000..d27904f --- /dev/null +++ b/include/cryptlib/ec2n.h @@ -0,0 +1,137 @@ +// ec2n.h - originally written and placed in the public domain by Wei Dai + +/// \file ec2n.h +/// \brief Classes for Elliptic Curves over binary fields + + +#ifndef CRYPTOPP_EC2N_H +#define CRYPTOPP_EC2N_H + +#include "cryptlib.h" +#include "gf2n.h" +#include "integer.h" +#include "algebra.h" +#include "ecpoint.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve over GF(2^n) +class CRYPTOPP_DLL EC2N : public AbstractGroup, public EncodedPoint +{ +public: + typedef GF2NP Field; + typedef Field::Element FieldElement; + typedef EC2NPoint Point; + + virtual ~EC2N() {} + + /// \brief Construct an EC2N + EC2N() {} + + /// \brief Construct an EC2N + /// \param field Field, GF2NP derived class + /// \param a Field::Element + /// \param b Field::Element + EC2N(const Field &field, const Field::Element &a, const Field::Element &b) + : m_field(field), m_a(a), m_b(b) {} + + /// \brief Construct an EC2N from BER encoded parameters + /// \param bt BufferedTransformation derived object + /// \details This constructor will decode and extract the the fields fieldID and curve of the sequence ECParameters + EC2N(BufferedTransformation &bt); + + /// \brief Encode the fields fieldID and curve of the sequence ECParameters + /// \param bt BufferedTransformation derived object + void DEREncode(BufferedTransformation &bt) const; + + bool Equal(const Point &P, const Point &Q) const; + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*m_field->MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return Integer::Power2(m_field->MaxElementBitLength());} + const Field & GetField() const {return *m_field;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + + bool operator==(const EC2N &rhs) const + {return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;} + +private: + clonable_ptr m_field; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation; + +/// \brief Elliptic Curve precomputation +/// \tparam EC elliptic curve field +template class EcPrecomputation; + +/// \brief EC2N precomputation specialization +/// \details Implementation of DL_GroupPrecomputation +/// \sa DL_GroupPrecomputation +template<> class EcPrecomputation : public DL_GroupPrecomputation +{ +public: + typedef EC2N EllipticCurve; + + virtual ~EcPrecomputation() {} + + // DL_GroupPrecomputation + const AbstractGroup & GetGroup() const {return m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec.BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec.DEREncodePoint(bt, v, false);} + + /// \brief Set the elliptic curve + /// \param ec ECP derived class + /// \details SetCurve() is not inherited + void SetCurve(const EC2N &ec) {m_ec = ec;} + + /// \brief Get the elliptic curve + /// \returns EC2N curve + /// \details GetCurve() is not inherited + const EC2N & GetCurve() const {return m_ec;} + +private: + EC2N m_ec; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/eccrypto.h b/include/cryptlib/eccrypto.h new file mode 100644 index 0000000..c5c3cab --- /dev/null +++ b/include/cryptlib/eccrypto.h @@ -0,0 +1,663 @@ +// eccrypto.h - originally written and placed in the public domain by Wei Dai +// deterministic signatures added by by Douglas Roark + +/// \file eccrypto.h +/// \brief Classes and functions for Elliptic Curves over prime and binary fields + +#ifndef CRYPTOPP_ECCRYPTO_H +#define CRYPTOPP_ECCRYPTO_H + +#include "config.h" +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "hmac.h" +#include "sha.h" +#include "gfpcrypt.h" +#include "dh.h" +#include "mqv.h" +#include "hmqv.h" +#include "fhmqv.h" +#include "ecp.h" +#include "ec2n.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve Parameters +/// \tparam EC elliptic curve field +/// \details This class corresponds to the ASN.1 sequence of the same name +/// in ANSI X9.62 and SEC 1. EC is currently defined for ECP and EC2N. +template +class DL_GroupParameters_EC : public DL_GroupParametersImpl > +{ + typedef DL_GroupParameters_EC ThisClass; + +public: + typedef EC EllipticCurve; + typedef typename EllipticCurve::Point Point; + typedef Point Element; + typedef IncompatibleCofactorMultiplication DefaultCofactorOption; + + virtual ~DL_GroupParameters_EC() {} + + /// \brief Construct an EC GroupParameters + DL_GroupParameters_EC() : m_compress(false), m_encodeAsOID(true) {} + + /// \brief Construct an EC GroupParameters + /// \param oid the OID of a curve + DL_GroupParameters_EC(const OID &oid) + : m_compress(false), m_encodeAsOID(true) {Initialize(oid);} + + /// \brief Construct an EC GroupParameters + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param k the cofactor + DL_GroupParameters_EC(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + : m_compress(false), m_encodeAsOID(true) {Initialize(ec, G, n, k);} + + /// \brief Construct an EC GroupParameters + /// \param bt BufferedTransformation with group parameters + DL_GroupParameters_EC(BufferedTransformation &bt) + : m_compress(false), m_encodeAsOID(true) {BERDecode(bt);} + + /// \brief Initialize an EC GroupParameters using {EC,G,n,k} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param k the cofactor + /// \details This Initialize() function overload initializes group parameters from existing parameters. + void Initialize(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + { + this->m_groupPrecomputation.SetCurve(ec); + this->SetSubgroupGenerator(G); + m_n = n; + m_k = k; + } + + /// \brief Initialize a DL_GroupParameters_EC {EC,G,n,k} + /// \param oid the OID of a curve + /// \details This Initialize() function overload initializes group parameters from existing parameters. + void Initialize(const OID &oid); + + // NameValuePairs + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // GeneratibleCryptoMaterial interface + /// this implementation doesn't actually generate a curve, it just initializes the parameters with existing values + /*! parameters: (Curve, SubgroupGenerator, SubgroupOrder, Cofactor (optional)), or (GroupOID) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // DL_GroupParameters + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return this->m_gpc;} + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return this->m_gpc;} + const Integer & GetSubgroupOrder() const {return m_n;} + Integer GetCofactor() const; + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation *precomp) const; + bool FastSubgroupCheckAvailable() const {return false;} + void EncodeElement(bool reversible, const Element &element, byte *encoded) const + { + if (reversible) + GetCurve().EncodePoint(encoded, element, m_compress); + else + element.x.Encode(encoded, GetEncodedElementSize(false)); + } + virtual unsigned int GetEncodedElementSize(bool reversible) const + { + if (reversible) + return GetCurve().EncodedPointSize(m_compress); + else + return GetCurve().GetField().MaxElementByteLength(); + } + Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const + { + Point result; + if (!GetCurve().DecodePoint(result, encoded, GetEncodedElementSize(true))) + throw DL_BadElement(); + if (checkForGroupMembership && !ValidateElement(1, result, NULLPTR)) + throw DL_BadElement(); + return result; + } + Integer ConvertElementToInteger(const Element &element) const; + Integer GetMaxExponent() const {return GetSubgroupOrder()-1;} + bool IsIdentity(const Element &element) const {return element.identity;} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "EC";} + + // ASN1Key + OID GetAlgorithmID() const; + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + + // non-inherited + + // enumerate OIDs for recommended parameters, use OID() to get first one + static OID CRYPTOPP_API GetNextRecommendedParametersOID(const OID &oid); + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void SetPointCompression(bool compress) {m_compress = compress;} + bool GetPointCompression() const {return m_compress;} + + void SetEncodeAsOID(bool encodeAsOID) {m_encodeAsOID = encodeAsOID;} + bool GetEncodeAsOID() const {return m_encodeAsOID;} + + const EllipticCurve& GetCurve() const {return this->m_groupPrecomputation.GetCurve();} + + bool operator==(const ThisClass &rhs) const + {return this->m_groupPrecomputation.GetCurve() == rhs.m_groupPrecomputation.GetCurve() && this->m_gpc.GetBase(this->m_groupPrecomputation) == rhs.m_gpc.GetBase(rhs.m_groupPrecomputation);} + +protected: + unsigned int FieldElementLength() const {return GetCurve().GetField().MaxElementByteLength();} + unsigned int ExponentLength() const {return m_n.ByteCount();} + + OID m_oid; // set if parameters loaded from a recommended curve + Integer m_n; // order of base point + mutable Integer m_k; // cofactor + mutable bool m_compress, m_encodeAsOID; // presentation details +}; + +/// \brief Elliptic Curve Discrete Log (DL) public key +/// \tparam EC elliptic curve field +template +class DL_PublicKey_EC : public DL_PublicKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PublicKey_EC() {} + + /// \brief Initialize an EC Public Key using {GP,Q} + /// \param params group parameters + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Element &Q) + {this->AccessGroupParameters() = params; this->SetPublicElement(Q);} + + /// \brief Initialize an EC Public Key using {EC,G,n,Q} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve Discrete Log (DL) private key +/// \tparam EC elliptic curve field +template +class DL_PrivateKey_EC : public DL_PrivateKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PrivateKey_EC(); + + /// \brief Initialize an EC Private Key using {GP,x} + /// \param params group parameters + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Integer &x) + {this->AccessGroupParameters() = params; this->SetPrivateExponent(x);} + + /// \brief Initialize an EC Private Key using {EC,G,n,x} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPrivateExponent(x);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param params the EC group parameters + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC ¶ms) + {this->GenerateRandom(rng, params);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {this->GenerateRandom(rng, DL_GroupParameters_EC(ec, G, n));} + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey_EC::~DL_PrivateKey_EC() {} + +/// \brief Elliptic Curve Diffie-Hellman +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \sa CofactorMultiplicationOption, Elliptic Curve Diffie-Hellman, AKA ECDH +/// \since Crypto++ 3.0 +template ::DefaultCofactorOption> +struct ECDH +{ + typedef DH_Domain, COFACTOR_OPTION> Domain; +}; + +/// \brief Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \sa CofactorMultiplicationOption, Elliptic Curve Menezes-Qu-Vanstone, AKA ECMQV +template ::DefaultCofactorOption> +struct ECMQV +{ + typedef MQV_Domain, COFACTOR_OPTION> Domain; +}; + +/// \brief Hashed Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa CofactorMultiplicationOption +template ::DefaultCofactorOption, class HASH = SHA256> +struct ECHMQV +{ + typedef HMQV_Domain, COFACTOR_OPTION, HASH> Domain; +}; + +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA1 >::Domain ECHMQV160; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECHMQV256; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECHMQV384; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECHMQV512; + +/// \brief Fully Hashed Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa CofactorMultiplicationOption +template ::DefaultCofactorOption, class HASH = SHA256> +struct ECFHMQV +{ + typedef FHMQV_Domain, COFACTOR_OPTION, HASH> Domain; +}; + +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA1 >::Domain ECFHMQV160; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECFHMQV256; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECFHMQV384; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECFHMQV512; + +/// \brief Elliptic Curve Discrete Log (DL) keys +/// \tparam EC elliptic curve field +template +struct DL_Keys_EC +{ + typedef DL_PublicKey_EC PublicKey; + typedef DL_PrivateKey_EC PrivateKey; +}; + +// Forward declaration; documented below +template +struct ECDSA; + +/// \brief Elliptic Curve DSA keys +/// \tparam EC elliptic curve field +/// \since Crypto++ 3.2 +template +struct DL_Keys_ECDSA +{ + typedef DL_PublicKey_EC PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA > PrivateKey; +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature algorithm +/// \tparam EC elliptic curve field +/// \since Crypto++ 3.2 +template +class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";} +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature algorithm based on RFC 6979 +/// \tparam EC elliptic curve field +/// \sa RFC 6979, Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +class DL_Algorithm_ECDSA_RFC6979 : public DL_Algorithm_DSA_RFC6979 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA-RFC6979";} +}; + +/// \brief Elliptic Curve NR (ECNR) signature algorithm +/// \tparam EC elliptic curve field +template +class DL_Algorithm_ECNR : public DL_Algorithm_NR +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECNR";} +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa ECDSA +/// \since Crypto++ 3.2 +template +struct ECDSA : public DL_SS, DL_Algorithm_ECDSA, DL_SignatureMessageEncodingMethod_DSA, H> +{ +}; + +/// \brief Elliptic Curve DSA (ECDSA) deterministic signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +struct ECDSA_RFC6979 : public DL_SS< + DL_Keys_ECDSA, + DL_Algorithm_ECDSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + ECDSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECDSA-RFC6979/") + H::StaticAlgorithmName();} +}; + +/// \brief Elliptic Curve NR (ECNR) signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +template +struct ECNR : public DL_SS, DL_Algorithm_ECNR, DL_SignatureMessageEncodingMethod_NR, H> +{ +}; + +// ****************************************** + +template +class DL_PublicKey_ECGDSA; +template +class DL_PrivateKey_ECGDSA; + +/// \brief Elliptic Curve German DSA key for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_PrivateKey_ECGDSA : public DL_PrivateKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PrivateKey_ECGDSA() {} + + /// \brief Initialize an EC Private Key using {GP,x} + /// \param params group parameters + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Integer &x) + { + this->AccessGroupParameters() = params; + this->SetPrivateExponent(x); + CRYPTOPP_ASSERT(x>=1 && x<=params.GetSubgroupOrder()-1); + } + + /// \brief Initialize an EC Private Key using {EC,G,n,x} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + { + this->AccessGroupParameters().Initialize(ec, G, n); + this->SetPrivateExponent(x); + CRYPTOPP_ASSERT(x>=1 && x<=this->AccessGroupParameters().GetSubgroupOrder()-1); + } + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param params the EC group parameters + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC ¶ms) + {this->GenerateRandom(rng, params);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {this->GenerateRandom(rng, DL_GroupParameters_EC(ec, G, n));} + + virtual void MakePublicKey(DL_PublicKey_ECGDSA &pub) const + { + const DL_GroupParameters& params = this->GetAbstractGroupParameters(); + pub.AccessAbstractGroupParameters().AssignFrom(params); + const Integer &xInv = this->GetPrivateExponent().InverseMod(params.GetSubgroupOrder()); + pub.SetPublicElement(params.ExponentiateBase(xInv)); + CRYPTOPP_ASSERT(xInv.NotZero()); + } + + virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper, + DL_PrivateKey_ECGDSA >(this, name, valueType, pValue).Assignable(); + } + + virtual void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper, + DL_PrivateKey_ECGDSA >(this, source); + } + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve German DSA key for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_PublicKey_ECGDSA : public DL_PublicKeyImpl > +{ + typedef DL_PublicKey_ECGDSA ThisClass; + +public: + typedef typename EC::Point Element; + + virtual ~DL_PublicKey_ECGDSA() {} + + /// \brief Initialize an EC Public Key using {GP,Q} + /// \param params group parameters + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Element &Q) + {this->AccessGroupParameters() = params; this->SetPublicElement(Q);} + + /// \brief Initialize an EC Public Key using {EC,G,n,Q} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);} + + virtual void AssignFrom(const NameValuePairs &source) + { + DL_PrivateKey_ECGDSA *pPrivateKey = NULLPTR; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } + } + + // DL_PublicKey + virtual void SetPublicElement(const Element &y) + {this->AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve German DSA keys for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +struct DL_Keys_ECGDSA +{ + typedef DL_PublicKey_ECGDSA PublicKey; + typedef DL_PrivateKey_ECGDSA PrivateKey; +}; + +/// \brief Elliptic Curve German DSA signature algorithm +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_Algorithm_ECGDSA : public DL_Algorithm_GDSA_ISO15946 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECGDSA";} +}; + +/// \brief Elliptic Curve German Digital Signature Algorithm signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf The Digital Signature Scheme +/// ECGDSA (October 24, 2006) +/// \since Crypto++ 6.0 +template +struct ECGDSA : public DL_SS< + DL_Keys_ECGDSA, + DL_Algorithm_ECGDSA, + DL_SignatureMessageEncodingMethod_DSA, + H> +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECGDSA-ISO15946/") + H::StaticAlgorithmName();} +}; + +// ****************************************** + +/// \brief Elliptic Curve Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as u·V, v·U and label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \details ECIES is an Elliptic Curve based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation +/// Method (KEM) with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom +/// SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Ecryption +/// Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. SHA-256 or another hash will likely improve the +/// security provided by the MAC. The hash is also used in the key derivation function as a PRF. +/// \details Below is an example of constructing a Crypto++ 4.2 compatible ECIES encryptor and decryptor. +///
+///     AutoSeededRandomPool prng;
+///     DL_PrivateKey_EC key;
+///     key.Initialize(prng, ASN1::secp160r1());
+///
+///     ECIES::Decryptor decryptor(key);
+///     ECIES::Encryptor encryptor(decryptor);
+/// 
+/// \sa DLIES, Elliptic Curve Integrated Encryption Scheme (ECIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct ECIES + : public DL_ES< + DL_Keys_EC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + ECIES > +{ + // TODO: fix this after name is standardized + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES";} +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "eccrypto.cpp" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA >; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/ecp.h b/include/cryptlib/ecp.h new file mode 100644 index 0000000..946a08b --- /dev/null +++ b/include/cryptlib/ecp.h @@ -0,0 +1,155 @@ +// ecp.h - originally written and placed in the public domain by Wei Dai + +/// \file ecp.h +/// \brief Classes for Elliptic Curves over prime fields + +#ifndef CRYPTOPP_ECP_H +#define CRYPTOPP_ECP_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "ecpoint.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve over GF(p), where p is prime +class CRYPTOPP_DLL ECP : public AbstractGroup, public EncodedPoint +{ +public: + typedef ModularArithmetic Field; + typedef Integer FieldElement; + typedef ECPPoint Point; + + virtual ~ECP() {} + + /// \brief Construct an ECP + ECP() {} + + /// \brief Copy construct an ECP + /// \param ecp the other ECP object + /// \param convertToMontgomeryRepresentation flag indicating if the curve should be converted to a MontgomeryRepresentation + /// \sa ModularArithmetic, MontgomeryRepresentation + ECP(const ECP &ecp, bool convertToMontgomeryRepresentation = false); + + /// \brief Construct an ECP + /// \param modulus the prime modulus + /// \param a Field::Element + /// \param b Field::Element + ECP(const Integer &modulus, const FieldElement &a, const FieldElement &b) + : m_fieldPtr(new Field(modulus)), m_a(a.IsNegative() ? modulus+a : a), m_b(b) {} + + /// \brief Construct an ECP from BER encoded parameters + /// \param bt BufferedTransformation derived object + /// \details This constructor will decode and extract the the fields fieldID and curve of the sequence ECParameters + ECP(BufferedTransformation &bt); + + /// \brief Encode the fields fieldID and curve of the sequence ECParameters + /// \param bt BufferedTransformation derived object + void DEREncode(BufferedTransformation &bt) const; + + bool Equal(const Point &P, const Point &Q) const; + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + Point ScalarMultiply(const Point &P, const Integer &k) const; + Point CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const; + void SimultaneousMultiply(Point *results, const Point &base, const Integer *exponents, unsigned int exponentsCount) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*GetField().MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return GetField().GetModulus();} + const Field & GetField() const {return *m_fieldPtr;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + + bool operator==(const ECP &rhs) const + {return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;} + +private: + clonable_ptr m_fieldPtr; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation; + +/// \brief Elliptic Curve precomputation +/// \tparam EC elliptic curve field +template class EcPrecomputation; + +/// \brief ECP precomputation specialization +/// \details Implementation of DL_GroupPrecomputation with input and output +/// conversions for Montgomery modular multiplication. +/// \sa DL_GroupPrecomputation, ModularArithmetic, MontgomeryRepresentation +template<> class EcPrecomputation : public DL_GroupPrecomputation +{ +public: + typedef ECP EllipticCurve; + + virtual ~EcPrecomputation() {} + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertIn(P.x), m_ec->GetField().ConvertIn(P.y));}; + Element ConvertOut(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertOut(P.x), m_ec->GetField().ConvertOut(P.y));} + const AbstractGroup & GetGroup() const {return *m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec->BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec->DEREncodePoint(bt, v, false);} + + /// \brief Set the elliptic curve + /// \param ec ECP derived class + /// \details SetCurve() is not inherited + void SetCurve(const ECP &ec) + { + m_ec.reset(new ECP(ec, true)); + m_ecOriginal = ec; + } + + /// \brief Get the elliptic curve + /// \returns ECP curve + /// \details GetCurve() is not inherited + const ECP & GetCurve() const {return *m_ecOriginal;} + +private: + value_ptr m_ec, m_ecOriginal; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/ecpoint.h b/include/cryptlib/ecpoint.h new file mode 100644 index 0000000..d209d06 --- /dev/null +++ b/include/cryptlib/ecpoint.h @@ -0,0 +1,146 @@ +// ecpoint.h - written and placed in the public domain by Jeffrey Walton +// Data structures moved from ecp.h and ec2n.h. Added EncodedPoint interface + +/// \file ecpoint.h +/// \brief Classes for Elliptic Curve points +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_ECPOINT_H +#define CRYPTOPP_ECPOINT_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "gf2n.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptical Curve Point over GF(p), where p is prime +/// \since Crypto++ 2.0 +struct CRYPTOPP_DLL ECPPoint +{ + virtual ~ECPPoint() {} + + /// \brief Construct an ECPPoint + /// \details identity is set to true + ECPPoint() : identity(true) {} + + /// \brief Construct an ECPPoint from coordinates + /// \details identity is set to false + ECPPoint(const Integer &x, const Integer &y) + : x(x), y(y), identity(false) {} + + /// \brief Tests points for equality + /// \param t the other point + /// \returns true if the points are equal, false otherwise + bool operator==(const ECPPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + + /// \brief Tests points for ordering + /// \param t the other point + /// \returns true if this point is less than other, false otherwise + bool operator< (const ECPPoint &t) const + {return identity ? !t.identity : (!t.identity && (x; + +/// \brief Elliptical Curve Point over GF(2^n) +/// \since Crypto++ 2.0 +struct CRYPTOPP_DLL EC2NPoint +{ + virtual ~EC2NPoint() {} + + /// \brief Construct an EC2NPoint + /// \details identity is set to true + EC2NPoint() : identity(true) {} + + /// \brief Construct an EC2NPoint from coordinates + /// \details identity is set to false + EC2NPoint(const PolynomialMod2 &x, const PolynomialMod2 &y) + : x(x), y(y), identity(false) {} + + /// \brief Tests points for equality + /// \param t the other point + /// \returns true if the points are equal, false otherwise + bool operator==(const EC2NPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + + /// \brief Tests points for ordering + /// \param t the other point + /// \returns true if this point is less than other, false otherwise + bool operator< (const EC2NPoint &t) const + {return identity ? !t.identity : (!t.identity && (x; + +/// \brief Abstract class for encoding and decoding ellicptic curve points +/// \tparam Point ellicptic curve point +/// \details EncodedPoint is an interface for encoding and decoding elliptic curve points. +/// The template parameter Point should be a class like ECP or EC2N. +/// \since Crypto++ 6.0 +template +class EncodedPoint +{ +public: + virtual ~EncodedPoint() {} + + /// \brief Decodes an elliptic curve point + /// \param P point which is decoded + /// \param bt source BufferedTransformation + /// \param len number of bytes to read from the BufferedTransformation + /// \returns true if a point was decoded, false otherwise + virtual bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const =0; + + /// \brief Decodes an elliptic curve point + /// \param P point which is decoded + /// \param encodedPoint byte array with the encoded point + /// \param len the size of the array + /// \returns true if a point was decoded, false otherwise + virtual bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const =0; + + /// \brief Verifies points on elliptic curve + /// \param P point to verify + /// \returns true if the point is valid, false otherwise + virtual bool VerifyPoint(const Point &P) const =0; + + /// \brief Determines encoded point size + /// \param compressed flag indicating if the point is compressed + /// \returns the minimum number of bytes required to encode the point + virtual unsigned int EncodedPointSize(bool compressed = false) const =0; + + /// \brief Encodes an elliptic curve point + /// \param P point which is decoded + /// \param encodedPoint byte array for the encoded point + /// \param compressed flag indicating if the point is compressed + /// \details encodedPoint must be at least EncodedPointSize() in length + virtual void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const =0; + + /// \brief Encodes an elliptic curve point + /// \param bt target BufferedTransformation + /// \param P point which is encoded + /// \param compressed flag indicating if the point is compressed + virtual void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0; + + /// \brief BER Decodes an elliptic curve point + /// \param bt source BufferedTransformation + /// \returns the decoded elliptic curve point + virtual Point BERDecodePoint(BufferedTransformation &bt) const =0; + + /// \brief DER Encodes an elliptic curve point + /// \param bt target BufferedTransformation + /// \param P point which is encoded + /// \param compressed flag indicating if the point is compressed + virtual void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_ECPOINT_H diff --git a/include/cryptlib/elgamal.h b/include/cryptlib/elgamal.h new file mode 100644 index 0000000..379806e --- /dev/null +++ b/include/cryptlib/elgamal.h @@ -0,0 +1,149 @@ +// elgamal.h - originally written and placed in the public domain by Wei Dai + +/// \file elgamal.h +/// \brief Classes and functions for ElGamal key agreement and encryption schemes + +#ifndef CRYPTOPP_ELGAMAL_H +#define CRYPTOPP_ELGAMAL_H + +#include "cryptlib.h" +#include "modexppc.h" +#include "integer.h" +#include "gfpcrypt.h" +#include "pubkey.h" +#include "dsa.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ElGamal key agreement and encryption schemes base class +/// \since Crypto++ 1.0 +class CRYPTOPP_NO_VTABLE ElGamalBase : public DL_KeyAgreementAlgorithm_DH, + public DL_KeyDerivationAlgorithm, + public DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~ElGamalBase() {} + + void Derive(const DL_GroupParameters &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const + { + CRYPTOPP_UNUSED(groupParams), CRYPTOPP_UNUSED(ephemeralPublicKey), CRYPTOPP_UNUSED(derivationParams); + agreedElement.Encode(derivedKey, derivedLength); + } + + size_t GetSymmetricKeyLength(size_t plainTextLength) const + { + CRYPTOPP_UNUSED(plainTextLength); + return GetGroupParameters().GetModulus().ByteCount(); + } + + size_t GetSymmetricCiphertextLength(size_t plainTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + if (plainTextLength <= GetMaxSymmetricPlaintextLength(len)) + return len; + else + return 0; + } + + size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + if (cipherTextLength == len) + return STDMIN(255U, len-3); + else + return 0; + } + + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(parameters); + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + SecByteBlock block(modulusLen-1); + rng.GenerateBlock(block, modulusLen-2-plainTextLength); + memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength); + block[modulusLen-2] = (byte)plainTextLength; + + a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen); + } + + DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(parameters); + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + if (cipherTextLength != modulusLen) + return DecodingResult(); + + Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p); + + m.Encode(plainText, 1); + unsigned int plainTextLength = plainText[0]; + if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen)) + return DecodingResult(); + m >>= 8; + m.Encode(plainText, plainTextLength); + return DecodingResult(plainTextLength); + } + + virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0; +}; + +/// \brief ElGamal key agreement and encryption schemes default implementation +/// \since Crypto++ 1.0 +template +class ElGamalObjectImpl : public DL_ObjectImplBase, public ElGamalBase +{ +public: + virtual ~ElGamalObjectImpl() {} + + size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());} + size_t FixedCiphertextLength() const {return this->CiphertextLength(0);} + + const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();} + + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const + {return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);} + +protected: + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const {return *this;} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const {return *this;} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;} +}; + +/// \brief ElGamal key agreement and encryption schemes keys +/// \details The ElGamalKeys class used DL_PrivateKey_GFP_OldFormat and DL_PublicKey_GFP_OldFormat +/// for the PrivateKey and PublicKey typedef from about Crypto++ 1.0 through Crypto++ 5.6.5. +/// At Crypto++ 6.0 the serialization format was cutover to standard PKCS8 and X509 encodings. +/// \sa Commit a5a684d92986e8e2 +struct ElGamalKeys +{ + typedef DL_CryptoKeys_GFP::GroupParameters GroupParameters; + typedef DL_CryptoKeys_GFP::PrivateKey PrivateKey; + typedef DL_CryptoKeys_GFP::PublicKey PublicKey; +}; + +/// \brief ElGamal encryption scheme with non-standard padding +/// \since Crypto++ 1.0 +struct ElGamal +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";} + + typedef SchemeOptions::GroupParameters GroupParameters; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate, SchemeOptions, SchemeOptions::PublicKey> > Encryptor; + /// implements PK_Decryptor interface + typedef PK_FinalTemplate, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor; +}; + +typedef ElGamal::Encryptor ElGamalEncryptor; +typedef ElGamal::Decryptor ElGamalDecryptor; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/emsa2.h b/include/cryptlib/emsa2.h new file mode 100644 index 0000000..d39e73d --- /dev/null +++ b/include/cryptlib/emsa2.h @@ -0,0 +1,101 @@ +// emsa2.h - originally written and placed in the public domain by Wei Dai + +/// \file emsa2.h +/// \brief Classes and functions for various padding schemes used in public key algorithms + +#ifndef CRYPTOPP_EMSA2_H +#define CRYPTOPP_EMSA2_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "hashfwd.h" +#include "misc.h" + +#ifdef CRYPTOPP_IS_DLL +# include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief EMSA2 hash identifier +/// \tparam H HashTransformation derived class +/// \since Crypto++ 5.0 +template class EMSA2HashId +{ +public: + static const byte id; +}; + +/// \brief EMSA2 padding method +/// \tparam BASE Message encoding method +/// \since Crypto++ 5.0 +template +class EMSA2HashIdLookup : public BASE +{ +public: + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(&EMSA2HashId::id, 1); + } + }; + }; +}; + +// EMSA2HashId can be instantiated with the following classes. +// SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, Whirlpool + +#ifdef CRYPTOPP_IS_DLL +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +#endif + +// https://github.com/weidai11/cryptopp/issues/300 and +// https://github.com/weidai11/cryptopp/issues/533 +#if defined(__clang__) +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +#endif + +/// \brief EMSA2 padding method +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL EMSA2Pad : public EMSA2HashIdLookup +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA2";} + + size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(hashIdentifierLength); return 8*digestLength + 31;} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +// EMSA2, for use with RWSS and RSA_ISO +// Only the following hash functions are supported by this signature standard: +// \dontinclude emsa2.h +// \skip EMSA2HashId can be instantiated +// \until end of list + +/// \brief EMSA2/P1363 padding method +/// \details Use with RWSS and RSA_ISO +/// \since Crypto++ 5.0 +struct P1363_EMSA2 : public SignatureStandard +{ + typedef EMSA2Pad SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/eprecomp.h b/include/cryptlib/eprecomp.h new file mode 100644 index 0000000..b5d8b36 --- /dev/null +++ b/include/cryptlib/eprecomp.h @@ -0,0 +1,162 @@ +// eprecomp.h - originally written and placed in the public domain by Wei Dai + +/// \file eprecomp.h +/// \brief Classes for precomputation in a group + +#ifndef CRYPTOPP_EPRECOMP_H +#define CRYPTOPP_EPRECOMP_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DL_GroupPrecomputation interface +/// \tparam T Field element +template +class DL_GroupPrecomputation +{ +public: + typedef T Element; + + virtual ~DL_GroupPrecomputation() {} + + /// \brief Determines if elements needs conversion + /// \returns true if the element needs conversion, false otherwise + /// \details NeedConversions determines if an element must convert between representations. + virtual bool NeedConversions() const {return false;} + + /// \brief Converts an element between representations + /// \param v element to convert + /// \returns an element converted to an alternate representation for internal use + /// \details ConvertIn is used when an element must convert between representations. + virtual Element ConvertIn(const Element &v) const {return v;} + + /// \brief Converts an element between representations + /// \param v element to convert + /// \returns an element converted from an alternate representation + virtual Element ConvertOut(const Element &v) const {return v;} + + /// \brief Retrieves AbstractGroup interface + /// \returns GetGroup() returns the AbstractGroup interface + virtual const AbstractGroup & GetGroup() const =0; + + /// \brief Decodes element in DER format + /// \param bt BufferedTransformation object + /// \returns element in the group + virtual Element BERDecodeElement(BufferedTransformation &bt) const =0; + + /// \brief Encodes element in DER format + /// \param bt BufferedTransformation object + /// \param P Element to encode + virtual void DEREncodeElement(BufferedTransformation &bt, const Element &P) const =0; +}; + +/// \brief DL_FixedBasePrecomputation interface +/// \tparam T Field element +template +class DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual ~DL_FixedBasePrecomputation() {} + + /// \brief Determines whether this object is initialized + /// \returns true if this object is initialized, false otherwise + virtual bool IsInitialized() const =0; + + /// \brief Set the base element + /// \param group the group + /// \param base element in the group + virtual void SetBase(const DL_GroupPrecomputation &group, const Element &base) =0; + + /// \brief Get the base element + /// \param group the group + /// \returns base element in the group + virtual const Element & GetBase(const DL_GroupPrecomputation &group) const =0; + + /// \brief Perform precomputation + /// \param group the group + /// \param maxExpBits used to calculate the exponent base + /// \param storage the suggested number of objects for the precompute table + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + virtual void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) =0; + + /// \brief Retrieve previously saved precomputation + /// \param group the the group + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throws NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) =0; + + /// \brief Save precomputation for later use + /// \param group the the group + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throws NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const =0; + + /// \brief Exponentiates an element + /// \param group the group + /// \param exponent the exponent + /// \return the result of the exponentiation + virtual Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const =0; + + /// \brief Exponentiates an element + /// \param pc1 the first the group precomputation + /// \param exponent1 the first exponent + /// \param pc2 the second the group precomputation + /// \param exponent2 the first exponent2 + /// \returns the public element raised to the exponent + /// \details CascadeExponentiateBaseAndPublicElement raises the public element to + /// the base element and precomputation. + virtual Element CascadeExponentiate(const DL_GroupPrecomputation &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const =0; +}; + +/// \brief DL_FixedBasePrecomputation adapter class +/// \tparam T Field element +template +class DL_FixedBasePrecomputationImpl : public DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual ~DL_FixedBasePrecomputationImpl() {} + + DL_FixedBasePrecomputationImpl() : m_windowSize(0) {} + + // DL_FixedBasePrecomputation + bool IsInitialized() const + {return !m_bases.empty();} + void SetBase(const DL_GroupPrecomputation &group, const Element &base); + const Element & GetBase(const DL_GroupPrecomputation &group) const + {return group.NeedConversions() ? m_base : m_bases[0];} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage); + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation); + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const; + Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Element CascadeExponentiate(const DL_GroupPrecomputation &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const; + +private: + void PrepareCascade(const DL_GroupPrecomputation &group, std::vector > &eb, const Integer &exponent) const; + + Element m_base; + unsigned int m_windowSize; + Integer m_exponentBase; // what base to represent the exponent in + std::vector m_bases; // precalculated bases +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "eprecomp.cpp" +#endif + +#endif diff --git a/include/cryptlib/esign.h b/include/cryptlib/esign.h new file mode 100644 index 0000000..2c597c2 --- /dev/null +++ b/include/cryptlib/esign.h @@ -0,0 +1,169 @@ +// esign.h - originally written and placed in the public domain by Wei Dai + +/// \file esign.h +/// \brief Classes providing ESIGN signature schemes as defined in IEEE P1363a +/// \since Crypto++ 5.0 + +#ifndef CRYPTOPP_ESIGN_H +#define CRYPTOPP_ESIGN_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ESIGN trapdoor function using the public key +/// \since Crypto++ 5.0 +class ESIGNFunction : public TrapdoorFunction, public ASN1CryptoMaterial +{ + typedef ESIGNFunction ThisClass; + +public: + + /// \brief Initialize a ESIGN public key with {n,e} + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // PublicKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return Integer::Power2(GetK());} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + // Covertiy finding on overflow. The library allows small values for research purposes. + unsigned int GetK() const {return SaturatingSubtract(m_n.BitCount()/3, 1U);} + + Integer m_n, m_e; +}; + +/// \brief ESIGN trapdoor function using the private key +/// \since Crypto++ 5.0 +class InvertibleESIGNFunction : public ESIGNFunction, public RandomizedTrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleESIGNFunction ThisClass; + +public: + + /// \brief Initialize a ESIGN private key with {n,e,p,q} + /// \param n modulus + /// \param e public exponent + /// \param p first prime factor + /// \param q second prime factor + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q) + {m_n = n; m_e = e; m_p = p; m_q = q;} + + /// \brief Create a ESIGN private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulud, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + // Squash Visual Studio C4250 warning + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + + // Squash Visual Studio C4250 warning + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + +protected: + Integer m_p, m_q; +}; + +/// \brief EMSA5 padding method +/// \tparam T Mask Generation Function +/// \since Crypto++ 5.0 +template +class EMSA5Pad : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EMSA5";} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const + { + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + SecByteBlock digest(hash.DigestSize()); + hash.Final(digest); + size_t representativeByteLength = BitsToBytes(representativeBitLength); + T mgf; + mgf.GenerateAndMask(hash, representative, representativeByteLength, digest, digest.size(), false); + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); + } +}; + +/// \brief EMSA5 padding method, for use with ESIGN +/// \since Crypto++ 5.0 +struct P1363_EMSA5 : public SignatureStandard +{ + typedef EMSA5Pad SignatureMessageEncodingMethod; +}; + +/// \brief ESIGN keys +/// \since Crypto++ 5.0 +struct ESIGN_Keys +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ESIGN";} + typedef ESIGNFunction PublicKey; + typedef InvertibleESIGNFunction PrivateKey; +}; + +/// \brief ESIGN signature scheme, IEEE P1363a +/// \tparam H HashTransformation derived class +/// \tparam STANDARD Signature encoding method +/// \since Crypto++ 5.0 +template +struct ESIGN : public TF_SS +{ +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/factory.h b/include/cryptlib/factory.h new file mode 100644 index 0000000..82dc5f5 --- /dev/null +++ b/include/cryptlib/factory.h @@ -0,0 +1,179 @@ +// factory.h - originally written and placed in the public domain by Wei Dai + +/// \file factory.h +/// \brief Classes and functions for registering and locating library objects + +#ifndef CRYPTOPP_OBJFACT_H +#define CRYPTOPP_OBJFACT_H + +#include "cryptlib.h" +#include "misc.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Object factory interface for registering objects +/// \tparam AbstractClass Base class interface of the object +template +class ObjectFactory +{ +public: + virtual ~ObjectFactory () {} + virtual AbstractClass * CreateObject() const =0; +}; + +/// \brief Object factory for registering objects +/// \tparam AbstractClass Base class interface of the object +/// \tparam ConcreteClass Class object +template +class DefaultObjectFactory : public ObjectFactory +{ +public: + AbstractClass * CreateObject() const + { + return new ConcreteClass; + } +}; + +/// \brief Object factory registry +/// \tparam AbstractClass Base class interface of the object +/// \tparam instance unique identifier +template +class ObjectFactoryRegistry +{ +public: + class FactoryNotFound : public Exception + { + public: + FactoryNotFound(const char *name) : Exception(OTHER_ERROR, std::string("ObjectFactoryRegistry: could not find factory for algorithm ") + name) {} + }; + + ~ObjectFactoryRegistry() + { + for (typename Map::iterator i = m_map.begin(); i != m_map.end(); ++i) + { + delete (ObjectFactory *)i->second; + i->second = NULLPTR; + } + } + + void RegisterFactory(const std::string &name, ObjectFactory *factory) + { + m_map[name] = factory; + } + + const ObjectFactory * GetFactory(const char *name) const + { + typename Map::const_iterator i = m_map.find(name); + return i == m_map.end() ? NULLPTR : (ObjectFactory *)i->second; + } + + AbstractClass *CreateObject(const char *name) const + { + const ObjectFactory *factory = GetFactory(name); + if (!factory) + throw FactoryNotFound(name); + return factory->CreateObject(); + } + + // Return a vector containing the factory names. This is easier than returning an iterator. + // from Andrew Pitonyak + std::vector GetFactoryNames() const + { + std::vector names; + typename Map::const_iterator iter; + for (iter = m_map.begin(); iter != m_map.end(); ++iter) + names.push_back(iter->first); + return names; + } + + CRYPTOPP_NOINLINE static ObjectFactoryRegistry & Registry(CRYPTOPP_NOINLINE_DOTDOTDOT); + +private: + // use void * instead of ObjectFactory * to save code size + typedef std::map Map; + Map m_map; +}; + +template +ObjectFactoryRegistry & ObjectFactoryRegistry::Registry(CRYPTOPP_NOINLINE_DOTDOTDOT) +{ + static ObjectFactoryRegistry s_registry; + return s_registry; +} + +/// \brief Object factory registry helper +/// \tparam AbstractClass Base class interface of the object +/// \tparam ConcreteClass Class object +/// \tparam instance unique identifier +template +struct RegisterDefaultFactoryFor +{ + RegisterDefaultFactoryFor(const char *name=NULLPTR) + { + // BCB2006 workaround + std::string n = name ? std::string(name) : std::string(ConcreteClass::StaticAlgorithmName()); + ObjectFactoryRegistry::Registry(). + RegisterFactory(n, new DefaultObjectFactory); + } +}; + +/// \fn RegisterAsymmetricCipherDefaultFactories +/// \brief Register asymmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterAsymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterSignatureSchemeDefaultFactories +/// \brief Register signature schemes +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterSignatureSchemeDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterSymmetricCipherDefaultFactories +/// \brief Register symmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterSymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterAuthenticatedSymmetricCipherDefaultFactories +/// \brief Register authenticated symmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterAuthenticatedSymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/fhmqv.h b/include/cryptlib/fhmqv.h new file mode 100644 index 0000000..ce6025a --- /dev/null +++ b/include/cryptlib/fhmqv.h @@ -0,0 +1,302 @@ +// fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal +// Shamelessly based upon Wei Dai's MQV source files + +#ifndef CRYPTOPP_FHMQV_H +#define CRYPTOPP_FHMQV_H + +/// \file fhmqv.h +/// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p) +/// \since Crypto++ 5.6.4 + +#include "gfpcrypt.h" +#include "algebra.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +template +class FHMQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef FHMQV_Domain Domain; + + virtual ~FHMQV_Domain() {} + + FHMQV_Domain(bool clientRole = true): m_role(clientRole ? RoleClient : RoleServer) {} + + FHMQV_Domain(const GroupParameters ¶ms, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {} + + FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.BERDecode(bt);} + + template + FHMQV_Domain(T1 v1, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1);} + + template + FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2);} + + template + FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3);} + + template + FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + +public: + + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + GroupParameters & AccessGroupParameters(){return m_groupParameters;} + + CryptoParameters & AccessCryptoParameters(){return AccessAbstractGroupParameters();} + + /// return length of agreed value produced + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + /// return length of static private keys in this domain + unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + /// return length of static public keys in this domain + unsigned int StaticPublicKeyLength() const{return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// generate static private key + /*! \pre size of privateKey == PrivateStaticKeyLength() */ + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// generate static public key + /*! \pre size of publicKey == PublicStaticKeyLength() */ + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();} + + /// return length of ephemeral private keys in this domain + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// return length of ephemeral public keys in this domain + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// derive agreed value from your private keys and couterparty's public keys, return false in case of failure + /*! \note The ephemeral public key will always be validated. + If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time. + \pre size of agreedValue == AgreedValueLength() + \pre length of staticPrivateKey == StaticPrivateKeyLength() + \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength() + \pre length of staticOtherPublicKey == StaticPublicKeyLength() + \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength() + */ + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR; + size_t xxs = 0, yys = 0, aas = 0, bbs = 0; + + // Depending on the role, this will hold either A's or B's static + // (long term) public key. AA or BB will then point into tt. + SecByteBlock tt(StaticPublicKeyLength()); + + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + if(m_role == RoleServer) + { + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Element B = params.ExponentiateBase(b); + params.EncodeElement(true, B, tt); + + XX = const_cast(ephemeralOtherPublicKey); + xxs = EphemeralPublicKeyLength(); + YY = const_cast(ephemeralPrivateKey) + StaticPrivateKeyLength(); + yys = EphemeralPublicKeyLength(); + AA = const_cast(staticOtherPublicKey); + aas = StaticPublicKeyLength(); + BB = tt.BytePtr(); + bbs = tt.SizeInBytes(); + } + else if(m_role == RoleClient) + { + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Element A = params.ExponentiateBase(a); + params.EncodeElement(true, A, tt); + + XX = const_cast(ephemeralPrivateKey) + StaticPrivateKeyLength(); + xxs = EphemeralPublicKeyLength(); + YY = const_cast(ephemeralOtherPublicKey); + yys = EphemeralPublicKeyLength(); + AA = tt.BytePtr(); + aas = tt.SizeInBytes(); + BB = const_cast(staticOtherPublicKey); + bbs = StaticPublicKeyLength(); + } + else + { + CRYPTOPP_ASSERT(0); + return false; + } + + // DecodeElement calls ValidateElement at level 1. Level 1 only calls + // VerifyPoint to ensure the element is in G*. If the other's PublicKey is + // requested to be validated, we manually call ValidateElement at level 3. + Element VV1 = params.DecodeElement(staticOtherPublicKey, false); + if(!params.ValidateElement(validateStaticOtherPublicKey ? 3 : 1, VV1, NULLPTR)) + return false; + + // DecodeElement calls ValidateElement at level 1. Level 1 only calls + // VerifyPoint to ensure the element is in G*. Crank it up. + Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, false); + if(!params.ValidateElement(3, VV2, NULLPTR)) + return false; + + const Integer& q = params.GetSubgroupOrder(); + const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8); + + Integer d, e; + SecByteBlock dd(len), ee(len); + + Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes()); + d.Decode(dd.BytePtr(), dd.SizeInBytes()); + + Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes()); + e.Decode(ee.BytePtr(), ee.SizeInBytes()); + + Element sigma; + if(m_role == RoleServer) + { + Integer y(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_B = (y + e * b) % q; + + Element A = params.DecodeElement(AA, false); + Element X = params.DecodeElement(XX, false); + + Element t1 = params.ExponentiateElement(A, d); + Element t2 = m_groupParameters.MultiplyElements(X, t1); + + sigma = params.ExponentiateElement(t2, s_B); + } + else + { + Integer x(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_A = (x + d * a) % q; + + Element B = params.DecodeElement(BB, false); + Element Y = params.DecodeElement(YY, false); + + Element t1 = params.ExponentiateElement(B, e); + Element t2 = m_groupParameters.MultiplyElements(Y, t1); + + sigma = params.ExponentiateElement(t2, s_A); + } + + Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength()); + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + +protected: + + inline void Hash(const Element* sigma, + const byte* e1, size_t e1len, const byte* e2, size_t e2len, + const byte* s1, size_t s1len, const byte* s2, size_t s2len, + byte* digest, size_t dlen) const + { + HASH hash; + size_t idx = 0, req = dlen; + size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE); + + if(sigma) + { + Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma); + SecByteBlock sbb(x.MinEncodedSize()); + x.Encode(sbb.BytePtr(), sbb.SizeInBytes()); + hash.Update(sbb.BytePtr(), sbb.SizeInBytes()); + } + + hash.Update(e1, e1len); + hash.Update(e2, e2len); + hash.Update(s1, s1len); + hash.Update(s2, s2len); + + hash.TruncatedFinal(digest, blk); + req -= blk; + + // All this to catch tail bytes for large curves and small hashes + while(req != 0) + { + hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE); + + idx += (size_t)HASH::DIGESTSIZE; + blk = STDMIN(req, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(&digest[idx], blk); + + req -= blk; + } + } + +private: + + // The paper uses Initiator and Recipient - make it classical. + enum KeyAgreementRole{ RoleServer = 1, RoleClient }; + + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const{return m_groupParameters;} + + GroupParameters m_groupParameters; + KeyAgreementRole m_role; +}; + +/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa FHMQV, MQV_Domain, HMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +typedef FHMQV_Domain FHMQV; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/files.h b/include/cryptlib/files.h new file mode 100644 index 0000000..cda6826 --- /dev/null +++ b/include/cryptlib/files.h @@ -0,0 +1,177 @@ +// files.h - originally written and placed in the public domain by Wei Dai + +/// \file files.h +/// \brief Classes providing file-based library services +/// \since Crypto++ 1.0 + +#ifndef CRYPTOPP_FILES_H +#define CRYPTOPP_FILES_H + +#include "cryptlib.h" +#include "filters.h" +#include "argnames.h" +#include "smartptr.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Implementation of Store interface +/// \details file-based implementation of Store interface +class CRYPTOPP_DLL FileStore : public Store, private FilterPutSpaceHelper, public NotCopyable +{ +public: + /// \brief Exception thrown when file-based error is encountered + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + /// \brief Exception thrown when file-based open error is encountered + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileStore: error opening file for reading: " + filename) {}}; + /// \brief Exception thrown when file-based read error is encountered + class ReadErr : public Err {public: ReadErr() : Err("FileStore: error reading file") {}}; + + /// \brief Construct a FileStore + FileStore() : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) {} + + /// \brief Construct a FileStore + /// \param in an existing stream + FileStore(std::istream &in) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) + {StoreInitialize(MakeParameters(Name::InputStreamPointer(), &in));} + + /// \brief Construct a FileStore + /// \param filename the narrow name of the file to open + FileStore(const char *filename) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) + {StoreInitialize(MakeParameters(Name::InputFileName(), filename ? filename : ""));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || _MSC_VER >= 1400 + /// \brief Construct a FileStore + /// \param filename the Unicode name of the file to open + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileStore(const wchar_t *filename) + {StoreInitialize(MakeParameters(Name::InputFileNameWide(), filename));} +#endif + + /// \brief Retrieves the internal stream + /// \returns the internal stream pointer + std::istream* GetStream() {return m_stream;} + + /// \brief Retrieves the internal stream + /// \returns the internal stream pointer + const std::istream* GetStream() const {return m_stream;} + + lword MaxRetrievable() const; + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + lword Skip(lword skipMax=ULONG_MAX); + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + member_ptr m_file; + std::istream *m_stream; + byte *m_space; + size_t m_len; + bool m_waiting; +}; + +/// \brief Implementation of Store interface +/// \details file-based implementation of Store interface +class CRYPTOPP_DLL FileSource : public SourceTemplate +{ +public: + typedef FileStore::Err Err; + typedef FileStore::OpenErr OpenErr; + typedef FileStore::ReadErr ReadErr; + + /// \brief Construct a FileSource + FileSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a FileSource + /// \param in an existing stream + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputStreamPointer(), &in));} + + /// \brief Construct a FileSource + /// \param filename the narrow name of the file to open + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + /// \param binary flag indicating if the file is binary + FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileName(), filename)(Name::InputBinaryMode(), binary));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || _MSC_VER >= 1400 + /// \brief Construct a FileSource + /// \param filename the Unicode name of the file to open + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + /// \param binary flag indicating if the file is binary + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileSource(const wchar_t *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileNameWide(), filename)(Name::InputBinaryMode(), binary));} +#endif + + /// \brief Retrieves the internal stream + /// \returns the internal stream pointer + std::istream* GetStream() {return m_store.GetStream();} +}; + +/// \brief Implementation of Store interface +/// \details file-based implementation of Sink interface +class CRYPTOPP_DLL FileSink : public Sink, public NotCopyable +{ +public: + /// \brief Exception thrown when file-based error is encountered + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + /// \brief Exception thrown when file-based open error is encountered + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileSink: error opening file for writing: " + filename) {}}; + /// \brief Exception thrown when file-based write error is encountered + class WriteErr : public Err {public: WriteErr() : Err("FileSink: error writing file") {}}; + + /// \brief Construct a FileSink + FileSink() : m_stream(NULLPTR) {} + + /// \brief Construct a FileSink + /// \param out an existing stream + FileSink(std::ostream &out) + {IsolatedInitialize(MakeParameters(Name::OutputStreamPointer(), &out));} + + /// \brief Construct a FileSink + /// \param filename the narrow name of the file to open + /// \param binary flag indicating if the file is binary + FileSink(const char *filename, bool binary=true) + {IsolatedInitialize(MakeParameters(Name::OutputFileName(), filename)(Name::OutputBinaryMode(), binary));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 + /// \brief Construct a FileSink + /// \param filename the Unicode name of the file to open + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileSink(const wchar_t *filename, bool binary=true) + {IsolatedInitialize(MakeParameters(Name::OutputFileNameWide(), filename)(Name::OutputBinaryMode(), binary));} +#endif + + /// \brief Retrieves the internal stream + /// \returns the internal stream pointer + std::ostream* GetStream() {return m_stream;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +private: + member_ptr m_file; + std::ostream *m_stream; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/filters.h b/include/cryptlib/filters.h new file mode 100644 index 0000000..3e5be2c --- /dev/null +++ b/include/cryptlib/filters.h @@ -0,0 +1,1433 @@ +// filters.h - originally written and placed in the public domain by Wei Dai + +/// \file filters.h +/// \brief Implementation of BufferedTransformation's attachment interface. + +#ifndef CRYPTOPP_FILTERS_H +#define CRYPTOPP_FILTERS_H + +#include "cryptlib.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4231 4275 4514) +#endif + +#include "cryptlib.h" +#include "simple.h" +#include "secblock.h" +#include "misc.h" +#include "smartptr.h" +#include "queue.h" +#include "algparam.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Filter is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Filter : public BufferedTransformation, public NotCopyable +{ +public: + virtual ~Filter() {} + + /// \name ATTACHMENT + //@{ + + /// \brief Construct a Filter + /// \param attachment an optional attached transformation + /// \details attachment can be \p NULL. + Filter(BufferedTransformation *attachment = NULLPTR); + + /// \brief Determine if attachable + /// \returns \p true if the object allows attached transformations, \p false otherwise. + /// \note Source and Filter offer attached transformations; while Sink does not. + bool Attachable() {return true;} + + /// \brief Retrieve attached transformation + /// \returns pointer to a BufferedTransformation if there is an attached transformation, \p NULL otherwise. + BufferedTransformation *AttachedTransformation(); + + /// \brief Retrieve attached transformation + /// \returns pointer to a BufferedTransformation if there is an attached transformation, \p NULL otherwise. + const BufferedTransformation *AttachedTransformation() const; + + /// \brief Replace an attached transformation + /// \param newAttachment an optional attached transformation + /// \details newAttachment can be a single filter, a chain of filters or \p NULL. + /// Pass \p NULL to remove an existing BufferedTransformation or chain of filters + void Detach(BufferedTransformation *newAttachment = NULLPTR); + + //@} + + // See the documentation for BufferedTransformation in cryptlib.h + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + // See the documentation for BufferedTransformation in cryptlib.h + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + +protected: + virtual BufferedTransformation * NewDefaultAttachment() const; + void Insert(Filter *nextFilter); // insert filter after this one + + virtual bool ShouldPropagateMessageEnd() const {return true;} + virtual bool ShouldPropagateMessageSeriesEnd() const {return true;} + + void PropagateInitialize(const NameValuePairs ¶meters, int propagation); + + /// \brief Forward processed data on to attached transformation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \returns the number of bytes that remain in the block (i.e., bytes not processed) + size_t Output(int outputSite, const byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Output multiple bytes that may be modified by callee. + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \returns the number of bytes that remain in the block (i.e., bytes not processed) + size_t OutputModifiable(int outputSite, byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Signals the end of messages to the object + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \returns TODO + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool OutputMessageEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \returns TODO + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + bool OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \returns TODO + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + +private: + member_ptr m_attachment; + +protected: + size_t m_inputPosition; + int m_continueAt; +}; + +/// \brief Create a working space in a BufferedTransformation +struct CRYPTOPP_DLL FilterPutSpaceHelper +{ + virtual ~FilterPutSpaceHelper() {} + + /// \brief Create a working space in a BufferedTransformation + /// \param target BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \param desiredSize preferred size of the allocation, in bytes + /// \param bufferSize actual size of the allocation, in bytes + /// \pre desiredSize >= minSize and bufferSize >= minSize. + /// \details \p bufferSize is an IN and OUT parameter. If HelpCreatePutSpace() returns a non-NULL value, then + /// bufferSize is valid and provides the size of the working space created for the caller. + /// \details Internally, HelpCreatePutSpace() calls \ref BufferedTransformation::ChannelCreatePutSpace + /// "ChannelCreatePutSpace()" using \p desiredSize. If the target returns \p desiredSize with a size less + /// than \p minSize (i.e., the request could not be fulfilled), then an internal SecByteBlock + /// called \p m_tempSpace is resized and used for the caller. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) + { + CRYPTOPP_ASSERT(desiredSize >= minSize && bufferSize >= minSize); + if (m_tempSpace.size() < minSize) + { + byte *result = target.ChannelCreatePutSpace(channel, desiredSize); + if (desiredSize >= minSize) + { + bufferSize = desiredSize; + return result; + } + m_tempSpace.New(bufferSize); + } + + bufferSize = m_tempSpace.size(); + return m_tempSpace.begin(); + } + + /// \brief Create a working space in a BufferedTransformation + /// \param target the BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \details Internally, the overload calls HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) using \p minSize for missing arguments. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, minSize);} + + /// \brief Create a working space in a BufferedTransformation + /// \param target the BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \param bufferSize the actual size of the allocation, in bytes + /// \details Internally, the overload calls HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) using \p minSize for missing arguments. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t bufferSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, bufferSize);} + + /// \brief Temporay working space + SecByteBlock m_tempSpace; +}; + +/// \brief Measure how many bytes and messages pass through the filter +/// \details measure how many bytes and messages pass through the filter. The filter also serves as valve by +/// maintaining a list of ranges to skip during processing. +class CRYPTOPP_DLL MeterFilter : public Bufferless +{ +public: + virtual ~MeterFilter() {} + + /// \brief Construct a MeterFilter + /// \param attachment an optional attached transformation + /// \param transparent flag indicating if the filter should function transparently + /// \details \p attachment can be \p NULL. The filter is transparent by default. If the filter is + /// transparent, then PutMaybeModifiable() does not process a request and always returns 0. + MeterFilter(BufferedTransformation *attachment=NULLPTR, bool transparent=true) + : m_transparent(transparent), m_currentMessageBytes(0), m_totalBytes(0) + , m_currentSeriesMessages(0), m_totalMessages(0), m_totalMessageSeries(0) + , m_begin(NULLPTR), m_length(0) {Detach(attachment); ResetMeter();} + + /// \brief Set or change the transparent mode of this object + /// \param transparent the new transparent mode + void SetTransparent(bool transparent) {m_transparent = transparent;} + + /// \brief Adds a range to skip during processing + /// \param message the message to apply the range + /// \param position the 0-based index in the current stream + /// \param size the length of the range + /// \param sortNow flag indicating whether the range should be sorted + /// \details Internally, MeterFilter maitains a deque of ranges to skip. As messages are processed, + /// ranges of bytes are skipped according to the list of ranges. + void AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow = true); + + /// \brief Resets the meter + /// \details ResetMeter() reinitializes the meter by setting counters to 0 and removing previous + /// skip ranges. + void ResetMeter(); + + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); ResetMeter();} + + lword GetCurrentMessageBytes() const {return m_currentMessageBytes;} + lword GetTotalBytes() const {return m_totalBytes;} + unsigned int GetCurrentSeriesMessages() const {return m_currentSeriesMessages;} + unsigned int GetTotalMessages() const {return m_totalMessages;} + unsigned int GetTotalMessageSeries() const {return m_totalMessageSeries;} + + byte * CreatePutSpace(size_t &size) + {return AttachedTransformation()->CreatePutSpace(size);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedMessageSeriesEnd(bool blocking); + +private: + size_t PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable); + bool ShouldPropagateMessageEnd() const {return m_transparent;} + bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;} + + struct MessageRange + { + inline bool operator<(const MessageRange &b) const // BCB2006 workaround: this has to be a member function + {return message < b.message || (message == b.message && position < b.position);} + unsigned int message; lword position; lword size; + }; + + bool m_transparent; + lword m_currentMessageBytes, m_totalBytes; + unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries; + std::deque m_rangesToSkip; + byte *m_begin; + size_t m_length; +}; + +/// \brief A transparent MeterFilter +/// \sa MeterFilter, OpaqueFilter +class CRYPTOPP_DLL TransparentFilter : public MeterFilter +{ +public: + /// \brief Construct a TransparentFilter + /// \param attachment an optional attached transformation + TransparentFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, true) {} +}; + +/// \brief A non-transparent MeterFilter +/// \sa MeterFilter, TransparentFilter +class CRYPTOPP_DLL OpaqueFilter : public MeterFilter +{ +public: + /// \brief Construct an OpaqueFilter + /// \param attachment an optional attached transformation + OpaqueFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, false) {} +}; + +/// \brief Divides an input stream into discrete blocks +/// \details FilterWithBufferedInput divides the input stream into a first block, a number of +/// middle blocks, and a last block. First and last blocks are optional, and middle blocks may +/// be a stream instead (i.e. blockSize == 1). +/// \sa AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashVerificationFilter, +/// SignatureVerificationFilter, StreamTransformationFilter +class CRYPTOPP_DLL FilterWithBufferedInput : public Filter +{ +public: + virtual ~FilterWithBufferedInput() {} + + /// \brief Construct a FilterWithBufferedInput with an attached transformation + /// \param attachment an attached transformation + FilterWithBufferedInput(BufferedTransformation *attachment); + + /// \brief Construct a FilterWithBufferedInput with an attached transformation + /// \param firstSize the size of the first block + /// \param blockSize the size of middle blocks + /// \param lastSize the size of the last block + /// \param attachment an attached transformation + /// \details \p firstSize and \p lastSize may be 0. \p blockSize must be at least 1. + FilterWithBufferedInput(size_t firstSize, size_t blockSize, size_t lastSize, BufferedTransformation *attachment); + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(const_cast(inString), length, messageEnd, blocking, false); + } + + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(inString, length, messageEnd, blocking, true); + } + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \details IsolatedFlush() calls ForceNextPut() if hardFlush is true + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// \brief Flushes data buffered by this object + /// \details The input buffer may contain more than blockSize bytes if lastSize != 0. + /// ForceNextPut() forces a call to NextPut() if this is the case. + void ForceNextPut(); + +protected: + virtual bool DidFirstPut() const {return m_firstInputDone;} + virtual size_t GetFirstPutSize() const {return m_firstSize;} + virtual size_t GetBlockPutSize() const {return m_blockSize;} + virtual size_t GetLastPutSize() const {return m_lastSize;} + + virtual void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_UNUSED(firstSize); CRYPTOPP_UNUSED(blockSize); CRYPTOPP_UNUSED(lastSize); InitializeDerived(parameters);} + virtual void InitializeDerived(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters);} + // FirstPut() is called if (firstSize != 0 and totalLength >= firstSize) + // or (firstSize == 0 and (totalLength > 0 or a MessageEnd() is received)). + // inString is m_firstSize in length. + virtual void FirstPut(const byte *inString) =0; + // NextPut() is called if totalLength >= firstSize+blockSize+lastSize + virtual void NextPutSingle(const byte *inString) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_ASSERT(false);} + // Same as NextPut() except length can be a multiple of blockSize + // Either NextPut() or NextPutMultiple() must be overridden + virtual void NextPutMultiple(const byte *inString, size_t length); + // Same as NextPutMultiple(), but inString can be modified + virtual void NextPutModifiable(byte *inString, size_t length) + {NextPutMultiple(inString, length);} + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ virtual void LastPut(const byte *inString, size_t length) =0; + virtual void FlushDerived() {} + +protected: + size_t PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable); + void NextPutMaybeModifiable(byte *inString, size_t length, bool modifiable) + { + if (modifiable) NextPutModifiable(inString, length); + else NextPutMultiple(inString, length); + } + + // This function should no longer be used, put this here to cause a compiler error + // if someone tries to override NextPut(). + virtual int NextPut(const byte *inString, size_t length) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(false); return 0;} + + class BlockQueue + { + public: + void ResetQueue(size_t blockSize, size_t maxBlocks); + byte *GetBlock(); + byte *GetContigousBlocks(size_t &numberOfBytes); + size_t GetAll(byte *outString); + void Put(const byte *inString, size_t length); + size_t CurrentSize() const {return m_size;} + size_t MaxSize() const {return m_buffer.size();} + + private: + SecByteBlock m_buffer; + size_t m_blockSize, m_maxBlocks, m_size; + byte *m_begin; + }; + + size_t m_firstSize, m_blockSize, m_lastSize; + bool m_firstInputDone; + BlockQueue m_queue; +}; + +/// \brief A filter that buffers input using a ByteQueue +/// \details FilterWithInputQueue will buffer input using a ByteQueue. When the filter receives +/// a \ref BufferedTransformation::MessageEnd() "MessageEnd()" signal it will pass the data +/// on to its attached transformation. +class CRYPTOPP_DLL FilterWithInputQueue : public Filter +{ +public: + virtual ~FilterWithInputQueue() {} + + /// \brief Construct a FilterWithInputQueue + /// \param attachment an optional attached transformation + FilterWithInputQueue(BufferedTransformation *attachment=NULLPTR) : Filter(attachment) {} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("FilterWithInputQueue"); + + m_inQueue.Put(inString, length); + if (messageEnd) + { + IsolatedMessageEnd(blocking); + Output(0, NULLPTR, 0, messageEnd, blocking); + } + return 0; + } + +protected: + virtual bool IsolatedMessageEnd(bool blocking) =0; + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); m_inQueue.Clear();} + + ByteQueue m_inQueue; +}; + +/// \struct BlockPaddingSchemeDef +/// \brief Padding schemes used for block ciphers +/// \since Crypto++ 5.0 +struct BlockPaddingSchemeDef +{ + /// \enum BlockPaddingScheme + /// \brief Padding schemes used for block ciphers. + /// \details DEFAULT_PADDING means PKCS_PADDING if cipher.MandatoryBlockSize() > 1 && + /// cipher.MinLastBlockSize() == 0, which holds for ECB or CBC mode. Otherwise, + /// NO_PADDING for modes like OFB, CFB, CTR, CBC-CTS. + /// \sa Block Cipher Padding for + /// additional details. + /// \since Crypto++ 5.0 + enum BlockPaddingScheme { + /// \brief No padding added to a block + /// \since Crypto++ 5.0 + NO_PADDING, + /// \brief 0's padding added to a block + /// \since Crypto++ 5.0 + ZEROS_PADDING, + /// \brief PKCS #5 padding added to a block + /// \since Crypto++ 5.0 + PKCS_PADDING, + /// \brief 1 and 0's padding added to a block + /// \since Crypto++ 5.0 + ONE_AND_ZEROS_PADDING, + /// \brief W3C padding added to a block + /// \sa XML + /// Encryption Syntax and Processing + /// \since Crypto++ 6.0 + W3C_PADDING, + /// \brief Default padding scheme + /// \since Crypto++ 5.0 + DEFAULT_PADDING + }; +}; + +/// \brief Filter wrapper for StreamTransformation +/// \details StreamTransformationFilter() is a filter wrapper for StreamTransformation(). It is used when +/// pipelining data for stream ciphers and confidentiality-only block ciphers. The filter will optionally +/// handle padding and unpadding when needed. If you are using an authenticated encryption mode of operation, +/// then use AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter() +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL StreamTransformationFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef, private FilterPutSpaceHelper +{ +public: + virtual ~StreamTransformationFilter() {} + + /// \brief Construct a StreamTransformationFilter + /// \param c reference to a StreamTransformation + /// \param attachment an optional attached transformation + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details This contructor creates a StreamTransformationFilter() for stream ciphers and + /// confidentiality-only block cipher modes of operation. If you are using an authenticated + /// encryption mode of operation, then use either AuthenticatedEncryptionFilter() or + /// AuthenticatedDecryptionFilter(). + /// \sa AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter() + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment = NULLPTR, BlockPaddingScheme padding = DEFAULT_PADDING); + + std::string AlgorithmName() const {return m_cipher.AlgorithmName();} + +protected: + + friend class AuthenticatedEncryptionFilter; + friend class AuthenticatedDecryptionFilter; + + /// \brief Construct a StreamTransformationFilter + /// \param c reference to a StreamTransformation + /// \param attachment an optional attached transformation + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \param authenticated flag indicating whether the filter should allow authenticated encryption schemes + /// \details This constructor is used for authenticated encryption mode of operation and by + /// AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter(). + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding, bool authenticated); + + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void NextPutModifiable(byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + + static size_t LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding); + + StreamTransformation &m_cipher; + BlockPaddingScheme m_padding; + unsigned int m_mandatoryBlockSize; + unsigned int m_optimalBufferSize; + unsigned int m_reservedBufferSize; + bool m_isSpecial; +}; + +/// \brief Filter wrapper for HashTransformation +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL HashFilter : public Bufferless, private FilterPutSpaceHelper +{ +public: + virtual ~HashFilter() {} + + /// \brief Construct a HashFilter + /// \param hm reference to a HashTransformation + /// \param attachment an optional attached transformation + /// \param putMessage flag indicating whether the original message should be passed to an attached transformation + /// \param truncatedDigestSize the size of the digest + /// \param messagePutChannel the channel on which the message should be output + /// \param hashPutChannel the channel on which the digest should be output + HashFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, bool putMessage=false, int truncatedDigestSize=-1, const std::string &messagePutChannel=DEFAULT_CHANNEL, const std::string &hashPutChannel=DEFAULT_CHANNEL); + + std::string AlgorithmName() const {return m_hashModule.AlgorithmName();} + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + byte * CreatePutSpace(size_t &size) {return m_hashModule.CreateUpdateSpace(size);} + +private: + HashTransformation &m_hashModule; + bool m_putMessage; + unsigned int m_digestSize; + byte *m_space; + std::string m_messagePutChannel, m_hashPutChannel; +}; + +/// \brief Filter wrapper for HashTransformation +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL HashVerificationFilter : public FilterWithBufferedInput +{ +public: + virtual ~HashVerificationFilter() {} + + /// \brief Exception thrown when a data integrity check failure is encountered + class HashVerificationFailed : public Exception + { + public: + HashVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "HashVerificationFilter: message hash or MAC not valid") {} + }; + + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief Indicates the hash is at the end of the message (i.e., concatenation of message+hash) + HASH_AT_END=0, + /// \brief Indicates the hash is at the beginning of the message (i.e., concatenation of hash+message) + HASH_AT_BEGIN=1, + /// \brief Indicates the message should be passed to an attached transformation + PUT_MESSAGE=2, + /// \brief Indicates the hash should be passed to an attached transformation + PUT_HASH=4, + /// \brief Indicates the result of the verification should be passed to an attached transformation + PUT_RESULT=8, + /// \brief Indicates the filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using \p HASH_AT_BEGIN and \p PUT_RESULT + DEFAULT_FLAGS = HASH_AT_BEGIN | PUT_RESULT + }; + + /// \brief Construct a HashVerificationFilter + /// \param hm reference to a HashTransformation + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + /// \param truncatedDigestSize the size of the digest + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1); + + std::string AlgorithmName() const {return m_hashModule.AlgorithmName();} + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + +private: + friend class AuthenticatedDecryptionFilter; + + HashTransformation &m_hashModule; + word32 m_flags; + unsigned int m_digestSize; + bool m_verified; + SecByteBlock m_expectedHash; +}; + +/// \brief Filter wrapper for encrypting with AuthenticatedSymmetricCipher +/// \details AuthenticatedEncryptionFilter() is a wrapper for encrypting with AuthenticatedSymmetricCipher(), +/// optionally handling padding/unpadding when needed. +/// \sa AuthenticatedDecryptionFilter, EAX, CCM, GCM, AuthenticatedSymmetricCipher +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL AuthenticatedEncryptionFilter : public StreamTransformationFilter +{ +public: + virtual ~AuthenticatedEncryptionFilter() {} + + /// \brief Construct a AuthenticatedEncryptionFilter + /// \param c reference to a AuthenticatedSymmetricCipher + /// \param attachment an optional attached transformation + /// \param putAAD flag indicating whether the AAD should be passed to an attached transformation + /// \param truncatedDigestSize the size of the digest + /// \param macChannel the channel on which the MAC should be output + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + /// \since Crypto++ 5.6.0 + AuthenticatedEncryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, bool putAAD=false, int truncatedDigestSize=-1, const std::string &macChannel=DEFAULT_CHANNEL, BlockPaddingScheme padding = DEFAULT_PADDING); + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length); + +protected: + HashFilter m_hf; +}; + +/// \brief Filter wrapper for decrypting with AuthenticatedSymmetricCipher +/// \details AuthenticatedDecryptionFilter() is a wrapper for decrypting with AuthenticatedSymmetricCipher(), +/// optionally handling padding/unpadding when needed. +/// \sa AuthenticatedEncryptionFilter, EAX, CCM, GCM, AuthenticatedSymmetricCipher +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL AuthenticatedDecryptionFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef +{ +public: + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief Indicates the MAC is at the end of the message (i.e., concatenation of message+mac) + MAC_AT_END=0, + /// \brief Indicates the MAC is at the beginning of the message (i.e., concatenation of mac+message) + MAC_AT_BEGIN=1, + /// \brief Indicates the filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using \p THROW_EXCEPTION + DEFAULT_FLAGS = THROW_EXCEPTION + }; + + virtual ~AuthenticatedDecryptionFilter() {} + + /// \brief Construct a AuthenticatedDecryptionFilter + /// \param c reference to a AuthenticatedSymmetricCipher + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + /// \param truncatedDigestSize the size of the digest + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details Additional authenticated data should be given in channel "AAD". + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + /// \since Crypto++ 5.6.0 + AuthenticatedDecryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1, BlockPaddingScheme padding = DEFAULT_PADDING); + + std::string AlgorithmName() const {return m_hashVerifier.AlgorithmName();} + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + bool GetLastResult() const {return m_hashVerifier.GetLastResult();} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length); + + HashVerificationFilter m_hashVerifier; + StreamTransformationFilter m_streamFilter; +}; + +/// \brief Filter wrapper for PK_Signer +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL SignerFilter : public Unflushable +{ +public: + virtual ~SignerFilter() {} + + /// \brief Construct a SignerFilter + /// \param rng a RandomNumberGenerator derived class + /// \param signer a PK_Signer derived class + /// \param attachment an optional attached transformation + /// \param putMessage flag indicating whether the original message should be passed to an attached transformation + SignerFilter(RandomNumberGenerator &rng, const PK_Signer &signer, BufferedTransformation *attachment = NULLPTR, bool putMessage=false) + : m_rng(rng), m_signer(signer), m_messageAccumulator(signer.NewSignatureAccumulator(rng)), m_putMessage(putMessage) {Detach(attachment);} + + std::string AlgorithmName() const {return m_signer.AlgorithmName();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator &m_rng; + const PK_Signer &m_signer; + member_ptr m_messageAccumulator; + bool m_putMessage; + SecByteBlock m_buf; +}; + +/// \brief Filter wrapper for PK_Verifier +/// \details This filter was formerly named VerifierFilter. The name changed at Crypto++ 5.0. +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL SignatureVerificationFilter : public FilterWithBufferedInput +{ +public: + /// \brief Exception thrown when an invalid signature is encountered + class SignatureVerificationFailed : public Exception + { + public: + SignatureVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "VerifierFilter: digital signature not valid") {} + }; + + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief Indicates the signature is at the end of the message (i.e., concatenation of message+signature) + SIGNATURE_AT_END=0, + /// \brief Indicates the signature is at the beginning of the message (i.e., concatenation of signature+message) + SIGNATURE_AT_BEGIN=1, + /// \brief Indicates the message should be passed to an attached transformation + PUT_MESSAGE=2, + /// \brief Indicates the signature should be passed to an attached transformation + PUT_SIGNATURE=4, + /// \brief Indicates the result of the verification should be passed to an attached transformation + PUT_RESULT=8, + /// \brief Indicates the filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using \p SIGNATURE_AT_BEGIN and \p PUT_RESULT + DEFAULT_FLAGS = SIGNATURE_AT_BEGIN | PUT_RESULT + }; + + virtual ~SignatureVerificationFilter() {} + + /// \brief Construct a SignatureVerificationFilter + /// \param verifier a PK_Verifier derived class + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS); + + std::string AlgorithmName() const {return m_verifier.AlgorithmName();} + + /// \brief Retrieves the result of the last verification + /// \returns true if the signature on the previosus message was valid, false otherwise + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + +private: + const PK_Verifier &m_verifier; + member_ptr m_messageAccumulator; + word32 m_flags; + SecByteBlock m_signature; + bool m_verified; +}; + +/// \brief Redirect input to another BufferedTransformation without owning it +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL Redirector : public CustomSignalPropagation +{ +public: + /// \enum Behavior + /// \brief Controls signal propagation behavior + enum Behavior + { + /// \brief Pass data only + DATA_ONLY = 0x00, + /// \brief Pass signals + PASS_SIGNALS = 0x01, + /// \brief Pass wait events + PASS_WAIT_OBJECTS = 0x02, + /// \brief Pass everything + /// \details PASS_EVERYTHING is default + PASS_EVERYTHING = PASS_SIGNALS | PASS_WAIT_OBJECTS + }; + + virtual ~Redirector() {} + + /// \brief Construct a Redirector + Redirector() : m_target(NULLPTR), m_behavior(PASS_EVERYTHING) {} + + /// \brief Construct a Redirector + /// \param target the destination BufferedTransformation + /// \param behavior Behavior "flags" specifying signal propagation + Redirector(BufferedTransformation &target, Behavior behavior=PASS_EVERYTHING) + : m_target(&target), m_behavior(behavior) {} + + /// \brief Redirect input to another BufferedTransformation + /// \param target the destination BufferedTransformation + void Redirect(BufferedTransformation &target) {m_target = ⌖} + /// \brief Stop redirecting input + void StopRedirection() {m_target = NULLPTR;} + + Behavior GetBehavior() {return (Behavior) m_behavior;} + void SetBehavior(Behavior behavior) {m_behavior=behavior;} + bool GetPassSignals() const {return (m_behavior & PASS_SIGNALS) != 0;} + void SetPassSignals(bool pass) { if (pass) m_behavior |= PASS_SIGNALS; else m_behavior &= ~(word32) PASS_SIGNALS; } + bool GetPassWaitObjects() const {return (m_behavior & PASS_WAIT_OBJECTS) != 0;} + void SetPassWaitObjects(bool pass) { if (pass) m_behavior |= PASS_WAIT_OBJECTS; else m_behavior &= ~(word32) PASS_WAIT_OBJECTS; } + + bool CanModifyInput() const + {return m_target ? m_target->CanModifyInput() : false;} + + void Initialize(const NameValuePairs ¶meters, int propagation); + byte * CreatePutSpace(size_t &size) + { + if (m_target) + return m_target->CreatePutSpace(size); + else + { + size = 0; + return NULLPTR; + } + } + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->Put2(inString, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->MessageSeriesEnd(propagation, blocking) : false;} + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + { + if (m_target) + return m_target->ChannelCreatePutSpace(channel, size); + else + { + size = 0; + return NULLPTR; + } + } + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPut2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPutModifiable2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + + unsigned int GetMaxWaitObjectCount() const + { return m_target && GetPassWaitObjects() ? m_target->GetMaxWaitObjectCount() : 0; } + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) + { if (m_target && GetPassWaitObjects()) m_target->GetWaitObjects(container, callStack); } + +private: + BufferedTransformation *m_target; + word32 m_behavior; +}; + +/// \brief Filter class that is a proxy for a sink +/// \details Used By ProxyFilter +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL OutputProxy : public CustomSignalPropagation +{ +public: + virtual ~OutputProxy() {} + + /// \brief Construct an OutputProxy + /// \param owner the owning transformation + /// \param passSignal flag indicating if signals should be passed + OutputProxy(BufferedTransformation &owner, bool passSignal) : m_owner(owner), m_passSignal(passSignal) {} + + /// \brief Retrieve passSignal flag + /// \returns flag indicating if signals should be passed + bool GetPassSignal() const {return m_passSignal;} + /// \brief Set passSignal flag + /// \param passSignal flag indicating if signals should be passed + void SetPassSignal(bool passSignal) {m_passSignal = passSignal;} + + byte * CreatePutSpace(size_t &size) + {return m_owner.AttachedTransformation()->CreatePutSpace(size);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->Put2(inString, length, m_passSignal ? messageEnd : 0, blocking);} + size_t PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->PutModifiable2(begin, length, m_passSignal ? messageEnd : 0, blocking);} + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) + {if (m_passSignal) m_owner.AttachedTransformation()->Initialize(parameters, propagation);} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->MessageSeriesEnd(propagation, blocking) : false;} + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + {return m_owner.AttachedTransformation()->ChannelCreatePutSpace(channel, size);} + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPut2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPutModifiable2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + +private: + BufferedTransformation &m_owner; + bool m_passSignal; +}; + +/// \brief Base class for Filter classes that are proxies for a chain of other filters +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ProxyFilter : public FilterWithBufferedInput +{ +public: + virtual ~ProxyFilter() {} + + /// \brief Construct a ProxyFilter + /// \param filter an output filter + /// \param firstSize the first Put size + /// \param lastSize the last Put size + /// \param attachment an attached transformation + ProxyFilter(BufferedTransformation *filter, size_t firstSize, size_t lastSize, BufferedTransformation *attachment); + + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// \brief Sets the OutputProxy filter + /// \param filter an OutputProxy filter + void SetFilter(Filter *filter); + void NextPutMultiple(const byte *s, size_t len); + void NextPutModifiable(byte *inString, size_t length); + +protected: + member_ptr m_filter; +}; + +/// \brief Proxy filter that doesn't modify the underlying filter's input or output +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL SimpleProxyFilter : public ProxyFilter +{ +public: + /// \brief Construct a SimpleProxyFilter + /// \param filter an output filter + /// \param attachment an attached transformation + SimpleProxyFilter(BufferedTransformation *filter, BufferedTransformation *attachment) + : ProxyFilter(filter, 0, 0, attachment) {} + + void FirstPut(const byte * inString) + {CRYPTOPP_UNUSED(inString);} + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length) + {CRYPTOPP_UNUSED(inString), CRYPTOPP_UNUSED(length); m_filter->MessageEnd();} +}; + +/// \brief Filter wrapper for PK_Encryptor +/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Encryptor::CreateEncryptionFilter. +/// This class provides symmetry with VerifierFilter. +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL PK_EncryptorFilter : public SimpleProxyFilter +{ +public: + /// \brief Construct a PK_EncryptorFilter + /// \param rng a RandomNumberGenerator derived class + /// \param encryptor a PK_Encryptor derived class + /// \param attachment an optional attached transformation + PK_EncryptorFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment = NULLPTR) + : SimpleProxyFilter(encryptor.CreateEncryptionFilter(rng), attachment) {} +}; + +/// \brief Filter wrapper for PK_Decryptor +/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Decryptor::CreateDecryptionFilter. +/// This class provides symmetry with SignerFilter. +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL PK_DecryptorFilter : public SimpleProxyFilter +{ +public: + /// \brief Construct a PK_DecryptorFilter + /// \param rng a RandomNumberGenerator derived class + /// \param decryptor a PK_Decryptor derived class + /// \param attachment an optional attached transformation + PK_DecryptorFilter(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment = NULLPTR) + : SimpleProxyFilter(decryptor.CreateDecryptionFilter(rng), attachment) {} +}; + +/// \brief Append input to a string object +/// \tparam T std::basic_string type +/// \details StringSinkTemplate is a StringSinkTemplate typedef +/// \since Crypto++ 5.0 +template +class StringSinkTemplate : public Bufferless +{ +public: + virtual ~StringSinkTemplate() {} + + /// \brief Construct a StringSinkTemplate + /// \param output std::basic_string type + StringSinkTemplate(T &output) + : m_output(&output) {CRYPTOPP_ASSERT(sizeof(output[0])==1);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {if (!parameters.GetValue("OutputStringPointer", m_output)) throw InvalidArgument("StringSink: OutputStringPointer not specified");} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); + typedef typename T::traits_type::char_type char_type; + + if (length > 0) + { + typename T::size_type size = m_output->size(); + if (length < size && size + length > m_output->capacity()) + m_output->reserve(2*size); + m_output->append((const char_type *)inString, (const char_type *)inString+length); + } + return 0; + } + +private: + T *m_output; +}; + +/// \brief Append input to a string object +/// \details StringSink is a typedef for StringSinkTemplate. +/// \sa ArraySink, ArrayXorSink +/// \since Crypto++ 4.0 +DOCUMENTED_TYPEDEF(StringSinkTemplate, StringSink) +CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate; + +/// \brief Incorporates input into RNG as additional entropy +/// \since Crypto++ 4.0 +class RandomNumberSink : public Bufferless +{ +public: + virtual ~RandomNumberSink() {} + + /// \brief Construct a RandomNumberSink + RandomNumberSink() + : m_rng(NULLPTR) {} + + /// \brief Construct a RandomNumberSink + /// \param rng a RandomNumberGenerator derived class + RandomNumberSink(RandomNumberGenerator &rng) + : m_rng(&rng) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator *m_rng; +}; + +/// \brief Copy input to a memory buffer +/// \details ArraySink wraps a fixed size buffer. The buffer is full once Put returns non-0. +/// When used in a pipleline, ArraySink silently discards input if the buffer is full. +/// AvailableSize() can be used to determine how much space remains in the buffer. +/// TotalPutLength() can be used to determine how many bytes were processed. +/// \sa StringSink, ArrayXorSink +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ArraySink : public Bufferless +{ +public: + virtual ~ArraySink() {} + + /// \brief Construct an ArraySink + /// \param parameters a set of NameValuePairs to initialize this object + /// \details Name::OutputBuffer() is a mandatory parameter using this constructor. + ArraySink(const NameValuePairs ¶meters = g_nullNameValuePairs) + : m_buf(NULLPTR), m_size(0), m_total(0) {IsolatedInitialize(parameters);} + + /// \brief Construct an ArraySink + /// \param buf pointer to a memory buffer + /// \param size length of the memory buffer + ArraySink(byte *buf, size_t size) + : m_buf(buf), m_size(size), m_total(0) {} + + /// \brief Provides the size remaining in the Sink + /// \returns size remaining in the Sink, in bytes + size_t AvailableSize() {return SaturatingSubtract(m_size, m_total);} + + /// \brief Provides the number of bytes written to the Sink + /// \returns number of bytes written to the Sink, in bytes + lword TotalPutLength() {return m_total;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(size_t &size); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +protected: + byte *m_buf; + size_t m_size; + lword m_total; +}; + +/// \brief Xor input to a memory buffer +/// \details ArrayXorSink wraps a fixed size buffer. The buffer is full once Put returns non-0. +/// When used in a pipleline, ArrayXorSink silently discards input if the buffer is full. +/// AvailableSize() can be used to determine how much space remains in the buffer. +/// TotalPutLength() can be used to determine how many bytes were processed. +/// \sa StringSink, ArraySink +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ArrayXorSink : public ArraySink +{ +public: + virtual ~ArrayXorSink() {} + + /// \brief Construct an ArrayXorSink + /// \param buf pointer to a memory buffer + /// \param size length of the memory buffer + ArrayXorSink(byte *buf, size_t size) + : ArraySink(buf, size) {} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + byte * CreatePutSpace(size_t &size) {return BufferedTransformation::CreatePutSpace(size);} +}; + +/// \brief String-based implementation of Store interface +/// \since Crypto++ 4.0 +class StringStore : public Store +{ +public: + /// \brief Construct a StringStore + /// \param string pointer to a C-String + StringStore(const char *string = NULLPTR) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + /// \brief Construct a StringStore + /// \param string pointer to a memory buffer + /// \param length size of the memory buffer + StringStore(const byte *string, size_t length) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + + /// \brief Construct a StringStore + /// \tparam T std::basic_string type + /// \param string reference to a std::basic_string type + template StringStore(const T &string) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + CRYPTOPP_DLL size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + CRYPTOPP_DLL size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + +private: + CRYPTOPP_DLL void StoreInitialize(const NameValuePairs ¶meters); + + const byte *m_store; + size_t m_length, m_count; +}; + +/// \brief RNG-based implementation of Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL RandomNumberStore : public Store +{ +public: + virtual ~RandomNumberStore() {} + + RandomNumberStore() + : m_rng(NULLPTR), m_length(0), m_count(0) {} + + RandomNumberStore(RandomNumberGenerator &rng, lword length) + : m_rng(&rng), m_length(length), m_count(0) {} + + bool AnyRetrievable() const {return MaxRetrievable() != 0;} + lword MaxRetrievable() const {return m_length-m_count;} + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const + { + CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); + throw NotImplemented("RandomNumberStore: CopyRangeTo2() is not supported by this store"); + } + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + RandomNumberGenerator *m_rng; + lword m_length, m_count; +}; + +/// \brief Empty store +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL NullStore : public Store +{ +public: + NullStore(lword size = ULONG_MAX) : m_size(size) {} + void StoreInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters);} + lword MaxRetrievable() const {return m_size;} + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + +private: + lword m_size; +}; + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Source is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +/// \sa Store and SourceTemplate +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Source : public InputRejecting +{ +public: + virtual ~Source() {} + + /// \brief Construct a Source + /// \param attachment an optional attached transformation + Source(BufferedTransformation *attachment = NULLPTR) + {Source::Detach(attachment);} + + /// \name PIPELINE + //@{ + + /// \brief Pump data to attached transformation + /// \param pumpMax the maximpum number of bytes to pump + /// \returns the number of bytes that remain in the block (i.e., bytes not processed) + /// \details Internally, Pump() calls Pump2(). + /// \note pumpMax is a \p lword, which is a 64-bit value that typically uses \p LWORD_MAX. The default + /// argument is a \p size_t that uses \p SIZE_MAX, and it can be 32-bits or 64-bits. + lword Pump(lword pumpMax=(size_t)SIZE_MAX) + {Pump2(pumpMax); return pumpMax;} + + /// \brief Pump messages to attached transformation + /// \param count the maximpum number of messages to pump + /// \returns TODO + /// \details Internally, PumpMessages() calls PumpMessages2(). + unsigned int PumpMessages(unsigned int count=UINT_MAX) + {PumpMessages2(count); return count;} + + /// \brief Pump all data to attached transformation + /// \details Internally, PumpAll() calls PumpAll2(). + void PumpAll() + {PumpAll2();} + + /// \brief Pump data to attached transformation + /// \param byteCount the maximpum number of bytes to pump + /// \param blocking specifies whether the object should block when processing input + /// \returns the number of bytes that remain in the block (i.e., bytes not processed) + /// \details byteCount is an \a IN and \a OUT parameter. When the call is made, byteCount is the + /// requested size of the pump. When the call returns, byteCount is the number of bytes that + /// were pumped. + virtual size_t Pump2(lword &byteCount, bool blocking=true) =0; + + /// \brief Pump messages to attached transformation + /// \param messageCount the maximpum number of messages to pump + /// \param blocking specifies whether the object should block when processing input + /// \details messageCount is an IN and OUT parameter. + virtual size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) =0; + + /// \brief Pump all data to attached transformation + /// \param blocking specifies whether the object should block when processing input + /// \returns the number of bytes that remain in the block (i.e., bytes not processed) + virtual size_t PumpAll2(bool blocking=true); + + /// \brief Determines if the Source is exhausted + /// \returns true if the source has been exhausted + virtual bool SourceExhausted() const =0; + + //@} + +protected: + void SourceInitialize(bool pumpAll, const NameValuePairs ¶meters) + { + IsolatedInitialize(parameters); + if (pumpAll) + PumpAll(); + } +}; + +/// \brief Transform a Store into a Source +/// \tparam T the class or type +/// \since Crypto++ 5.0 +template +class SourceTemplate : public Source +{ +public: + virtual ~SourceTemplate() {} + + /// \brief Construct a SourceTemplate + /// \param attachment an attached transformation + SourceTemplate(BufferedTransformation *attachment) + : Source(attachment) {} + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_store.IsolatedInitialize(parameters);} + size_t Pump2(lword &byteCount, bool blocking=true) + {return m_store.TransferTo2(*AttachedTransformation(), byteCount, DEFAULT_CHANNEL, blocking);} + size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) + {return m_store.TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);} + size_t PumpAll2(bool blocking=true) + {return m_store.TransferAllTo2(*AttachedTransformation(), DEFAULT_CHANNEL, blocking);} + bool SourceExhausted() const + {return !m_store.AnyRetrievable() && !m_store.AnyMessages();} + void SetAutoSignalPropagation(int propagation) + {m_store.SetAutoSignalPropagation(propagation);} + int GetAutoSignalPropagation() const + {return m_store.GetAutoSignalPropagation();} + +protected: + T m_store; +}; + +/// \brief String-based implementation of the Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL StringSource : public SourceTemplate +{ +public: + /// \brief Construct a StringSource + /// \param attachment an optional attached transformation + StringSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a StringSource + /// \param string C-String + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + /// \brief Construct a StringSource + /// \param string binary byte array + /// \param length size of the byte array + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + + /// \brief Construct a StringSource + /// \param string std::string + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} +}; + +/// \brief Pointer-based implementation of the Source interface +/// \details ArraySource is a typedef for StringSource. Use the third constructor for an array source. +/// The third constructor takes a pointer and length. +/// \since Crypto++ 5.6.0 +DOCUMENTED_TYPEDEF(StringSource, ArraySource) + +/// \brief RNG-based implementation of Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL RandomNumberSource : public SourceTemplate +{ +public: + RandomNumberSource(RandomNumberGenerator &rng, int length, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) + {SourceInitialize(pumpAll, MakeParameters("RandomNumberGeneratorPointer", &rng)("RandomNumberStoreSize", length));} +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/fips140.h b/include/cryptlib/fips140.h new file mode 100644 index 0000000..8aab65c --- /dev/null +++ b/include/cryptlib/fips140.h @@ -0,0 +1,112 @@ +// fips140.h - originally written and placed in the public domain by Wei Dai + +/// \file fips140.h +/// \brief Classes and functions for the FIPS 140-2 validated library +/// \details The FIPS validated library is only available on Windows as a DLL. Once compiled, +/// the library is always in FIPS mode contingent upon successful execution of +/// DoPowerUpSelfTest() or DoDllPowerUpSelfTest(). +/// \sa Visual Studio and +/// config.h on the Crypto++ wiki. + +#ifndef CRYPTOPP_FIPS140_H +#define CRYPTOPP_FIPS140_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// Exception thrown when a crypto algorithm is used after a self test fails +/// \details The self tests for an algorithm are performed by Algortihm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +class CRYPTOPP_DLL SelfTestFailure : public Exception +{ +public: + explicit SelfTestFailure(const std::string &s) : Exception(OTHER_ERROR, s) {} +}; + +/// \brief Determines whether the library provides FIPS validated cryptography +/// \returns true if FIPS 140-2 validated features were enabled at compile time. +/// \details true if FIPS 140-2 validated features were enabled at compile time, +/// false otherwise. +/// \note FIPS mode is enabled at compile time. A program or other module cannot +/// arbitrarily enter or exit the mode. +CRYPTOPP_DLL bool CRYPTOPP_API FIPS_140_2_ComplianceEnabled(); + +/// \brief Status of the power-up self test +enum PowerUpSelfTestStatus { + + /// \brief The self tests have not been performed. + POWER_UP_SELF_TEST_NOT_DONE, + /// \brief The self tests were executed via DoPowerUpSelfTest() or + /// DoDllPowerUpSelfTest(), but the result was failure. + POWER_UP_SELF_TEST_FAILED, + /// \brief The self tests were executed via DoPowerUpSelfTest() or + /// DoDllPowerUpSelfTest(), and the result was success. + POWER_UP_SELF_TEST_PASSED +}; + +/// \brief Performs the power-up self test +/// \param moduleFilename the fully qualified name of the module +/// \param expectedModuleMac the expected MAC of the components protected by the integrity check +/// \details Performs the power-up self test, and sets the self test status to +/// POWER_UP_SELF_TEST_PASSED or POWER_UP_SELF_TEST_FAILED. +/// \details The self tests for an algorithm are performed by the Algortihm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +CRYPTOPP_DLL void CRYPTOPP_API DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleMac); + +/// \brief Performs the power-up self test on the DLL +/// \details Performs the power-up self test using the filename of this DLL and the +/// embedded module MAC, and sets the self test status to POWER_UP_SELF_TEST_PASSED or +/// POWER_UP_SELF_TEST_FAILED. +/// \details The self tests for an algorithm are performed by the Algortihm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +CRYPTOPP_DLL void CRYPTOPP_API DoDllPowerUpSelfTest(); + +/// \brief Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED +/// \details Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED to simulate failure. +CRYPTOPP_DLL void CRYPTOPP_API SimulatePowerUpSelfTestFailure(); + +/// \brief Provides the current power-up self test status +/// \returns the current power-up self test status +CRYPTOPP_DLL PowerUpSelfTestStatus CRYPTOPP_API GetPowerUpSelfTestStatus(); + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +typedef PowerUpSelfTestStatus (CRYPTOPP_API * PGetPowerUpSelfTestStatus)(); +#endif + +/// \brief Class object that calculates the MAC on the module +/// \returns the MAC for the module +CRYPTOPP_DLL MessageAuthenticationCode * CRYPTOPP_API NewIntegrityCheckingMAC(); + +/// \brief Verifies the MAC on the module +/// \param moduleFilename the fully qualified name of the module +/// \param expectedModuleMac the expected MAC of the components protected by the integrity check +/// \param pActualMac the actual MAC of the components calculated by the integrity check +/// \param pMacFileLocation the offest of the MAC in the PE/PE+ module +/// \returns true if the MAC is valid, false otherwise +CRYPTOPP_DLL bool CRYPTOPP_API IntegrityCheckModule(const char *moduleFilename, const byte *expectedModuleMac, SecByteBlock *pActualMac = NULLPTR, unsigned long *pMacFileLocation = NULLPTR); + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +// this is used by Algorithm constructor to allow Algorithm objects to be constructed for the self test +bool PowerUpSelfTestInProgressOnThisThread(); + +void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress); + +void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); + +void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); +#endif + +/// \brief The placeholder used prior to embedding the actual MAC in the module. +/// \details After the DLL is built but before it is MAC'd, the string CRYPTOPP_DUMMY_DLL_MAC +/// is used as a placeholder for the actual MAC. A post-build step is performed which calculates +/// the MAC of the DLL and embeds it in the module. The actual MAC is written by the +/// cryptest.exe program using the mac_dll subcommand. +#define CRYPTOPP_DUMMY_DLL_MAC "MAC_51f34b8db820ae8" + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/fltrimpl.h b/include/cryptlib/fltrimpl.h new file mode 100644 index 0000000..0c5d153 --- /dev/null +++ b/include/cryptlib/fltrimpl.h @@ -0,0 +1,87 @@ +#ifndef CRYPTOPP_FLTRIMPL_H +#define CRYPTOPP_FLTRIMPL_H + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4100) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-value" +#endif + +#define FILTER_BEGIN \ + switch (m_continueAt) \ + { \ + case 0: \ + m_inputPosition = 0; + +#define FILTER_END_NO_MESSAGE_END_NO_RETURN \ + break; \ + default: \ + CRYPTOPP_ASSERT(false); \ + } + +#define FILTER_END_NO_MESSAGE_END \ + FILTER_END_NO_MESSAGE_END_NO_RETURN \ + return 0; + +/* +#define FILTER_END \ + case -1: \ + if (messageEnd && Output(-1, NULLPTR, 0, messageEnd, blocking)) \ + return 1; \ + FILTER_END_NO_MESSAGE_END +*/ + +#define FILTER_OUTPUT3(site, statement, output, length, messageEnd, channel) \ + {\ + case site: \ + statement; \ + if (Output(site, output, length, messageEnd, blocking, channel)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT2(site, statement, output, length, messageEnd) \ + FILTER_OUTPUT3(site, statement, output, length, messageEnd, DEFAULT_CHANNEL) + +#define FILTER_OUTPUT(site, output, length, messageEnd) \ + FILTER_OUTPUT2(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT_BYTE(site, output) \ + FILTER_OUTPUT(site, &(const byte &)(byte)output, 1, 0) + +#define FILTER_OUTPUT2_MODIFIABLE(site, statement, output, length, messageEnd) \ + {\ + /* fall through */ \ + case site: \ + statement; \ + if (OutputModifiable(site, output, length, messageEnd, blocking)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT_MODIFIABLE(site, output, length, messageEnd) \ + FILTER_OUTPUT2_MODIFIABLE(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, statement, output, length, messageEnd, modifiable) \ + {\ + /* fall through */ \ + case site: \ + statement; \ + if (modifiable ? OutputModifiable(site, output, length, messageEnd, blocking) : Output(site, output, length, messageEnd, blocking)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT_MAYBE_MODIFIABLE(site, output, length, messageEnd, modifiable) \ + FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, 0, output, length, messageEnd, modifiable) + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/include/cryptlib/gcm.h b/include/cryptlib/gcm.h new file mode 100644 index 0000000..f2c26d0 --- /dev/null +++ b/include/cryptlib/gcm.h @@ -0,0 +1,131 @@ +// gcm.h - originally written and placed in the public domain by Wei Dai + +/// \file gcm.h +/// \brief GCM block cipher mode of operation +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_GCM_H +#define CRYPTOPP_GCM_H + +#include "authenc.h" +#include "modes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \enum GCM_TablesOption +/// \brief GCM table size options +enum GCM_TablesOption { + /// \brief Use a table with 2K entries + GCM_2K_Tables, + /// \brief Use a table with 64K entries + GCM_64K_Tables}; + +/// \brief GCM block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GCM_Base : public AuthenticatedSymmetricCipherBase +{ +public: + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + std::string("/GCM");} + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength();} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const + {return GetBlockCipher().GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const + {return GetBlockCipher().IsValidKeyLength(n);} + unsigned int OptimalDataAlignment() const; + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 12;} + unsigned int MinIVLength() const + {return 1;} + unsigned int MaxIVLength() const + {return UINT_MAX;} // (W64LIT(1)<<61)-1 in the standard + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return (W64LIT(1)<<61)-1;} + lword MaxMessageLength() const + {return ((W64LIT(1)<<39)-256)/8;} + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return false;} + unsigned int AuthenticationBlockSize() const + {return HASH_BLOCKSIZE;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + + virtual BlockCipher & AccessBlockCipher() =0; + virtual GCM_TablesOption GetTablesOption() const =0; + + const BlockCipher & GetBlockCipher() const {return const_cast(this)->AccessBlockCipher();}; + byte *HashBuffer() {return m_buffer+REQUIRED_BLOCKSIZE;} + byte *HashKey() {return m_buffer+2*REQUIRED_BLOCKSIZE;} + byte *MulTable() {return m_buffer+3*REQUIRED_BLOCKSIZE;} + inline void ReverseHashBufferIfNeeded(); + + class CRYPTOPP_DLL GCTR : public CTR_Mode_ExternalCipher::Encryption + { + protected: + void IncrementCounterBy256(); + }; + + GCTR m_ctr; + static word16 s_reductionTable[256]; + static volatile bool s_reductionTableInitialized; + enum {REQUIRED_BLOCKSIZE = 16, HASH_BLOCKSIZE = 16}; +}; + +/// \brief GCM block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class GCM_Final : public GCM_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/GCM");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + GCM_TablesOption GetTablesOption() const {return T_TablesOption;} + BlockCipher & AccessBlockCipher() {return m_cipher;} + typename T_BlockCipher::Encryption m_cipher; +}; + +/// \brief GCM block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables +/// \details \p GCM provides the \p Encryption and \p Decryption typedef. See GCM_Base +/// and GCM_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa GCM Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct GCM : public AuthenticatedSymmetricCipherDocumentation +{ + typedef GCM_Final Encryption; + typedef GCM_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/gf256.h b/include/cryptlib/gf256.h new file mode 100644 index 0000000..3c5c3f6 --- /dev/null +++ b/include/cryptlib/gf256.h @@ -0,0 +1,72 @@ +// gf256.h - originally written and placed in the public domain by Wei Dai + +/// \file gf256.h +/// \brief Classes and functions for schemes over GF(256) + +#ifndef CRYPTOPP_GF256_H +#define CRYPTOPP_GF256_H + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GF(256) with polynomial basis +class GF256 +{ +public: + typedef byte Element; + typedef int RandomizationParameter; + + GF256(byte modulus) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {CRYPTOPP_UNUSED(ignored); return rng.GenerateByte();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Zero() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {CRYPTOPP_UNUSED(a); return 0;} + + Element One() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/gf2_32.h b/include/cryptlib/gf2_32.h new file mode 100644 index 0000000..9e794fe --- /dev/null +++ b/include/cryptlib/gf2_32.h @@ -0,0 +1,73 @@ +// gf2_32.h - originally written and placed in the public domain by Wei Dai + +/// \file gf2_32.h +/// \brief Classes and functions for schemes over GF(2^32) + +#ifndef CRYPTOPP_GF2_32_H +#define CRYPTOPP_GF2_32_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GF(2^32) with polynomial basis +class GF2_32 +{ +public: + typedef word32 Element; + typedef int RandomizationParameter; + + GF2_32(word32 modulus=0x0000008D) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {CRYPTOPP_UNUSED(ignored); return rng.GenerateWord32();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Identity() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {CRYPTOPP_UNUSED(a); return 0;} + + Element MultiplicativeIdentity() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word32 m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/gf2n.h b/include/cryptlib/gf2n.h new file mode 100644 index 0000000..f90633a --- /dev/null +++ b/include/cryptlib/gf2n.h @@ -0,0 +1,387 @@ +// gf2n.h - originally written and placed in the public domain by Wei Dai + +/// \file gf2n.h +/// \brief Classes and functions for schemes over GF(2^n) + +#ifndef CRYPTOPP_GF2N_H +#define CRYPTOPP_GF2N_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algebra.h" +#include "misc.h" +#include "asn.h" + +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Polynomial with Coefficients in GF(2) +/*! \nosubgrouping */ +class CRYPTOPP_DLL PolynomialMod2 +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// \brief Excpetion thrown when divide by zero is encountered + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialMod2: division by zero") {} + }; + + typedef unsigned int RandomizationParameter; + //@} + + /// \name CREATORS + //@{ + /// \brief Construct the zero polynomial + PolynomialMod2(); + /// Copy construct a PolynomialMod2 + PolynomialMod2(const PolynomialMod2& t); + + /// \brief Construct a PolynomialMod2 from a word + /// \details value should be encoded with the least significant bit as coefficient to x^0 + /// and most significant bit as coefficient to x^(WORD_BITS-1) + /// bitLength denotes how much memory to allocate initially + PolynomialMod2(word value, size_t bitLength=WORD_BITS); + + /// \brief Construct a PolynomialMod2 from big-endian byte array + PolynomialMod2(const byte *encodedPoly, size_t byteCount) + {Decode(encodedPoly, byteCount);} + + /// \brief Construct a PolynomialMod2 from big-endian form stored in a BufferedTransformation + PolynomialMod2(BufferedTransformation &encodedPoly, size_t byteCount) + {Decode(encodedPoly, byteCount);} + + /// \brief Create a uniformly distributed random polynomial + /// \details Create a random polynomial uniformly distributed over all polynomials with degree less than bitcount + PolynomialMod2(RandomNumberGenerator &rng, size_t bitcount) + {Randomize(rng, bitcount);} + + /// \brief Provides x^i + /// \returns x^i + static PolynomialMod2 CRYPTOPP_API Monomial(size_t i); + /// \brief Provides x^t0 + x^t1 + x^t2 + /// \returns x^t0 + x^t1 + x^t2 + static PolynomialMod2 CRYPTOPP_API Trinomial(size_t t0, size_t t1, size_t t2); + /// \brief Provides x^t0 + x^t1 + x^t2 + x^t3 + x^t4 + /// \returns x^t0 + x^t1 + x^t2 + x^t3 + x^t4 + static PolynomialMod2 CRYPTOPP_API Pentanomial(size_t t0, size_t t1, size_t t2, size_t t3, size_t t4); + /// \brief Provides x^(n-1) + ... + x + 1 + /// \returns x^(n-1) + ... + x + 1 + static PolynomialMod2 CRYPTOPP_API AllOnes(size_t n); + + /// \brief The Zero polinomial + /// \returns the zero polynomial + static const PolynomialMod2 & CRYPTOPP_API Zero(); + /// \brief The One polinomial + /// \returns the one polynomial + static const PolynomialMod2 & CRYPTOPP_API One(); + //@} + + /// \name ENCODE/DECODE + //@{ + /// minimum number of bytes to encode this polynomial + /*! MinEncodedSize of 0 is 1 */ + unsigned int MinEncodedSize() const {return STDMAX(1U, ByteCount());} + + /// encode in big-endian format + /// \details if outputLen < MinEncodedSize, the most significant bytes will be dropped + /// if outputLen > MinEncodedSize, the most significant bytes will be padded + void Encode(byte *output, size_t outputLen) const; + /// + void Encode(BufferedTransformation &bt, size_t outputLen) const; + + /// + void Decode(const byte *input, size_t inputLen); + /// + //* Precondition: bt.MaxRetrievable() >= inputLen + void Decode(BufferedTransformation &bt, size_t inputLen); + + /// encode value as big-endian octet string + void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const; + /// decode value as big-endian octet string + void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length); + //@} + + /// \name ACCESSORS + //@{ + /// number of significant bits = Degree() + 1 + unsigned int BitCount() const; + /// number of significant bytes = ceiling(BitCount()/8) + unsigned int ByteCount() const; + /// number of significant words = ceiling(ByteCount()/sizeof(word)) + unsigned int WordCount() const; + + /// return the n-th bit, n=0 being the least significant bit + bool GetBit(size_t n) const {return GetCoefficient(n)!=0;} + /// return the n-th byte + byte GetByte(size_t n) const; + + /// the zero polynomial will return a degree of -1 + signed int Degree() const {return (signed int)(BitCount()-1U);} + /// degree + 1 + unsigned int CoefficientCount() const {return BitCount();} + /// return coefficient for x^i + int GetCoefficient(size_t i) const + {return (i/WORD_BITS < reg.size()) ? int(reg[i/WORD_BITS] >> (i % WORD_BITS)) & 1 : 0;} + /// return coefficient for x^i + int operator[](unsigned int i) const {return GetCoefficient(i);} + + /// + bool IsZero() const {return !*this;} + /// + bool Equals(const PolynomialMod2 &rhs) const; + //@} + + /// \name MANIPULATORS + //@{ + /// + PolynomialMod2& operator=(const PolynomialMod2& t); + /// + PolynomialMod2& operator&=(const PolynomialMod2& t); + /// + PolynomialMod2& operator^=(const PolynomialMod2& t); + /// + PolynomialMod2& operator+=(const PolynomialMod2& t) {return *this ^= t;} + /// + PolynomialMod2& operator-=(const PolynomialMod2& t) {return *this ^= t;} + /// + PolynomialMod2& operator*=(const PolynomialMod2& t); + /// + PolynomialMod2& operator/=(const PolynomialMod2& t); + /// + PolynomialMod2& operator%=(const PolynomialMod2& t); + /// + PolynomialMod2& operator<<=(unsigned int); + /// + PolynomialMod2& operator>>=(unsigned int); + + /// + void Randomize(RandomNumberGenerator &rng, size_t bitcount); + + /// + void SetBit(size_t i, int value = 1); + /// set the n-th byte to value + void SetByte(size_t n, byte value); + + /// + void SetCoefficient(size_t i, int value) {SetBit(i, value);} + + /// + void swap(PolynomialMod2 &a) {reg.swap(a.reg);} + //@} + + /// \name UNARY OPERATORS + //@{ + /// + bool operator!() const; + /// + PolynomialMod2 operator+() const {return *this;} + /// + PolynomialMod2 operator-() const {return *this;} + //@} + + /// \name BINARY OPERATORS + //@{ + /// + PolynomialMod2 And(const PolynomialMod2 &b) const; + /// + PolynomialMod2 Xor(const PolynomialMod2 &b) const; + /// + PolynomialMod2 Plus(const PolynomialMod2 &b) const {return Xor(b);} + /// + PolynomialMod2 Minus(const PolynomialMod2 &b) const {return Xor(b);} + /// + PolynomialMod2 Times(const PolynomialMod2 &b) const; + /// + PolynomialMod2 DividedBy(const PolynomialMod2 &b) const; + /// + PolynomialMod2 Modulo(const PolynomialMod2 &b) const; + + /// + PolynomialMod2 operator>>(unsigned int n) const; + /// + PolynomialMod2 operator<<(unsigned int n) const; + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// sum modulo 2 of all coefficients + unsigned int Parity() const; + + /// check for irreducibility + bool IsIrreducible() const; + + /// is always zero since we're working modulo 2 + PolynomialMod2 Doubled() const {return Zero();} + /// + PolynomialMod2 Squared() const; + + /// only 1 is a unit + bool IsUnit() const {return Equals(One());} + /// return inverse if *this is a unit, otherwise return 0 + PolynomialMod2 MultiplicativeInverse() const {return IsUnit() ? One() : Zero();} + + /// greatest common divisor + static PolynomialMod2 CRYPTOPP_API Gcd(const PolynomialMod2 &a, const PolynomialMod2 &n); + /// calculate multiplicative inverse of *this mod n + PolynomialMod2 InverseMod(const PolynomialMod2 &) const; + + /// calculate r and q such that (a == d*q + r) && (deg(r) < deg(d)) + static void CRYPTOPP_API Divide(PolynomialMod2 &r, PolynomialMod2 &q, const PolynomialMod2 &a, const PolynomialMod2 &d); + //@} + + /// \name INPUT/OUTPUT + //@{ + /// + friend std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a); + //@} + +private: + friend class GF2NT; + + SecWordBlock reg; +}; + +/// +inline bool operator==(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Equals(b);} +/// +inline bool operator!=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return !(a==b);} +/// compares degree +inline bool operator> (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() > b.Degree();} +/// compares degree +inline bool operator>=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() >= b.Degree();} +/// compares degree +inline bool operator< (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() < b.Degree();} +/// compares degree +inline bool operator<=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() <= b.Degree();} +/// +inline CryptoPP::PolynomialMod2 operator&(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.And(b);} +/// +inline CryptoPP::PolynomialMod2 operator^(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Xor(b);} +/// +inline CryptoPP::PolynomialMod2 operator+(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Plus(b);} +/// +inline CryptoPP::PolynomialMod2 operator-(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Minus(b);} +/// +inline CryptoPP::PolynomialMod2 operator*(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Times(b);} +/// +inline CryptoPP::PolynomialMod2 operator/(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.DividedBy(b);} +/// +inline CryptoPP::PolynomialMod2 operator%(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Modulo(b);} + +// CodeWarrior 8 workaround: put these template instantiations after overloaded operator declarations, +// but before the use of QuotientRing > for VC .NET 2003 +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain; +CRYPTOPP_DLL_TEMPLATE_CLASS EuclideanDomainOf; +CRYPTOPP_DLL_TEMPLATE_CLASS QuotientRing >; + +/// \brief GF(2^n) with Polynomial Basis +class CRYPTOPP_DLL GF2NP : public QuotientRing > +{ +public: + GF2NP(const PolynomialMod2 &modulus); + + virtual GF2NP * Clone() const {return new GF2NP(*this);} + virtual void DEREncode(BufferedTransformation &bt) const + {CRYPTOPP_UNUSED(bt); CRYPTOPP_ASSERT(false);} // no ASN.1 syntax yet for general polynomial basis + + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + bool Equal(const Element &a, const Element &b) const + {CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree() && b.Degree() < m_modulus.Degree()); return a.Equals(b);} + + bool IsUnit(const Element &a) const + {CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree()); return !!a;} + + unsigned int MaxElementBitLength() const + {return m;} + + unsigned int MaxElementByteLength() const + {return (unsigned int)BitsToBytes(MaxElementBitLength());} + + Element SquareRoot(const Element &a) const; + + Element HalfTrace(const Element &a) const; + + // returns z such that z^2 + z == a + Element SolveQuadraticEquation(const Element &a) const; + +protected: + unsigned int m; +}; + +/// \brief GF(2^n) with Trinomial Basis +class CRYPTOPP_DLL GF2NT : public GF2NP +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2 + GF2NT(unsigned int t0, unsigned int t1, unsigned int t2); + + GF2NP * Clone() const {return new GF2NT(*this);} + void DEREncode(BufferedTransformation &bt) const; + + const Element& Multiply(const Element &a, const Element &b) const; + + const Element& Square(const Element &a) const + {return Reduced(a.Squared());} + + const Element& MultiplicativeInverse(const Element &a) const; + +private: + const Element& Reduced(const Element &a) const; + + unsigned int t0, t1; + mutable PolynomialMod2 result; +}; + +/// \brief GF(2^n) with Pentanomial Basis +class CRYPTOPP_DLL GF2NPP : public GF2NP +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2 + x^t3 + x^t4, t0 > t1 > t2 > t3 > t4 + GF2NPP(unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4) + : GF2NP(PolynomialMod2::Pentanomial(t0, t1, t2, t3, t4)), t0(t0), t1(t1), t2(t2), t3(t3) {} + + GF2NP * Clone() const {return new GF2NPP(*this);} + void DEREncode(BufferedTransformation &bt) const; + +private: + unsigned int t0, t1, t2, t3; +}; + +// construct new GF2NP from the ASN.1 sequence Characteristic-two +CRYPTOPP_DLL GF2NP * CRYPTOPP_API BERDecodeGF2NP(BufferedTransformation &bt); + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::PolynomialMod2 &a, CryptoPP::PolynomialMod2 &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/gfpcrypt.h b/include/cryptlib/gfpcrypt.h new file mode 100644 index 0000000..7cfa1f6 --- /dev/null +++ b/include/cryptlib/gfpcrypt.h @@ -0,0 +1,861 @@ +// gfpcrypt.h - originally written and placed in the public domain by Wei Dai +// RFC6979 deterministic signatures added by Douglas Roark +// ECGDSA added by Jeffrey Walton + +/// \file gfpcrypt.h +/// \brief Classes and functions for schemes based on Discrete Logs (DL) over GF(p) + +#ifndef CRYPTOPP_GFPCRYPT_H +#define CRYPTOPP_GFPCRYPT_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4189 4231 4275) +#endif + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "modexppc.h" +#include "algparam.h" +#include "smartptr.h" +#include "sha.h" +#include "asn.h" +#include "hmac.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters; + +/// \brief Integer-based GroupParameters specialization +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBased : public ASN1CryptoMaterial > +{ + typedef DL_GroupParameters_IntegerBased ThisClass; + +public: + virtual ~DL_GroupParameters_IntegerBased() {} + + /// \brief Initialize a group parameters over integers + /// \param params the group parameters + void Initialize(const DL_GroupParameters_IntegerBased ¶ms) + {Initialize(params.GetModulus(), params.GetSubgroupOrder(), params.GetSubgroupGenerator());} + + /// \brief Create a group parameters over integers + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the size of p, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int pbits) + {GenerateRandom(rng, MakeParameters("ModulusSize", (int)pbits));} + + /// \brief Initialize a group parameters over integers + /// \param p the modulus + /// \param g the generator + void Initialize(const Integer &p, const Integer &g) + {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(ComputeGroupOrder(p)/2);} + + /// \brief Initialize a group parameters over integers + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + void Initialize(const Integer &p, const Integer &q, const Integer &g) + {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(q);} + + // ASN1Object interface + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + // GeneratibleCryptoMaterial interface + /*! parameters: (ModulusSize, SubgroupOrderSize (optional)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // DL_GroupParameters + const Integer & GetSubgroupOrder() const {return m_q;} + Integer GetGroupOrder() const {return GetFieldType() == 1 ? GetModulus()-Integer::One() : GetModulus()+Integer::One();} + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Integer &element, const DL_FixedBasePrecomputation *precomp) const; + bool FastSubgroupCheckAvailable() const {return GetCofactor() == 2;} + + // Cygwin i386 crash at -O3; see http://github.com/weidai11/cryptopp/issues/40. + void EncodeElement(bool reversible, const Element &element, byte *encoded) const; + unsigned int GetEncodedElementSize(bool reversible) const; + + Integer DecodeElement(const byte *encoded, bool checkForGroupMembership) const; + Integer ConvertElementToInteger(const Element &element) const + {return element;} + Integer GetMaxExponent() const; + static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "";} + + OID GetAlgorithmID() const; + + virtual const Integer & GetModulus() const =0; + virtual void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) =0; + + void SetSubgroupOrder(const Integer &q) + {m_q = q; ParametersChanged();} + +protected: + Integer ComputeGroupOrder(const Integer &modulus) const + {return modulus-(GetFieldType() == 1 ? 1 : -1);} + + // GF(p) = 1, GF(p^2) = 2 + virtual int GetFieldType() const =0; + virtual unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const; + +private: + Integer m_q; +}; + +/// \brief Integer-based GroupParameters default implementation +/// \tparam GROUP_PRECOMP group parameters precomputation specialization +/// \tparam BASE_PRECOMP base class precomputation specialization +template > +class CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBasedImpl : public DL_GroupParametersImpl +{ + typedef DL_GroupParameters_IntegerBasedImpl ThisClass; + +public: + typedef typename GROUP_PRECOMP::Element Element; + + virtual ~DL_GroupParameters_IntegerBasedImpl() {} + + // GeneratibleCryptoMaterial interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + {return GetValueHelper(this, name, valueType, pValue).Assignable();} + + void AssignFrom(const NameValuePairs &source) + {AssignFromHelper(this, source);} + + // DL_GroupParameters + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return this->m_gpc;} + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return this->m_gpc;} + + // IntegerGroupParameters + const Integer & GetModulus() const {return this->m_groupPrecomputation.GetModulus();} + const Integer & GetGenerator() const {return this->m_gpc.GetBase(this->GetGroupPrecomputation());} + + void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) // these have to be set together + {this->m_groupPrecomputation.SetModulus(p); this->m_gpc.SetBase(this->GetGroupPrecomputation(), g); this->ParametersChanged();} + + // non-inherited + bool operator==(const DL_GroupParameters_IntegerBasedImpl &rhs) const + {return GetModulus() == rhs.GetModulus() && GetGenerator() == rhs.GetGenerator() && this->GetSubgroupOrder() == rhs.GetSubgroupOrder();} + bool operator!=(const DL_GroupParameters_IntegerBasedImpl &rhs) const + {return !operator==(rhs);} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_IntegerBasedImpl; + +/// \brief GF(p) group parameters +class CRYPTOPP_DLL DL_GroupParameters_GFP : public DL_GroupParameters_IntegerBasedImpl +{ +public: + virtual ~DL_GroupParameters_GFP() {} + + // DL_GroupParameters + bool IsIdentity(const Integer &element) const {return element == Integer::One();} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + // NameValuePairs interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue).Assignable(); + } + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + +protected: + int GetFieldType() const {return 1;} +}; + +/// \brief GF(p) group parameters that default to safe primes +class CRYPTOPP_DLL DL_GroupParameters_GFP_DefaultSafePrime : public DL_GroupParameters_GFP +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + + virtual ~DL_GroupParameters_GFP_DefaultSafePrime() {} + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +/// \brief GDSA algorithm +/// \tparam T FieldElement type or class +template +class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-1363";} + + virtual ~DL_Algorithm_GDSA() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + r %= q; + Integer kInv = k.InverseMod(q); + s = (kInv * (x*r + e)) % q; + CRYPTOPP_ASSERT(!!r && !!s); + } + + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q || s<1) + return false; + + Integer w = s.InverseMod(q); + Integer u1 = (e * w) % q; + Integer u2 = (r * w) % q; + // verify r == (g^u1 * y^u2 mod p) mod q + return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q; + } +}; + +/// \brief DSA signature algorithm based on RFC 6979 +/// \tparam T FieldElement type or class +/// \tparam H HashTransformation derived class +/// \sa RFC 6979, Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +class DL_Algorithm_DSA_RFC6979 : public DL_Algorithm_GDSA, public DeterministicSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-RFC6979";} + + virtual ~DL_Algorithm_DSA_RFC6979() {} + + bool IsProbabilistic() const + {return false;} + bool IsDeterministic() const + {return true;} + + // Deterministic K + Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const + { + static const byte zero = 0, one = 1; + const size_t qlen = q.BitCount(); + const size_t rlen = BitsToBytes(qlen); + + // Step (a) - formatted E(m) + SecByteBlock BH(e.MinEncodedSize()); + e.Encode(BH, BH.size()); + BH = bits2octets(BH, q); + + // Step (a) - private key to byte array + SecByteBlock BX(STDMAX(rlen, x.MinEncodedSize())); + x.Encode(BX, BX.size()); + + // Step (b) + SecByteBlock V(H::DIGESTSIZE); + std::fill(V.begin(), V.begin()+H::DIGESTSIZE, one); + + // Step (c) + SecByteBlock K(H::DIGESTSIZE); + std::fill(K.begin(), K.begin()+H::DIGESTSIZE, zero); + + // Step (d) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.Update(&zero, 1); + m_hmac.Update(BX, BX.size()); + m_hmac.Update(BH, BH.size()); + m_hmac.TruncatedFinal(K, K.size()); + + // Step (e) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + // Step (f) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.Update(&one, 1); + m_hmac.Update(BX, BX.size()); + m_hmac.Update(BH, BH.size()); + m_hmac.TruncatedFinal(K, K.size()); + + // Step (g) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + Integer k; + SecByteBlock temp(rlen); + for (;;) + { + // We want qlen bits, but we support only hash functions with an output length + // multiple of 8; hence, we will gather rlen bits, i.e., rolen octets. + size_t toff = 0; + while (toff < rlen) + { + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + size_t cc = STDMIN(V.size(), temp.size() - toff); + memcpy_s(temp+toff, temp.size() - toff, V, cc); + toff += cc; + } + + k = bits2int(temp, qlen); + if (k > 0 && k < q) + break; + + // k is not in the proper range; update K and V, and loop. + m_hmac.Update(V, V.size()); + m_hmac.Update(&zero, 1); + m_hmac.TruncatedFinal(K, K.size()); + + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + } + + return k; + } + +protected: + + Integer bits2int(const SecByteBlock& bits, size_t qlen) const + { + Integer ret(bits, bits.size()); + size_t blen = bits.size()*8; + + if (blen > qlen) + ret >>= blen - qlen; + + return ret; + } + + // RFC 6979 support function. Takes an integer and converts it into bytes that + // are the same length as an elliptic curve's order. + SecByteBlock int2octets(const Integer& val, size_t rlen) const + { + SecByteBlock block(val.MinEncodedSize()); + val.Encode(block, val.MinEncodedSize()); + + if (block.size() == rlen) + return block; + + // The least significant bytes are the ones we need to preserve. + SecByteBlock t(rlen); + if (block.size() > rlen) + { + size_t offset = block.size() - rlen; + std::memcpy(t, block + offset, rlen); + } + else // block.size() < rlen + { + size_t offset = rlen - block.size(); + memset(t, '\x00', offset); + std::memcpy(t + offset, block, rlen - offset); + } + + return t; + } + + // Turn a stream of bits into a set of bytes with the same length as an elliptic + // curve's order. + SecByteBlock bits2octets(const SecByteBlock& in, const Integer& q) const + { + Integer b2 = bits2int(in, q.BitCount()); + Integer b1 = b2 - q; + return int2octets(b1.IsNegative() ? b2 : b1, q.ByteCount()); + } + +private: + mutable H m_hash; + mutable HMAC m_hmac; +}; + +/// \brief German Digital Signature Algorithm +/// \tparam T FieldElement type or class +/// \details The Digital Signature Scheme ECGDSA does not define the algorithm over integers. Rather, the +/// signature algorithm is only defined over elliptic curves. However, The library design is such that the +/// generic algorithm reside in gfpcrypt.h. +/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf +/// The Digital Signature Scheme ECGDSA (October 24, 2006) +template +class DL_Algorithm_GDSA_ISO15946 : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "GDSA-ISO15946";} + + virtual ~DL_Algorithm_GDSA_ISO15946() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + // r = x(k * G) mod q + r = params.ConvertElementToInteger(params.ExponentiateBase(k)) % q; + // s = (k * r - h(m)) * d_A mod q + s = (k * r - e) * x % q; + CRYPTOPP_ASSERT(!!r && !!s); + } + + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q || s<1) + return false; + + const Integer& rInv = r.InverseMod(q); + const Integer u1 = (rInv * e) % q; + const Integer u2 = (rInv * s) % q; + // verify x(G^u1 + P_A^u2) mod q + return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q; + } +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; + +/// \brief NR algorithm +/// \tparam T FieldElement type or class +template +class DL_Algorithm_NR : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "NR";} + + virtual ~DL_Algorithm_NR() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + r = (r + e) % q; + s = (k - x*r) % q; + CRYPTOPP_ASSERT(!!r); + } + + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q) + return false; + + // check r == (m_g^s * m_y^r + m) mod m_q + return r == (params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(s, r)) + e) % q; + } +}; + +/// \brief Discrete Log (DL) public key in GF(p) groups +/// \tparam GP GroupParameters derived class +/// \details DSA public key format is defined in 7.3.3 of RFC 2459. The private key format is defined in 12.9 of PKCS #11 v2.10. +template +class DL_PublicKey_GFP : public DL_PublicKeyImpl +{ +public: + virtual ~DL_PublicKey_GFP() {} + + /// \brief Initialize a public key over GF(p) + /// \param params the group parameters + /// \param y the public element + void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &y) + {this->AccessGroupParameters().Initialize(params); this->SetPublicElement(y);} + + /// \brief Initialize a public key over GF(p) + /// \param p the modulus + /// \param g the generator + /// \param y the public element + void Initialize(const Integer &p, const Integer &g, const Integer &y) + {this->AccessGroupParameters().Initialize(p, g); this->SetPublicElement(y);} + + /// \brief Initialize a public key over GF(p) + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + /// \param y the public element + void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &y) + {this->AccessGroupParameters().Initialize(p, q, g); this->SetPublicElement(y);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool, size_t) + {this->SetPublicElement(Integer(bt));} + void DEREncodePublicKey(BufferedTransformation &bt) const + {this->GetPublicElement().DEREncode(bt);} +}; + +/// \brief Discrete Log (DL) private key in GF(p) groups +/// \tparam GP GroupParameters derived class +template +class DL_PrivateKey_GFP : public DL_PrivateKeyImpl +{ +public: + virtual ~DL_PrivateKey_GFP(); + + /// \brief Create a private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {this->GenerateRandomWithKeySize(rng, modulusBits);} + + /// \brief Create a private key + /// \param rng a RandomNumberGenerator derived class + /// \param p the modulus + /// \param g the generator + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &g) + {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupGenerator", g));} + + /// \brief Create a private key + /// \param rng a RandomNumberGenerator derived class + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &q, const Integer &g) + {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupOrder", q)("SubgroupGenerator", g));} + + /// \brief Initialize a private key over GF(p) + /// \param params the group parameters + /// \param x the private exponent + void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &x) + {this->AccessGroupParameters().Initialize(params); this->SetPrivateExponent(x);} + + /// \brief Initialize a private key over GF(p) + /// \param p the modulus + /// \param g the generator + /// \param x the private exponent + void Initialize(const Integer &p, const Integer &g, const Integer &x) + {this->AccessGroupParameters().Initialize(p, g); this->SetPrivateExponent(x);} + + /// \brief Initialize a private key over GF(p) + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + /// \param x the private exponent + void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &x) + {this->AccessGroupParameters().Initialize(p, q, g); this->SetPrivateExponent(x);} +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey_GFP::~DL_PrivateKey_GFP() {} + +/// \brief Discrete Log (DL) signing/verification keys in GF(p) groups +struct DL_SignatureKeys_GFP +{ + typedef DL_GroupParameters_GFP GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief Discrete Log (DL) encryption/decryption keys in GF(p) groups +struct DL_CryptoKeys_GFP +{ + typedef DL_GroupParameters_GFP_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief DSA signature scheme +/// \tparam H HashTransformation derived class +/// \sa DSA-1363 +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2 +template +struct GDSA : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_GDSA, + DL_SignatureMessageEncodingMethod_DSA, + H> +{ +}; + +/// \brief NR signature scheme +/// \tparam H HashTransformation derived class +/// \sa NR +template +struct NR : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_NR, + DL_SignatureMessageEncodingMethod_NR, + H> +{ +}; + +/// \brief DSA group parameters +/// \details These are GF(p) group parameters that are allowed by the DSA standard +/// \sa DL_Keys_DSA +class CRYPTOPP_DLL DL_GroupParameters_DSA : public DL_GroupParameters_GFP +{ +public: + virtual ~DL_GroupParameters_DSA() {} + + /*! also checks that the lengths of p and q are allowed by the DSA standard */ + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + /*! parameters: (ModulusSize), or (Modulus, SubgroupOrder, SubgroupGenerator) */ + /*! ModulusSize must be between DSA::MIN_PRIME_LENGTH and DSA::MAX_PRIME_LENGTH, and divisible by DSA::PRIME_LENGTH_MULTIPLE */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + static bool CRYPTOPP_API IsValidPrimeLength(unsigned int pbits) + {return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;} + + enum {MIN_PRIME_LENGTH = 1024, MAX_PRIME_LENGTH = 3072, PRIME_LENGTH_MULTIPLE = 1024}; +}; + +template +class DSA2; + +/// \brief DSA keys +/// \sa DL_GroupParameters_DSA +struct DL_Keys_DSA +{ + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest, DSA2 > PrivateKey; +}; + +/// \brief DSA signature scheme +/// \tparam H HashTransformation derived class +/// \details The class is named DSA2 instead of DSA for backwards compatibility because +/// DSA was a non-template class. +/// \details DSA default method GenerateRandom uses a 2048-bit modulus and a 224-bit subgoup by default. +/// The modulus can be changed using the following code: +///
+///   DSA::PrivateKey privateKey;
+///   privateKey.GenerateRandomWithKeySize(prng, 2048);
+/// 
+/// \details The subgroup order can be changed using the following code: +///
+///   AlgorithmParameters params = MakeParameters
+///     (Name::ModulusSize(), 2048)
+///     (Name::SubgroupOrderSize(), 256);
+///
+///   DSA::PrivateKey privateKey;
+///   privateKey.GenerateRandom(prng, params);
+/// 
+/// \sa DSA, as specified in FIPS 186-3, +/// Digital Signature Algorithm on the wiki, and +/// NameValuePairs on the wiki. +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2, Crypto++ 6.1 for 2048-bit modulus. +template +class DSA2 : public DL_SS< + DL_Keys_DSA, + DL_Algorithm_GDSA, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA2 > +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();} +}; + +/// \brief DSA deterministic signature scheme +/// \tparam H HashTransformation derived class +/// \sa DSA-1363 +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2 +template +struct DSA_RFC6979 : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_DSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("DSA-RFC6979/") + H::StaticAlgorithmName();} +}; + +/// DSA with SHA-1, typedef'd for backwards compatibility +typedef DSA2 DSA; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_GFP; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_GFP; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, DSA2 >; + +/// \brief P1363 based XOR Encryption Method +/// \tparam MAC MessageAuthenticationCode derived class used for MAC computation +/// \tparam DHAES_MODE flag indicating DHAES mode +/// \tparam LABEL_OCTETS flag indicating the label is octet count +/// \details DL_EncryptionAlgorithm_Xor is based on an early P1363 draft, which itself appears to be based on an +/// early Certicom SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used it in its Integrated +/// Ecryption Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you need this method for Crypto++ 4.2 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you need this method for Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=ture and LABEL_OCTETS=false. +/// \details Bouncy Castle 1.54 and Botan 1.11 compatibility are the default template parameters. +/// \since Crypto++ 4.0 +template +class DL_EncryptionAlgorithm_Xor : public DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~DL_EncryptionAlgorithm_Xor() {} + + bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;} + size_t GetSymmetricKeyLength(size_t plaintextLength) const + {return plaintextLength + static_cast(MAC::DIGESTSIZE);} + size_t GetSymmetricCiphertextLength(size_t plaintextLength) const + {return plaintextLength + static_cast(MAC::DIGESTSIZE);} + size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const + {return SaturatingSubtract(ciphertextLength, static_cast(MAC::DIGESTSIZE));} + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(rng); + const byte *cipherKey = NULLPTR, *macKey = NULLPTR; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plaintextLength; + } + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + if (plaintextLength) // Coverity finding + xorbuf(ciphertext, plaintext, cipherKey, plaintextLength); + + MAC mac(macKey); + mac.Update(ciphertext, plaintextLength); + mac.Update(encodingParameters.begin(), encodingParameters.size()); + if (DHAES_MODE) + { + byte L[8]; + PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size()))); + mac.Update(L, 8); + } + mac.Final(ciphertext + plaintextLength); + } + DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const + { + size_t plaintextLength = GetMaxSymmetricPlaintextLength(ciphertextLength); + const byte *cipherKey, *macKey; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plaintextLength; + } + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + MAC mac(macKey); + mac.Update(ciphertext, plaintextLength); + mac.Update(encodingParameters.begin(), encodingParameters.size()); + if (DHAES_MODE) + { + byte L[8]; + PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size()))); + mac.Update(L, 8); + } + if (!mac.Verify(ciphertext + plaintextLength)) + return DecodingResult(); + + if (plaintextLength) // Coverity finding + xorbuf(plaintext, ciphertext, cipherKey, plaintextLength); + + return DecodingResult(plaintextLength); + } +}; + +/// _ +template +class DL_KeyDerivationAlgorithm_P1363 : public DL_KeyDerivationAlgorithm +{ +public: + virtual ~DL_KeyDerivationAlgorithm_P1363() {} + + bool ParameterSupported(const char *name) const {return strcmp(name, Name::KeyDerivationParameters()) == 0;} + void Derive(const DL_GroupParameters ¶ms, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs ¶meters) const + { + SecByteBlock agreedSecret; + if (DHAES_MODE) + { + agreedSecret.New(params.GetEncodedElementSize(true) + params.GetEncodedElementSize(false)); + params.EncodeElement(true, ephemeralPublicKey, agreedSecret); + params.EncodeElement(false, agreedElement, agreedSecret + params.GetEncodedElementSize(true)); + } + else + { + agreedSecret.New(params.GetEncodedElementSize(false)); + params.EncodeElement(false, agreedElement, agreedSecret); + } + + ConstByteArrayParameter derivationParameters; + parameters.GetValue(Name::KeyDerivationParameters(), derivationParameters); + KDF::DeriveKey(derivedKey, derivedLength, agreedSecret, agreedSecret.size(), derivationParameters.begin(), derivationParameters.size()); + } +}; + +/// \brief Discrete Log Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes addition context parameters such as the label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \details DLIES is an Integer based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation Method (KEM) +/// with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom +/// SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Ecryption +/// Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the DLIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the DLIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. SHA-256 or another hash will likely improve the +/// security provided by the MAC. The hash is also used in the key derivation function as a PRF. +/// \details Below is an example of constructing a Crypto++ 4.2 compatible DLIES encryptor and decryptor. +///
+///     AutoSeededRandomPool prng;
+///     DL_PrivateKey_GFP key;
+///     key.Initialize(prng, 2048);
+///
+///     DLIES::Decryptor decryptor(key);
+///     DLIES::Encryptor encryptor(decryptor);
+/// 
+/// \sa ECIES, Discrete Log Integrated Encryption Scheme (DLIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct DLIES + : public DL_ES< + DL_CryptoKeys_GFP, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + DLIES<> > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return "DLIES";} // TODO: fix this after name is standardized +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/gost.h b/include/cryptlib/gost.h new file mode 100644 index 0000000..87082a1 --- /dev/null +++ b/include/cryptlib/gost.h @@ -0,0 +1,66 @@ +// gost.h - originally written and placed in the public domain by Wei Dai + +/// \file gost.h +/// \brief Classes for the GIST block cipher + +#ifndef CRYPTOPP_GOST_H +#define CRYPTOPP_GOST_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GOST block cipher information +/// \since Crypto++ 2.1 +struct GOST_Info : public FixedBlockSize<8>, public FixedKeyLength<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "GOST";} +}; + +/// \brief GOST block cipher +/// \sa GOST +/// \since Crypto++ 2.1 +class GOST : public GOST_Info, public BlockCipherDocumentation +{ + /// \brief GOST block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static void PrecalculateSTable(); + + static const byte sBox[8][16]; + static volatile bool sTableCalculated; + static word32 sTable[4][256]; + + FixedSizeSecBlock m_key; + }; + + /// \brief GOST block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief GOST block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef GOST::Encryption GOSTEncryption; +typedef GOST::Decryption GOSTDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/gzip.h b/include/cryptlib/gzip.h new file mode 100644 index 0000000..437a520 --- /dev/null +++ b/include/cryptlib/gzip.h @@ -0,0 +1,144 @@ +// gzip.h - originally written and placed in the public domain by Wei Dai + +/// \file gzip.h +/// \brief GZIP compression and decompression (RFC 1952) + +#ifndef CRYPTOPP_GZIP_H +#define CRYPTOPP_GZIP_H + +#include "cryptlib.h" +#include "zdeflate.h" +#include "zinflate.h" +#include "crc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GZIP Compression (RFC 1952) +class Gzip : public Deflator +{ +public: + /// \brief Construct a Gzip compressor + /// \param attachment an attached transformation + /// \param deflateLevel the deflate level + /// \param log2WindowSize the window size + /// \param detectUncompressible flag to detect if data is compressible + /// \details detectUncompressible makes it faster to process uncompressible files, but + /// if a file has both compressible and uncompressible parts, it may fail to compress + /// some of the compressible parts. + Gzip(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible), m_totalLen(0), m_filetime(0) { } + + /// \brief Construct a Gzip compressor + /// \param parameters a set of NameValuePairs to initialize this object + /// \param attachment an attached transformation + /// \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible + Gzip(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) + : Deflator(parameters, attachment), m_totalLen(0), m_filetime(0) + { + IsolatedInitialize(parameters); + } + + /// \param filetime the filetime to set in the header. The application is responsible for setting it. + void SetFiletime(word32 filetime) { m_filetime = filetime; } + + /// \param filename the original filename to set in the header. The application is responsible for setting it. + /// RFC 1952 requires a ISO/IEC 8859-1 encoding. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the filename is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the filename does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat + /// is thrown. If throwOnEncodingError is false then the filename is not checked. + void SetFilename(const std::string& filename, bool throwOnEncodingError = false); + + /// \param comment the comment to set in the header. The application is responsible for setting it. + /// RFC 1952 requires a ISO/IEC 8859-1 encoding. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the comment is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the comment does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat + /// is thrown. If throwOnEncodingError is false then the comment is not checked. + void SetComment(const std::string& comment, bool throwOnEncodingError = false); + + void IsolatedInitialize(const NameValuePairs ¶meters); + +protected: + enum {MAGIC1=0x1f, MAGIC2=0x8b, // flags for the header + DEFLATED=8, FAST=4, SLOW=2}; + + enum FLAG_MASKS { + FILENAME=8, COMMENTS=16}; + + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, size_t length); + void WritePoststreamTail(); + + word32 m_totalLen; + CRC32 m_crc; + + word32 m_filetime; + std::string m_filename; + std::string m_comment; +}; + +/// \brief GZIP Decompression (RFC 1952) +class Gunzip : public Inflator +{ +public: + typedef Inflator::Err Err; + + /// \brief Exception thrown when a header decoding error occurs + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "Gunzip: header decoding error") {}}; + /// \brief Exception thrown when the tail is too short + class TailErr : public Err {public: TailErr() : Err(INVALID_DATA_FORMAT, "Gunzip: tail too short") {}}; + /// \brief Exception thrown when a CRC error occurs + class CrcErr : public Err {public: CrcErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: CRC check error") {}}; + /// \brief Exception thrown when a length error occurs + class LengthErr : public Err {public: LengthErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: length check error") {}}; + + /// \brief Construct a Gunzip decompressor + /// \param attachment an attached transformation + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + Gunzip(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + + /// \return the filetime of the stream as set in the header. The application is responsible for setting it on the decompressed file. + word32 GetFiletime() const { return m_filetime; } + + /// \return the filename of the stream as set in the header. The application is responsible for setting it on the decompressed file. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the filename is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the filename does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat is thrown. + /// If throwOnEncodingError is false then the filename is not checked. + const std::string& GetFilename(bool throwOnEncodingError = false) const; + + /// \return the comment of the stream as set in the header. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the comment is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the comment does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat is thrown. + /// If throwOnEncodingError is false then the comment is not checked. + const std::string& GetComment(bool throwOnEncodingError = false) const; + +protected: + enum { + /// \brief First header magic value + MAGIC1=0x1f, + /// \brief Second header magic value + MAGIC2=0x8b, + /// \brief Deflated flag + DEFLATED=8 + }; + + enum FLAG_MASKS { + CONTINUED=2, EXTRA_FIELDS=4, FILENAME=8, COMMENTS=16, ENCRYPTED=32}; + + unsigned int MaxPrestreamHeaderSize() const {return 1024;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, size_t length); + unsigned int MaxPoststreamTailSize() const {return 8;} + void ProcessPoststreamTail(); + + word32 m_length; + CRC32 m_crc; + + word32 m_filetime; + std::string m_filename; + std::string m_comment; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/hashfwd.h b/include/cryptlib/hashfwd.h new file mode 100644 index 0000000..0dbbc09 --- /dev/null +++ b/include/cryptlib/hashfwd.h @@ -0,0 +1,35 @@ +// hashfwd.h - written and placed in the public domain by Jeffrey Walton + +/// \file hashfwd.h +/// \brief Forward declarations for hash functions used in signature encoding methods + +#ifndef CRYPTOPP_HASHFWD_H +#define CRYPTOPP_HASHFWD_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +class SHA1; +class SHA224; +class SHA256; +class SHA384; +class SHA512; + +class SHA3_256; +class SHA3_384; +class SHA3_512; + +class Tiger; +class RIPEMD128; +class RIPEMD160; +class Whirlpool; + +namespace Weak1 { + class MD2; + class MD5; +} + +NAMESPACE_END + +#endif // CRYPTOPP_HASHFWD_H diff --git a/include/cryptlib/hex.h b/include/cryptlib/hex.h new file mode 100644 index 0000000..bcf2bd0 --- /dev/null +++ b/include/cryptlib/hex.h @@ -0,0 +1,50 @@ +// hex.h - originally written and placed in the public domain by Wei Dai + +/// \file hex.h +/// \brief Classes for HexEncoder and HexDecoder + +#ifndef CRYPTOPP_HEX_H +#define CRYPTOPP_HEX_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Converts given data to base 16 +class CRYPTOPP_DLL HexEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a HexEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the output grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator append after processing + HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Decode base 16 data back to bytes +class CRYPTOPP_DLL HexDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a HexDecoder + /// \param attachment a BufferedTrasformation to attach to this object + HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 4, attachment) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/hkdf.h b/include/cryptlib/hkdf.h new file mode 100644 index 0000000..36a4382 --- /dev/null +++ b/include/cryptlib/hkdf.h @@ -0,0 +1,178 @@ +// hkdf.h - written and placed in public domain by Jeffrey Walton. + +/// \file hkdf.h +/// \brief Classes for HKDF from RFC 5869 +/// \since Crypto++ 5.6.3 + +#ifndef CRYPTOPP_HKDF_H +#define CRYPTOPP_HKDF_H + +#include "cryptlib.h" +#include "secblock.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Extract-and-Expand Key Derivation Function (HKDF) +/// \tparam T HashTransformation class +/// \sa Cryptographic Extraction and Key +/// Derivation: The HKDF Scheme and +/// HMAC-based Extract-and-Expand Key +/// Derivation Function (HKDF) +/// \since Crypto++ 5.6.3 +template +class HKDF : public KeyDerivationFunction +{ +public: + virtual ~HKDF() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("HKDF(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedLength() const { + return static_cast(T::DIGESTSIZE) * 255; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params) const; + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param info the additional input buffer + /// \param infoLen the size of the info buffer, in bytes + /// \returns the number of iterations performed + /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details salt and info can be nullptr with 0 length. + /// HKDF is unusual in that a non-NULL salt with length 0 is different than a + /// NULL salt. A NULL salt causes HKDF to use a string of 0's + /// of length T::DIGESTSIZE for the salt. + /// \details HKDF always returns 1 because it only performs 1 iteration. Other + /// derivation functions, like PBKDF's, will return more interesting values. + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } + + // If salt is absent (NULL), then use the NULL vector. Missing is different than + // EMPTY (Non-NULL, 0 length). The length of s_NullVector used depends on the Hash + // function. SHA-256 will use 32 bytes of s_NullVector. + typedef byte NullVectorType[T::DIGESTSIZE]; + static const NullVectorType& GetNullVector() { + static const NullVectorType s_NullVector = {0}; + return s_NullVector; + } +}; + +template +size_t HKDF::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedLength()) + return MaxDerivedLength(); + return keylength; +} + +template +size_t HKDF::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret && secretLen); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + + ConstByteArrayParameter p; + SecByteBlock salt, info; + + if (params.GetValue("Salt", p)) + salt.Assign(p.begin(), p.size()); + else + salt.Assign(GetNullVector(), T::DIGESTSIZE); + + if (params.GetValue("Info", p)) + info.Assign(p.begin(), p.size()); + else + info.Assign(GetNullVector(), 0); + + return DeriveKey(derived, derivedLen, secret, secretLen, salt.begin(), salt.size(), info.begin(), info.size()); +} + +template +size_t HKDF::DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const +{ + CRYPTOPP_ASSERT(secret && secretLen); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + + ThrowIfInvalidDerivedLength(derivedLen); + + // HKDF business logic. NULL is different than empty. + if (salt == NULLPTR) + { + salt = GetNullVector(); + saltLen = T::DIGESTSIZE; + } + + // key is PRK from the RFC, salt is IKM from the RFC + HMAC hmac; + SecByteBlock key(T::DIGESTSIZE), buffer(T::DIGESTSIZE); + + // Extract + hmac.SetKey(salt, saltLen); + hmac.CalculateDigest(key, secret, secretLen); + + // Key + hmac.SetKey(key.begin(), key.size()); + byte block = 0; + + // Expand + while (derivedLen > 0) + { + if (block++) {hmac.Update(buffer, buffer.size());} + if (infoLen) {hmac.Update(info, infoLen);} + hmac.CalculateDigest(buffer, &block, 1); + +#if CRYPTOPP_MSC_VERSION + const size_t digestSize = static_cast(T::DIGESTSIZE); + const size_t segmentLen = STDMIN(derivedLen, digestSize); + memcpy_s(derived, segmentLen, buffer, segmentLen); +#else + const size_t digestSize = static_cast(T::DIGESTSIZE); + const size_t segmentLen = STDMIN(derivedLen, digestSize); + std::memcpy(derived, buffer, segmentLen); +#endif + + derived += segmentLen; + derivedLen -= segmentLen; + } + + return 1; +} + +NAMESPACE_END + +#endif // CRYPTOPP_HKDF_H diff --git a/include/cryptlib/hmac.h b/include/cryptlib/hmac.h new file mode 100644 index 0000000..971de3a --- /dev/null +++ b/include/cryptlib/hmac.h @@ -0,0 +1,75 @@ +// hmac.h - originally written and placed in the public domain by Wei Dai + +/// \file hmac.h +/// \brief Classes for HMAC message authentication codes + +#ifndef CRYPTOPP_HMAC_H +#define CRYPTOPP_HMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HMAC information +/// \details HMAC_Base derives from VariableKeyLength and MessageAuthenticationCode +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HMAC_Base : public VariableKeyLength<16, 0, INT_MAX>, public MessageAuthenticationCode +{ +public: + /// \brief Construct a HMAC_Base + HMAC_Base() : m_innerHashKeyed(false) {} + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + + void Restart(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int OptimalBlockSize() const {return const_cast(this)->AccessHash().OptimalBlockSize();} + unsigned int DigestSize() const {return const_cast(this)->AccessHash().DigestSize();} + +protected: + virtual HashTransformation & AccessHash() =0; + byte * AccessIpad() {return m_buf;} + byte * AccessOpad() {return m_buf + AccessHash().BlockSize();} + byte * AccessInnerHash() {return m_buf + 2*AccessHash().BlockSize();} + +private: + void KeyInnerHash(); + + SecByteBlock m_buf; + bool m_innerHashKeyed; +}; + +/// \brief HMAC +/// \tparam T HashTransformation derived class +/// \details HMAC derives from MessageAuthenticationCodeImpl. It calculates the HMAC using +/// HMAC(K, text) = H(K XOR opad, H(K XOR ipad, text)). +/// \sa HMAC +/// \since Crypto++ 2.1 +template +class HMAC : public MessageAuthenticationCodeImpl > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE=T::DIGESTSIZE) + CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE) + + /// \brief Construct a HMAC + HMAC() {} + /// \brief Construct a HMAC + /// \param key the HMAC key + /// \param length the size of the HMAC key + HMAC(const byte *key, size_t length=HMAC_Base::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("HMAC(") + T::StaticAlgorithmName() + ")";} + std::string AlgorithmName() const {return std::string("HMAC(") + m_hash.AlgorithmName() + ")";} + +private: + HashTransformation & AccessHash() {return m_hash;} + + T m_hash; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/hmqv.h b/include/cryptlib/hmqv.h new file mode 100644 index 0000000..9772147 --- /dev/null +++ b/include/cryptlib/hmqv.h @@ -0,0 +1,310 @@ +// hmqv.h - written and placed in the public domain by Uri Blumenthal +// Shamelessly based upon Jeffrey Walton's FHMQV and Wei Dai's MQV source files + +#ifndef CRYPTOPP_HMQV_H +#define CRYPTOPP_HMQV_H + +/// \file hmqv.h +/// \brief Classes for Hashed Menezes-Qu-Vanstone key agreement in GF(p) +/// \since Crypto++ 5.6.4 + +#include "gfpcrypt.h" +#include "algebra.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +template +class HMQV_Domain: public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef HMQV_Domain Domain; + + virtual ~HMQV_Domain() {} + + HMQV_Domain(bool clientRole = true): m_role(clientRole ? RoleClient : RoleServer) {} + + HMQV_Domain(const GroupParameters ¶ms, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {} + + HMQV_Domain(BufferedTransformation &bt, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.BERDecode(bt);} + + template + HMQV_Domain(T1 v1, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1);} + + template + HMQV_Domain(T1 v1, T2 v2, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2);} + + template + HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3);} + + template + HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + +public: + + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + GroupParameters & AccessGroupParameters(){return m_groupParameters;} + + CryptoParameters & AccessCryptoParameters(){return AccessAbstractGroupParameters();} + + /// return length of agreed value produced + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + /// return length of static private keys in this domain + unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + /// return length of static public keys in this domain + unsigned int StaticPublicKeyLength() const{return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// generate static private key + /*! \pre size of privateKey == PrivateStaticKeyLength() */ + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// generate static public key + /*! \pre size of publicKey == PublicStaticKeyLength() */ + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();} + + /// return length of ephemeral private keys in this domain + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// return length of ephemeral public keys in this domain + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// derive agreed value from your private keys and couterparty's public keys, return false in case of failure + /*! \note The ephemeral public key will always be validated. + If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time. + \pre size of agreedValue == AgreedValueLength() + \pre length of staticPrivateKey == StaticPrivateKeyLength() + \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength() + \pre length of staticOtherPublicKey == StaticPublicKeyLength() + \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength() + */ + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR; + size_t xxs = 0, yys = 0, aas = 0, bbs = 0; + + // Depending on the role, this will hold either A's or B's static + // (long term) public key. AA or BB will then point into tt. + SecByteBlock tt(StaticPublicKeyLength()); + + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + if(m_role == RoleServer) + { + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Element B = params.ExponentiateBase(b); + params.EncodeElement(true, B, tt); + + XX = const_cast(ephemeralOtherPublicKey); + xxs = EphemeralPublicKeyLength(); + YY = const_cast(ephemeralPrivateKey) + StaticPrivateKeyLength(); + yys = EphemeralPublicKeyLength(); + AA = const_cast(staticOtherPublicKey); + aas = StaticPublicKeyLength(); + BB = tt.BytePtr(); + bbs = tt.SizeInBytes(); + } + else if(m_role == RoleClient) + { + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Element A = params.ExponentiateBase(a); + params.EncodeElement(true, A, tt); + + XX = const_cast(ephemeralPrivateKey) + StaticPrivateKeyLength(); + xxs = EphemeralPublicKeyLength(); + YY = const_cast(ephemeralOtherPublicKey); + yys = EphemeralPublicKeyLength(); + AA = tt.BytePtr(); + aas = tt.SizeInBytes(); + BB = const_cast(staticOtherPublicKey); + bbs = StaticPublicKeyLength(); + } + else + { + CRYPTOPP_ASSERT(0); + return false; + } + + // DecodeElement calls ValidateElement at level 1. Level 1 only calls + // VerifyPoint to ensure the element is in G*. If the other's PublicKey is + // requested to be validated, we manually call ValidateElement at level 3. + Element VV1 = params.DecodeElement(staticOtherPublicKey, false); + if(!params.ValidateElement(validateStaticOtherPublicKey ? 3 : 1, VV1, NULLPTR)) + return false; + + // DecodeElement calls ValidateElement at level 1. Level 1 only calls + // VerifyPoint to ensure the element is in G*. Crank it up. + Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, false); + if(!params.ValidateElement(3, VV2, NULLPTR)) + return false; + + // const Integer& p = params.GetGroupOrder(); // not used, remove later + const Integer& q = params.GetSubgroupOrder(); + const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8); + + Integer d, e; + SecByteBlock dd(len), ee(len); + + // Compute $d = \hat{H}(X, \hat{B})$ + Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes()); + d.Decode(dd.BytePtr(), dd.SizeInBytes()); + + // Compute $e = \hat{H}(Y, \hat{A})$ + Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes()); + e.Decode(ee.BytePtr(), ee.SizeInBytes()); + + Element sigma; + if(m_role == RoleServer) + { + Integer y(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_B = (y + e * b) % q; + + Element A = params.DecodeElement(AA, false); + Element X = params.DecodeElement(XX, false); + + Element t1 = params.ExponentiateElement(A, d); + Element t2 = m_groupParameters.MultiplyElements(X, t1); + + // $\sigma_B}=(X \cdot A^{d})^{s_B} + sigma = params.ExponentiateElement(t2, s_B); + } + else + { + Integer x(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_A = (x + d * a) % q; + + Element B = params.DecodeElement(BB, false); + Element Y = params.DecodeElement(YY, false); + + Element t1 = params.ExponentiateElement(B, e); + Element t2 = m_groupParameters.MultiplyElements(Y, t1); + + // $\sigma_A}=(Y \cdot B^{e})^{s_A} + sigma = params.ExponentiateElement(t2, s_A); + } + Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength()); + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + +protected: + // Hash invocation by client and server differ only in what keys + // each provides. + + inline void Hash(const Element* sigma, + const byte* e1, size_t e1len, // Ephemeral key and key length + const byte* s1, size_t s1len, // Static key and key length + byte* digest, size_t dlen) const + { + HASH hash; + size_t idx = 0, req = dlen; + size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE); + + if(sigma) + { + if (e1len != 0 || s1len != 0) { + CRYPTOPP_ASSERT(0); + } + Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma); + SecByteBlock sbb(x.MinEncodedSize()); + x.Encode(sbb.BytePtr(), sbb.SizeInBytes()); + hash.Update(sbb.BytePtr(), sbb.SizeInBytes()); + } else { + if (e1len == 0 || s1len == 0) { + CRYPTOPP_ASSERT(0); + } + hash.Update(e1, e1len); + hash.Update(s1, s1len); + } + + hash.TruncatedFinal(digest, blk); + req -= blk; + + // All this to catch tail bytes for large curves and small hashes + while(req != 0) + { + hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE); + + idx += (size_t)HASH::DIGESTSIZE; + blk = STDMIN(req, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(&digest[idx], blk); + + req -= blk; + } + } + +private: + + // The paper uses Initiator and Recipient - make it classical. + enum KeyAgreementRole{ RoleServer = 1, RoleClient }; + + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const{return m_groupParameters;} + + GroupParameters m_groupParameters; + KeyAgreementRole m_role; +}; + +/// \brief Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa HMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +typedef HMQV_Domain HMQV; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/hrtimer.h b/include/cryptlib/hrtimer.h new file mode 100644 index 0000000..fdb24f8 --- /dev/null +++ b/include/cryptlib/hrtimer.h @@ -0,0 +1,65 @@ +#ifndef CRYPTOPP_HRTIMER_H +#define CRYPTOPP_HRTIMER_H + +#include "config.h" + +#if !defined(HIGHRES_TIMER_AVAILABLE) || (defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)) +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef HIGHRES_TIMER_AVAILABLE + typedef word64 TimerWord; +#else + typedef clock_t TimerWord; +#endif + +/// \brief Base class for timers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TimerBase +{ +public: + enum Unit {SECONDS = 0, MILLISECONDS, MICROSECONDS, NANOSECONDS}; + TimerBase(Unit unit, bool stuckAtZero) + : m_timerUnit(unit), m_stuckAtZero(stuckAtZero), m_started(false) + , m_start(0), m_last(0) {} + + virtual TimerWord GetCurrentTimerValue() =0; // GetCurrentTime is a macro in MSVC 6.0 + virtual TimerWord TicksPerSecond() =0; // this is not the resolution, just a conversion factor into seconds + + void StartTimer(); + double ElapsedTimeAsDouble(); + unsigned long ElapsedTime(); + +private: + double ConvertTo(TimerWord t, Unit unit); + + Unit m_timerUnit; // HPUX workaround: m_unit is a system macro on HPUX + bool m_stuckAtZero, m_started; + TimerWord m_start, m_last; +}; + +/// \brief Measure CPU time spent executing instructions of this thread (if supported by OS) +/// \note ThreadUserTimer only works correctly on Windows NT or later desktops and servers. +/// On Unix-based it reports process time. On Windows Phone and Windows Store it reports wall +/// clock time with performance counter precision. On all others it reports wall clock time. +class ThreadUserTimer : public TimerBase +{ +public: + ThreadUserTimer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} + TimerWord GetCurrentTimerValue(); + TimerWord TicksPerSecond(); +}; + +/// high resolution timer +class CRYPTOPP_DLL Timer : public TimerBase +{ +public: + Timer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} + TimerWord GetCurrentTimerValue(); + TimerWord TicksPerSecond(); +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/ida.h b/include/cryptlib/ida.h new file mode 100644 index 0000000..000a0ce --- /dev/null +++ b/include/cryptlib/ida.h @@ -0,0 +1,180 @@ +// ida.h - originally written and placed in the public domain by Wei Dai + +/// \file ida.h +/// \brief Classes for Rabin's Information Dispersal and Shamir's Secret Sharing algorithms + +#ifndef CRYPTOPP_IDA_H +#define CRYPTOPP_IDA_H + +#include "cryptlib.h" +#include "mqueue.h" +#include "filters.h" +#include "channels.h" +#include "secblock.h" +#include "stdcpp.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Secret sharing and information dispersal base class +/// \since Crypto++ 1.0 +class RawIDA : public AutoSignaling > > +{ +public: + RawIDA(BufferedTransformation *attachment=NULLPTR) + : m_threshold (0), m_channelsReady(0), m_channelsFinished(0) + {Detach(attachment);} + + unsigned int GetThreshold() const {return m_threshold;} + void AddOutputChannel(word32 channelId); + void ChannelData(word32 channelId, const byte *inString, size_t length, bool messageEnd); + lword InputBuffered(word32 channelId) const; + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("RawIDA"); + ChannelData(StringToWord(channel), begin, length, messageEnd != 0); + return 0; + } + +protected: + virtual void FlushOutputQueues(); + virtual void OutputMessageEnds(); + + unsigned int InsertInputChannel(word32 channelId); + unsigned int LookupInputChannel(word32 channelId) const; + void ComputeV(unsigned int); + void PrepareInterpolation(); + void ProcessInputQueues(); + + typedef std::map InputChannelMap; + InputChannelMap m_inputChannelMap; + InputChannelMap::iterator m_lastMapPosition; + std::vector m_inputQueues; + std::vector m_inputChannelIds, m_outputChannelIds, m_outputToInput; + std::vector m_outputChannelIdStrings; + std::vector m_outputQueues; + int m_threshold; + unsigned int m_channelsReady, m_channelsFinished; + std::vector > m_v; + SecBlock m_u, m_w, m_y; +}; + +/// \brief Shamir's Secret Sharing Algorithm +/// \details SecretSharing is a variant of Shamir's secret sharing algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class SecretSharing : public CustomFlushPropagation +{ +public: + /// \brief Construct a SecretSharing + SecretSharing(RandomNumberGenerator &rng, int threshold, int nShares, BufferedTransformation *attachment=NULLPTR, bool addPadding=true) + : m_rng(rng), m_ida(new OutputProxy(*this, true)) + { + Detach(attachment); + IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RandomNumberGenerator &m_rng; + RawIDA m_ida; + bool m_pad; +}; + +/// \brief Shamir's Secret Sharing Algorithm +/// \details SecretSharing is a variant of Shamir's secret sharing algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class SecretRecovery : public RawIDA +{ +public: + /// \brief Construct a SecretRecovery + SecretRecovery(int threshold, BufferedTransformation *attachment=NULLPTR, bool removePadding=true) + : RawIDA(attachment) + {IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding));} + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; +}; + +/// a variant of Rabin's Information Dispersal Algorithm + +/// \brief Rabin's Information Dispersal Algorithm +/// \details InformationDispersal is a variant of Rabin's information dispersal algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class InformationDispersal : public CustomFlushPropagation +{ +public: + /// \brief Construct a InformationDispersal + InformationDispersal(int threshold, int nShares, BufferedTransformation *attachment=NULLPTR, bool addPadding=true) + : m_ida(new OutputProxy(*this, true)), m_pad(false), m_nextChannel(0) + { + Detach(attachment); + IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RawIDA m_ida; + bool m_pad; + unsigned int m_nextChannel; +}; + +/// \brief Rabin's Information Dispersal Algorithm +/// \details InformationDispersal is a variant of Rabin's information dispersal algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class InformationRecovery : public RawIDA +{ +public: + /// \brief Construct a InformationRecovery + InformationRecovery(int threshold, BufferedTransformation *attachment=NULLPTR, bool removePadding=true) + : RawIDA(attachment), m_pad(false) + {IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding));} + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; + ByteQueue m_queue; +}; + +class PaddingRemover : public Unflushable +{ +public: + PaddingRemover(BufferedTransformation *attachment=NULLPTR) + : m_possiblePadding(false), m_zeroCount(0) {Detach(attachment);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); m_possiblePadding = false;} + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + + // GetPossiblePadding() == false at the end of a message indicates incorrect padding + bool GetPossiblePadding() const {return m_possiblePadding;} + +private: + bool m_possiblePadding; + lword m_zeroCount; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/idea.h b/include/cryptlib/idea.h new file mode 100644 index 0000000..f4846b3 --- /dev/null +++ b/include/cryptlib/idea.h @@ -0,0 +1,66 @@ +// idea.h - originally written and placed in the public domain by Wei Dai + +/// \file idea.h +/// \brief Classes for the IDEA block cipher + +#ifndef CRYPTOPP_IDEA_H +#define CRYPTOPP_IDEA_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief IDEA block cipher information +/// \since Crypto++ 1.0 +struct IDEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public FixedRounds<8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "IDEA";} +}; + +/// \brief IDEA block cipher +/// \sa IDEA +/// \since Crypto++ 1.0 +class IDEA : public IDEA_Info, public BlockCipherDocumentation +{ +public: // made public for internal purposes +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + typedef word Word; +#else + typedef hword Word; +#endif + +private: + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + unsigned int OptimalDataAlignment() const {return 2;} + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + private: + void EnKey(const byte *); + void DeKey(); + FixedSizeSecBlock m_key; + + #ifdef IDEA_LARGECACHE + static inline void LookupMUL(word &a, word b); + void LookupKeyLogs(); + static void BuildLogTables(); + static volatile bool tablesBuilt; + static word16 log[0x10000], antilog[0x10000]; + #endif + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef IDEA::Encryption IDEAEncryption; +typedef IDEA::Decryption IDEADecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/integer.h b/include/cryptlib/integer.h new file mode 100644 index 0000000..8645853 --- /dev/null +++ b/include/cryptlib/integer.h @@ -0,0 +1,815 @@ +// integer.h - originally written and placed in the public domain by Wei Dai + +/// \file integer.h +/// \brief Multiple precision integer with arithmetic operations +/// \details The Integer class can represent positive and negative integers +/// with absolute value less than (256**sizeof(word))(256**sizeof(int)). +/// \details Internally, the library uses a sign magnitude representation, and the class +/// has two data members. The first is a IntegerSecBlock (a SecBlock) and it is +/// used to hold the representation. The second is a Sign (an enumeration), and it is +/// used to track the sign of the Integer. +/// \details For details on how the Integer class initializes its function pointers using +/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and +/// Integer::Two(), then see the comments at the top of integer.cpp. +/// \since Crypto++ 1.0 + +#ifndef CRYPTOPP_INTEGER_H +#define CRYPTOPP_INTEGER_H + +#include "cryptlib.h" +#include "secblock.h" +#include "stdcpp.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \struct InitializeInteger +/// \brief Performs static initialization of the Integer class +struct InitializeInteger +{ + InitializeInteger(); +}; + +// Always align, http://github.com/weidai11/cryptopp/issues/256 +typedef SecBlock > IntegerSecBlock; + +/// \brief Multiple precision integer with arithmetic operations +/// \details The Integer class can represent positive and negative integers +/// with absolute value less than (256**sizeof(word))(256**sizeof(int)). +/// \details Internally, the library uses a sign magnitude representation, and the class +/// has two data members. The first is a IntegerSecBlock (a SecBlock) and it is +/// used to hold the representation. The second is a Sign (an enumeration), and it is +/// used to track the sign of the Integer. +/// \details For details on how the Integer class initializes its function pointers using +/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and +/// Integer::Two(), then see the comments at the top of integer.cpp. +/// \since Crypto++ 1.0 +/// \nosubgrouping +class CRYPTOPP_DLL Integer : private InitializeInteger, public ASN1Object +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// \brief Exception thrown when division by 0 is encountered + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "Integer: division by zero") {} + }; + + /// \brief Exception thrown when a random number cannot be found that + /// satisfies the condition + class RandomNumberNotFound : public Exception + { + public: + RandomNumberNotFound() : Exception(OTHER_ERROR, "Integer: no integer satisfies the given parameters") {} + }; + + /// \enum Sign + /// \brief Used internally to represent the integer + /// \details Sign is used internally to represent the integer. It is also used in a few API functions. + /// \sa SetPositive(), SetNegative(), Signedness + enum Sign { + /// \brief the value is positive or 0 + POSITIVE=0, + /// \brief the value is negative + NEGATIVE=1}; + + /// \enum Signedness + /// \brief Used when importing and exporting integers + /// \details Signedness is usually used in API functions. + /// \sa Sign + enum Signedness { + /// \brief an unsigned value + UNSIGNED, + /// \brief a signed value + SIGNED}; + + /// \enum RandomNumberType + /// \brief Properties of a random integer + enum RandomNumberType { + /// \brief a number with no special properties + ANY, + /// \brief a number which is probabilistically prime + PRIME}; + //@} + + /// \name CREATORS + //@{ + /// \brief Creates the zero integer + Integer(); + + /// copy constructor + Integer(const Integer& t); + + /// \brief Convert from signed long + Integer(signed long value); + + /// \brief Convert from lword + /// \param sign enumeration indicating Sign + /// \param value the long word + Integer(Sign sign, lword value); + + /// \brief Convert from two words + /// \param sign enumeration indicating Sign + /// \param highWord the high word + /// \param lowWord the low word + Integer(Sign sign, word highWord, word lowWord); + + /// \brief Convert from a C-string + /// \param str C-string value + /// \param order the ByteOrder of the string to be processed + /// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case + /// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10. + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + explicit Integer(const char *str, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a wide C-string + /// \param str wide C-string value + /// \param order the ByteOrder of the string to be processed + /// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case + /// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10. + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + explicit Integer(const wchar_t *str, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a big-endian byte array + /// \param encodedInteger big-endian byte array + /// \param byteCount length of the byte array + /// \param sign enumeration indicating Signedness + /// \param order the ByteOrder of the array to be processed + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + Integer(const byte *encodedInteger, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a big-endian array + /// \param bt BufferedTransformation object with big-endian byte array + /// \param byteCount length of the byte array + /// \param sign enumeration indicating Signedness + /// \param order the ByteOrder of the data to be processed + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + Integer(BufferedTransformation &bt, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a BER encoded byte array + /// \param bt BufferedTransformation object with BER encoded byte array + explicit Integer(BufferedTransformation &bt); + + /// \brief Create a random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param bitCount the number of bits in the resulting integer + /// \details The random integer created is uniformly distributed over [0, 2bitCount]. + Integer(RandomNumberGenerator &rng, size_t bitCount); + + /// \brief Integer representing 0 + /// \returns an Integer representing 0 + /// \details Zero() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API Zero(); + /// \brief Integer representing 1 + /// \returns an Integer representing 1 + /// \details One() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API One(); + /// \brief Integer representing 2 + /// \returns an Integer representing 2 + /// \details Two() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API Two(); + + /// \brief Create a random integer of special form + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \param rnType RandomNumberType to specify the type + /// \param equiv the equivalence class based on the parameter \p mod + /// \param mod the modulus used to reduce the equivalence class + /// \throw RandomNumberNotFound if the set is empty. + /// \details Ideally, the random integer created should be uniformly distributed + /// over {x | min \<= x \<= max and \p x is of rnType and x \% mod == equiv}. + /// However the actual distribution may not be uniform because sequential + /// search is used to find an appropriate number from a random starting + /// point. + /// \details May return (with very small probability) a pseudoprime when a prime + /// is requested and max \> lastSmallPrime*lastSmallPrime. \p lastSmallPrime + /// is declared in nbtheory.h. + Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType=ANY, const Integer &equiv=Zero(), const Integer &mod=One()); + + /// \brief Exponentiates to a power of 2 + /// \returns the Integer 2e + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + static Integer CRYPTOPP_API Power2(size_t e); + //@} + + /// \name ENCODE/DECODE + //@{ + /// \brief Minimum number of bytes to encode this integer + /// \param sign enumeration indicating Signedness + /// \note The MinEncodedSize() of 0 is 1. + size_t MinEncodedSize(Signedness sign=UNSIGNED) const; + + /// \brief Encode in big-endian format + /// \param output big-endian byte array + /// \param outputLen length of the byte array + /// \param sign enumeration indicating Signedness + /// \details Unsigned means encode absolute value, signed means encode two's complement if negative. + /// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a + /// minimum size). An exact size is useful, for example, when encoding to a field element size. + void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const; + + /// \brief Encode in big-endian format + /// \param bt BufferedTransformation object + /// \param outputLen length of the encoding + /// \param sign enumeration indicating Signedness + /// \details Unsigned means encode absolute value, signed means encode two's complement if negative. + /// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a + /// minimum size). An exact size is useful, for example, when encoding to a field element size. + void Encode(BufferedTransformation &bt, size_t outputLen, Signedness sign=UNSIGNED) const; + + /// \brief Encode in DER format + /// \param bt BufferedTransformation object + /// \details Encodes the Integer using Distinguished Encoding Rules + /// The result is placed into a BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Encode absolute value as big-endian octet string + /// \param bt BufferedTransformation object + /// \param length the number of mytes to decode + void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const; + + /// \brief Encode absolute value in OpenPGP format + /// \param output big-endian byte array + /// \param bufferSize length of the byte array + /// \returns length of the output + /// \details OpenPGPEncode places result into the buffer and returns the + /// number of bytes used for the encoding + size_t OpenPGPEncode(byte *output, size_t bufferSize) const; + + /// \brief Encode absolute value in OpenPGP format + /// \param bt BufferedTransformation object + /// \returns length of the output + /// \details OpenPGPEncode places result into a BufferedTransformation object and returns the + /// number of bytes used for the encoding + size_t OpenPGPEncode(BufferedTransformation &bt) const; + + /// \brief Decode from big-endian byte array + /// \param input big-endian byte array + /// \param inputLen length of the byte array + /// \param sign enumeration indicating Signedness + void Decode(const byte *input, size_t inputLen, Signedness sign=UNSIGNED); + + /// \brief Decode nonnegative value from big-endian byte array + /// \param bt BufferedTransformation object + /// \param inputLen length of the byte array + /// \param sign enumeration indicating Signedness + /// \note bt.MaxRetrievable() \>= inputLen. + void Decode(BufferedTransformation &bt, size_t inputLen, Signedness sign=UNSIGNED); + + /// \brief Decode from BER format + /// \param input big-endian byte array + /// \param inputLen length of the byte array + void BERDecode(const byte *input, size_t inputLen); + + /// \brief Decode from BER format + /// \param bt BufferedTransformation object + void BERDecode(BufferedTransformation &bt); + + /// \brief Decode nonnegative value from big-endian octet string + /// \param bt BufferedTransformation object + /// \param length length of the byte array + void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length); + + /// \brief Exception thrown when an error is encountered decoding an OpenPGP integer + class OpenPGPDecodeErr : public Exception + { + public: + OpenPGPDecodeErr() : Exception(INVALID_DATA_FORMAT, "OpenPGP decode error") {} + }; + + /// \brief Decode from OpenPGP format + /// \param input big-endian byte array + /// \param inputLen length of the byte array + void OpenPGPDecode(const byte *input, size_t inputLen); + /// \brief Decode from OpenPGP format + /// \param bt BufferedTransformation object + void OpenPGPDecode(BufferedTransformation &bt); + //@} + + /// \name ACCESSORS + //@{ + /// \brief Determines if the Integer is convertable to Long + /// \returns true if *this can be represented as a signed long + /// \sa ConvertToLong() + bool IsConvertableToLong() const; + /// \brief Convert the Integer to Long + /// \return equivalent signed long if possible, otherwise undefined + /// \sa IsConvertableToLong() + signed long ConvertToLong() const; + + /// \brief Determines the number of bits required to represent the Integer + /// \returns number of significant bits = floor(log2(abs(*this))) + 1 + unsigned int BitCount() const; + /// \brief Determines the number of bytes required to represent the Integer + /// \returns number of significant bytes = ceiling(BitCount()/8) + unsigned int ByteCount() const; + /// \brief Determines the number of words required to represent the Integer + /// \returns number of significant words = ceiling(ByteCount()/sizeof(word)) + unsigned int WordCount() const; + + /// \brief Provides the i-th bit of the Integer + /// \returns the i-th bit, i=0 being the least significant bit + bool GetBit(size_t i) const; + /// \brief Provides the i-th byte of the Integer + /// \returns the i-th byte + byte GetByte(size_t i) const; + /// \brief Provides the low order bits of the Integer + /// \returns n lowest bits of *this >> i + lword GetBits(size_t i, size_t n) const; + + /// \brief Determines if the Integer is 0 + /// \returns true if the Integer is 0, false otherwise + bool IsZero() const {return !*this;} + /// \brief Determines if the Integer is non-0 + /// \returns true if the Integer is non-0, false otherwise + bool NotZero() const {return !IsZero();} + /// \brief Determines if the Integer is negative + /// \returns true if the Integer is negative, false otherwise + bool IsNegative() const {return sign == NEGATIVE;} + /// \brief Determines if the Integer is non-negative + /// \returns true if the Integer is non-negative, false otherwise + bool NotNegative() const {return !IsNegative();} + /// \brief Determines if the Integer is positive + /// \returns true if the Integer is positive, false otherwise + bool IsPositive() const {return NotNegative() && NotZero();} + /// \brief Determines if the Integer is non-positive + /// \returns true if the Integer is non-positive, false otherwise + bool NotPositive() const {return !IsPositive();} + /// \brief Determines if the Integer is even parity + /// \returns true if the Integer is even, false otherwise + bool IsEven() const {return GetBit(0) == 0;} + /// \brief Determines if the Integer is odd parity + /// \returns true if the Integer is odd, false otherwise + bool IsOdd() const {return GetBit(0) == 1;} + //@} + + /// \name MANIPULATORS + //@{ + /// \brief Assignment + Integer& operator=(const Integer& t); + + /// \brief Addition Assignment + Integer& operator+=(const Integer& t); + /// \brief Subtraction Assignment + Integer& operator-=(const Integer& t); + /// \brief Multiplication Assignment + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator*=(const Integer& t) {return *this = Times(t);} + /// \brief Division Assignment + Integer& operator/=(const Integer& t) {return *this = DividedBy(t);} + /// \brief Remainder Assignment + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator%=(const Integer& t) {return *this = Modulo(t);} + /// \brief Division Assignment + Integer& operator/=(word t) {return *this = DividedBy(t);} + /// \brief Remainder Assignment + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator%=(word t) {return *this = Integer(POSITIVE, 0, Modulo(t));} + + /// \brief Left-shift Assignment + Integer& operator<<=(size_t n); + /// \brief Right-shift Assignment + Integer& operator>>=(size_t n); + + /// \brief Bitwise AND Assignment + /// \param t the other Integer + /// \returns the result of *this & t + /// \details operator&=() performs a bitwise AND on *this. Missing bits are truncated + /// at the most significant bit positions, so the result is as small as the + /// smaller of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator&=(const Integer& t); + /// \brief Bitwise OR Assignment + /// \param t the second Integer + /// \returns the result of *this | t + /// \details operator|=() performs a bitwise OR on *this. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator|=(const Integer& t); + /// \brief Bitwise XOR Assignment + /// \param t the other Integer + /// \returns the result of *this ^ t + /// \details operator^=() performs a bitwise XOR on *this. Missing bits are shifted + /// in at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator^=(const Integer& t); + + /// \brief Set this Integer to random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param bitCount the number of bits in the resulting integer + /// \details The random integer created is uniformly distributed over [0, 2bitCount]. + void Randomize(RandomNumberGenerator &rng, size_t bitCount); + + /// \brief Set this Integer to random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \details The random integer created is uniformly distributed over [min, max]. + void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); + + /// \brief Set this Integer to random integer of special form + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \param rnType RandomNumberType to specify the type + /// \param equiv the equivalence class based on the parameter \p mod + /// \param mod the modulus used to reduce the equivalence class + /// \throw RandomNumberNotFound if the set is empty. + /// \details Ideally, the random integer created should be uniformly distributed + /// over {x | min \<= x \<= max and \p x is of rnType and x \% mod == equiv}. + /// However the actual distribution may not be uniform because sequential + /// search is used to find an appropriate number from a random starting + /// point. + /// \details May return (with very small probability) a pseudoprime when a prime + /// is requested and max \> lastSmallPrime*lastSmallPrime. \p lastSmallPrime + /// is declared in nbtheory.h. + bool Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv=Zero(), const Integer &mod=One()); + + /// \brief Generate a random number + /// \param rng RandomNumberGenerator used to generate material + /// \param params additional parameters that cannot be passed directly to the function + /// \returns true if a random number was generated, false otherwise + /// \details GenerateRandomNoThrow attempts to generate a random number according to the + /// parameters specified in params. The function does not throw RandomNumberNotFound. + /// \details The example below generates a prime number using NameValuePairs that Integer + /// class recognizes. The names are not provided in argnames.h. + ///
+		///     AutoSeededRandomPool prng;
+		///     AlgorithmParameters params = MakeParameters("BitLength", 2048)
+		///                                                ("RandomNumberType", Integer::PRIME);
+		///     Integer x;
+		///     if (x.GenerateRandomNoThrow(prng, params) == false)
+		///         throw std::runtime_error("Failed to generate prime number");
+		/// 
+ bool GenerateRandomNoThrow(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs); + + /// \brief Generate a random number + /// \param rng RandomNumberGenerator used to generate material + /// \param params additional parameters that cannot be passed directly to the function + /// \throw RandomNumberNotFound if a random number is not found + /// \details GenerateRandom attempts to generate a random number according to the + /// parameters specified in params. + /// \details The example below generates a prime number using NameValuePairs that Integer + /// class recognizes. The names are not provided in argnames.h. + ///
+		///     AutoSeededRandomPool prng;
+		///     AlgorithmParameters params = MakeParameters("BitLength", 2048)
+		///                                                ("RandomNumberType", Integer::PRIME);
+		///     Integer x;
+		///     try { x.GenerateRandom(prng, params); }
+		///     catch (RandomNumberNotFound&) { x = -1; }
+		/// 
+ void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) + { + if (!GenerateRandomNoThrow(rng, params)) + throw RandomNumberNotFound(); + } + + /// \brief Set the n-th bit to value + /// \details 0-based numbering. + void SetBit(size_t n, bool value=1); + + /// \brief Set the n-th byte to value + /// \details 0-based numbering. + void SetByte(size_t n, byte value); + + /// \brief Reverse the Sign of the Integer + void Negate(); + + /// \brief Sets the Integer to positive + void SetPositive() {sign = POSITIVE;} + + /// \brief Sets the Integer to negative + void SetNegative() {if (!!(*this)) sign = NEGATIVE;} + + /// \brief Swaps this Integer with another Integer + void swap(Integer &a); + //@} + + /// \name UNARY OPERATORS + //@{ + /// \brief Negation + bool operator!() const; + /// \brief Addition + Integer operator+() const {return *this;} + /// \brief Subtraction + Integer operator-() const; + /// \brief Pre-increment + Integer& operator++(); + /// \brief Pre-decrement + Integer& operator--(); + /// \brief Post-increment + Integer operator++(int) {Integer temp = *this; ++*this; return temp;} + /// \brief Post-decrement + Integer operator--(int) {Integer temp = *this; --*this; return temp;} + //@} + + /// \name BINARY OPERATORS + //@{ + /// \brief Perform signed comparison + /// \param a the Integer to comapre + /// \retval -1 if *this < a + /// \retval 0 if *this = a + /// \retval 1 if *this > a + int Compare(const Integer& a) const; + + /// \brief Addition + Integer Plus(const Integer &b) const; + /// \brief Subtraction + Integer Minus(const Integer &b) const; + /// \brief Multiplication + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Times(const Integer &b) const; + /// \brief Division + Integer DividedBy(const Integer &b) const; + /// \brief Remainder + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Modulo(const Integer &b) const; + /// \brief Division + Integer DividedBy(word b) const; + /// \brief Remainder + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + word Modulo(word b) const; + + /// \brief Bitwise AND + /// \param t the other Integer + /// \returns the result of *this & t + /// \details And() performs a bitwise AND on the operands. Missing bits are truncated + /// at the most significant bit positions, so the result is as small as the + /// smaller of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer And(const Integer& t) const; + + /// \brief Bitwise OR + /// \param t the other Integer + /// \returns the result of *this | t + /// \details Or() performs a bitwise OR on the operands. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer Or(const Integer& t) const; + + /// \brief Bitwise XOR + /// \param t the other Integer + /// \returns the result of *this ^ t + /// \details Xor() performs a bitwise XOR on the operands. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer Xor(const Integer& t) const; + + /// \brief Right-shift + Integer operator>>(size_t n) const {return Integer(*this)>>=n;} + /// \brief Left-shift + Integer operator<<(size_t n) const {return Integer(*this)<<=n;} + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// \brief Retrieve the absolute value of this integer + Integer AbsoluteValue() const; + /// \brief Add this integer to itself + Integer Doubled() const {return Plus(*this);} + /// \brief Multiply this integer by itself + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Squared() const {return Times(*this);} + /// \brief Extract square root + /// \details if negative return 0, else return floor of square root + Integer SquareRoot() const; + /// \brief Determine whether this integer is a perfect square + bool IsSquare() const; + + /// \brief Determine if 1 or -1 + /// \returns true if this integer is 1 or -1, false otherwise + bool IsUnit() const; + /// \brief Calculate multiplicative inverse + /// \returns MultiplicativeInverse inverse if 1 or -1, otherwise return 0. + Integer MultiplicativeInverse() const; + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a a reference to the dividend + /// \param d a reference to the divisor + /// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + static void CRYPTOPP_API Divide(Integer &r, Integer &q, const Integer &a, const Integer &d); + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a a reference to the dividend + /// \param d a reference to the divisor + /// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + /// This overload uses a faster division algorithm because the divisor is short. + static void CRYPTOPP_API Divide(word &r, Integer &q, const Integer &a, word d); + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a a reference to the dividend + /// \param n a reference to the divisor + /// \details DivideByPowerOf2 calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + /// It returns same result as Divide(r, q, a, Power2(n)), but faster. + /// This overload uses a faster division algorithm because the divisor is a power of 2. + static void CRYPTOPP_API DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n); + + /// \brief Calculate greatest common divisor + /// \param a a reference to the first number + /// \param n a reference to the secind number + /// \returns the greatest common divisor a and n. + static Integer CRYPTOPP_API Gcd(const Integer &a, const Integer &n); + + /// \brief Calculate multiplicative inverse + /// \param n a reference to the modulus + /// \returns an Integer *this % n. + /// \details InverseMod returns the multiplicative inverse of the Integer *this + /// modulo the Integer n. If no Integer exists then Integer 0 is returned. + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer InverseMod(const Integer &n) const; + + /// \brief Calculate multiplicative inverse + /// \param n the modulus + /// \returns a word *this % n. + /// \details InverseMod returns the multiplicative inverse of the Integer *this + /// modulo the word n. If no Integer exists then word 0 is returned. + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + word InverseMod(word n) const; + //@} + + /// \name INPUT/OUTPUT + //@{ + /// \brief Extraction operator + /// \param in a reference to a std::istream + /// \param a a reference to an Integer + /// \returns a reference to a std::istream reference + friend CRYPTOPP_DLL std::istream& CRYPTOPP_API operator>>(std::istream& in, Integer &a); + + /// \brief Insertion operator + /// \param out a reference to a std::ostream + /// \param a a constant reference to an Integer + /// \returns a reference to a std::ostream reference + /// \details The output integer responds to std::hex, std::oct, std::hex, std::upper and + /// std::lower. The output includes the suffix \a \b h (for hex), \a \b . (\a \b dot, for dec) + /// and \a \b o (for octal). There is currently no way to suppress the suffix. + /// \details If you want to print an Integer without the suffix or using an arbitrary base, then + /// use IntToString(). + /// \sa IntToString + friend CRYPTOPP_DLL std::ostream& CRYPTOPP_API operator<<(std::ostream& out, const Integer &a); + //@} + + /// \brief Modular multiplication + /// \param x a reference to the first term + /// \param y a reference to the second term + /// \param m a reference to the modulus + /// \returns an Integer (a * b) % m. + CRYPTOPP_DLL friend Integer CRYPTOPP_API a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m); + /// \brief Modular exponentiation + /// \param x a reference to the base + /// \param e a reference to the exponent + /// \param m a reference to the modulus + /// \returns an Integer (a ^ b) % m. + CRYPTOPP_DLL friend Integer CRYPTOPP_API a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m); + +protected: + + // http://github.com/weidai11/cryptopp/issues/602 + Integer InverseModNext(const Integer &n) const; + +private: + + Integer(word value, size_t length); + int PositiveCompare(const Integer &t) const; + + IntegerSecBlock reg; + Sign sign; + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + friend class ModularArithmetic; + friend class MontgomeryRepresentation; + friend class HalfMontgomeryRepresentation; + + friend void PositiveAdd(Integer &sum, const Integer &a, const Integer &b); + friend void PositiveSubtract(Integer &diff, const Integer &a, const Integer &b); + friend void PositiveMultiply(Integer &product, const Integer &a, const Integer &b); + friend void PositiveDivide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor); +#endif +}; + +/// \brief Comparison +inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;} +/// \brief Comparison +inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;} +/// \brief Comparison +inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;} +/// \brief Comparison +inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;} +/// \brief Comparison +inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;} +/// \brief Comparison +inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;} +/// \brief Addition +inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);} +/// \brief Subtraction +inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);} +/// \brief Multiplication +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);} +/// \brief Division +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);} +/// \brief Remainder +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);} +/// \brief Division +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);} +/// \brief Remainder +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);} + +/// \brief Bitwise AND +/// \param a the first Integer +/// \param b the second Integer +/// \returns the result of a & b +/// \details operator&() performs a bitwise AND on the operands. Missing bits are truncated +/// at the most significant bit positions, so the result is as small as the +/// smaller of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator&(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.And(b);} + +/// \brief Bitwise OR +/// \param a the first Integer +/// \param b the second Integer +/// \returns the result of a | b +/// \details operator|() performs a bitwise OR on the operands. Missing bits are shifted in +/// at the most significant bit positions, so the result is as large as the +/// larger of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator|(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Or(b);} + +/// \brief Bitwise XOR +/// \param a the first Integer +/// \param b the second Integer +/// \returns the result of a ^ b +/// \details operator^() performs a bitwise XOR on the operands. Missing bits are shifted +/// in at the most significant bit positions, so the result is as large as the +/// larger of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator^(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Xor(b);} + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +inline void swap(CryptoPP::Integer &a, CryptoPP::Integer &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/include/cryptlib/iterhash.h b/include/cryptlib/iterhash.h new file mode 100644 index 0000000..0277140 --- /dev/null +++ b/include/cryptlib/iterhash.h @@ -0,0 +1,196 @@ +// iterhash.h - originally written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_ITERHASH_H +#define CRYPTOPP_ITERHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "simple.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +// GCC cast warning +#define HashWordPtr(x) ((HashWordType*)(void*)(x)) +#define ConstHashWordPtr(x) ((const HashWordType*)(const void*)(x)) + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when trying to hash more data than is allowed by a hash function +class CRYPTOPP_DLL HashInputTooLong : public InvalidDataFormat +{ +public: + explicit HashInputTooLong(const std::string &alg) + : InvalidDataFormat("IteratedHashBase: input data exceeds maximum allowed by hash function " + alg) {} +}; + +/// \brief Iterated hash base class +/// \tparam T Hash word type +/// \tparam BASE HashTransformation derived class +/// \details IteratedHashBase provides an interface for block-based iterated hashes +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHashBase : public BASE +{ +public: + typedef T HashWordType; + + /// \brief Construct an IteratedHashBase + IteratedHashBase() : m_countLo(0), m_countHi(0) {} + + /// \brief Provides the input block size most efficient for this cipher. + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + unsigned int OptimalBlockSize() const {return this->BlockSize();} + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \details OptimalDataAlignment returns the natural alignment of the hash word. + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + /// \brief Updates a hash with additional input + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + void Update(const byte *input, size_t length); + + /// \brief Requests space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. + byte * CreateUpdateSpace(size_t &size); + + /// \brief Restart the hash + /// \details Discards the current state, and restart for a new message + void Restart(); + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() call Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + void TruncatedFinal(byte *digest, size_t digestSize); + +protected: + inline T GetBitCountHi() const {return (m_countLo >> (8*sizeof(T)-3)) + (m_countHi << 3);} + inline T GetBitCountLo() const {return m_countLo << 3;} + + void PadLastBlock(unsigned int lastBlockSize, byte padFirst=0x80); + virtual void Init() =0; + + virtual ByteOrder GetByteOrder() const =0; + virtual void HashEndianCorrectedBlock(const HashWordType *data) =0; + virtual size_t HashMultipleBlocks(const T *input, size_t length); + void HashBlock(const HashWordType *input) {HashMultipleBlocks(input, this->BlockSize());} + + virtual T* DataBuf() =0; + virtual T* StateBuf() =0; + +private: + T m_countLo, m_countHi; +}; + +/// \brief Iterated hash base class +/// \tparam T_HashWordType Hash word type +/// \tparam T_Endianness Endianness type of hash +/// \tparam T_BlockSize Block size of the hash +/// \tparam T_Base HashTransformation derived class +/// \details IteratedHash provides a default implementation for block-based iterated hashes +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHash : public IteratedHashBase +{ +public: + typedef T_Endianness ByteOrderClass; + typedef T_HashWordType HashWordType; + + CRYPTOPP_CONSTANT(BLOCKSIZE = T_BlockSize) + // BCB2006 workaround: can't use BLOCKSIZE here + CRYPTOPP_COMPILE_ASSERT((T_BlockSize & (T_BlockSize - 1)) == 0); // blockSize is a power of 2 + + virtual ~IteratedHash() {} + + /// \brief Provides the block size of the hash + /// \return the block size of the hash, in bytes + /// \details BlockSize() returns T_BlockSize. + unsigned int BlockSize() const {return T_BlockSize;} + + /// \brief Provides the byte order of the hash + /// \returns the byte order of the hash as an enumeration + /// \details GetByteOrder() returns T_Endianness::ToEnum(). + /// \sa ByteOrder() + ByteOrder GetByteOrder() const {return T_Endianness::ToEnum();} + + /// \brief Adjusts the byte ordering of the hash + /// \param out the output buffer + /// \param in the input buffer + /// \param byteCount the size of the buffers, in bytes + /// \details CorrectEndianess() calls ConditionalByteReverse() using T_Endianness. + inline void CorrectEndianess(HashWordType *out, const HashWordType *in, size_t byteCount) + { + ConditionalByteReverse(T_Endianness::ToEnum(), out, in, byteCount); + } + +protected: + T_HashWordType* DataBuf() {return this->m_data;} + FixedSizeSecBlock m_data; +}; + +/// \brief Iterated hash with a static transformation function +/// \tparam T_HashWordType Hash word type +/// \tparam T_Endianness Endianness type of hash +/// \tparam T_BlockSize Block size of the hash +/// \tparam T_StateSize Internal state size of the hash +/// \tparam T_Transform HashTransformation derived class +/// \tparam T_DigestSize Digest size of the hash +/// \tparam T_StateAligned Flag indicating if state is 16-byte aligned +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHashWithStaticTransform + : public ClonableImpl, T_Transform> > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize ? T_DigestSize : T_StateSize) + + virtual ~IteratedHashWithStaticTransform() {} + + /// \brief Provides the digest size of the hash + /// \return the digest size of the hash, in bytes + /// \details DigestSize() returns DIGESTSIZE. + unsigned int DigestSize() const {return DIGESTSIZE;}; + +protected: + IteratedHashWithStaticTransform() {this->Init();} + void HashEndianCorrectedBlock(const T_HashWordType *data) {T_Transform::Transform(this->m_state, data);} + void Init() {T_Transform::InitState(this->m_state);} + + T_HashWordType* StateBuf() {return this->m_state;} + FixedSizeAlignedSecBlock m_state; +}; + +#if !defined(__GNUC__) && !defined(__clang__) + CRYPTOPP_DLL_TEMPLATE_CLASS IteratedHashBase; + CRYPTOPP_STATIC_TEMPLATE_CLASS IteratedHashBase; + + CRYPTOPP_DLL_TEMPLATE_CLASS IteratedHashBase; + CRYPTOPP_STATIC_TEMPLATE_CLASS IteratedHashBase; +#endif + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/kalyna.h b/include/cryptlib/kalyna.h new file mode 100644 index 0000000..e664a39 --- /dev/null +++ b/include/cryptlib/kalyna.h @@ -0,0 +1,218 @@ +// kalyna.h - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. + +/// \file kalyna.h +/// \brief Classes for the Kalyna block cipher +/// \details The Crypto++ implementation relied upon three sources. First was Oliynykov, Gorbenko, Kazymyrov, +/// Ruzhentsev, Kuznetsov, Gorbenko, Dyrda, Dolgov, Pushkaryov, Mordvinov and Kaidalov's "A New Encryption +/// Standard of Ukraine: The Kalyna Block Cipher" (http://eprint.iacr.org/2015/650.pdf). Second was Roman +/// Oliynykov and Oleksandr Kazymyrov's GitHub with the reference implementation +/// (http://github.com/Roman-Oliynykov/Kalyna-reference). The third resource was Keru Kuro's implementation +/// of Kalyna in CppCrypto (http://sourceforge.net/projects/cppcrypto/). Kuro has an outstanding +/// implementation that performed better than the reference implementation and our initial attempts. + +#ifndef CRYPTOPP_KALYNA_H +#define CRYPTOPP_KALYNA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Kalyna-128 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna128_Info : public FixedBlockSize<16>, VariableKeyLength<16, 16, 32> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-128"; + } +}; + +/// \brief Kalyna-256 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna256_Info : public FixedBlockSize<32>, VariableKeyLength<32, 32, 64> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-256"; + } +}; + +/// \brief Kalyna-512 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna512_Info : public FixedBlockSize<64>, FixedKeyLength<64> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-512"; + } +}; + +/// \brief Kalyna block cipher base class +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Kalyna_Base +{ +public: + virtual ~Kalyna_Base() {} + +protected: + typedef SecBlock > AlignedSecBlock64; + mutable AlignedSecBlock64 m_wspace; // work space + AlignedSecBlock64 m_mkey; // master key + AlignedSecBlock64 m_rkeys; // round keys + unsigned int m_kl, m_nb, m_nk; // number 64-bit blocks and keys +}; + +/// \brief Kalyna 128-bit block cipher +/// \details Kalyna128 provides 128-bit block size. The valid key sizes are 128-bit and 256-bit. +/// \since Crypto++ 6.0 +class Kalyna128 : public Kalyna128_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-128") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_22(const word64 key[2]); + void SetKey_24(const word64 key[4]); + void ProcessBlock_22(const word64 inBlock[2], const word64 xorBlock[2], word64 outBlock[2]) const; + void ProcessBlock_24(const word64 inBlock[2], const word64 xorBlock[2] ,word64 outBlock[2]) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief Kalyna 256-bit block cipher +/// \details Kalyna256 provides 256-bit block size. The valid key sizes are 256-bit and 512-bit. +/// \since Crypto++ 6.0 +class Kalyna256 : public Kalyna256_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-256") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_44(const word64 key[4]); + void SetKey_48(const word64 key[8]); + void ProcessBlock_44(const word64 inBlock[4], const word64 xorBlock[4], word64 outBlock[4]) const; + void ProcessBlock_48(const word64 inBlock[4], const word64 xorBlock[4], word64 outBlock[4]) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief Kalyna 512-bit block cipher +/// \details Kalyna512 provides 512-bit block size. The valid key size is 512-bit. +/// \since Crypto++ 6.0 +class Kalyna512 : Kalyna512_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-512") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_88(const word64 key[8]); + void ProcessBlock_88(const word64 inBlock[8], const word64 xorBlock[8], word64 outBlock[8]) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Kalyna128::Encryption Kalyna128Encryption; +typedef Kalyna128::Decryption Kalyna128Decryption; + +typedef Kalyna256::Encryption Kalyna256Encryption; +typedef Kalyna256::Decryption Kalyna256Decryption; + +typedef Kalyna512::Encryption Kalyna512Encryption; +typedef Kalyna512::Decryption Kalyna512Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_KALYNA_H diff --git a/include/cryptlib/keccak.h b/include/cryptlib/keccak.h new file mode 100644 index 0000000..55be28d --- /dev/null +++ b/include/cryptlib/keccak.h @@ -0,0 +1,105 @@ +// keccak.h - originally written and placed in the public domain by Wei Dai + +/// \file keccak.h +/// \brief Classes for Keccak message digests +/// \details The Crypto++ Keccak implementation uses F1600 with XOF d=0x01. +/// FIPS 202 conformance (XOF d=0x06) is available in SHA3 classes. +/// \details Keccak will likely change in the future to accommodate extensibility of the +/// round function and the XOF functions. +/// \sa Keccak +/// \since Crypto++ 5.6.4 + +#ifndef CRYPTOPP_KECCAK_H +#define CRYPTOPP_KECCAK_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Keccak message digest base class +/// \details The Crypto++ Keccak implementation uses F1600 with XOF d=0x01. +/// FIPS 202 conformance (XOF d=0x06) is available in SHA3 classes. +/// \details Keccak is the base class for Keccak_224, Keccak_256, Keccak_384 and Keccak_512. +/// Library users should instantiate a derived class, and only use Keccak +/// as a base class reference or pointer. +/// \details Keccak will likely change in the future to accommodate extensibility of the +/// round function and the XOF functions. +/// \details Perform the following to specify a different digest size. The class will use F1600, +/// XOF d=0x01, and a new vaue for r() (which will be 200-2*24 = 152). +///
  Keccack_192 : public Keccack
+///   {
+///     public:
+///       CRYPTOPP_CONSTANT(DIGESTSIZE = 24)
+///       Keccack_192() : Keccack(DIGESTSIZE) {}
+///   };
+///   
+/// +/// \sa SHA3, Keccak_224, Keccak_256, Keccak_384 and Keccak_512. +/// \since Crypto++ 5.6.4 +class Keccak : public HashTransformation +{ +public: + /// \brief Construct a Keccak + /// \param digestSize the digest size, in bytes + /// \details Keccak is the base class for Keccak_224, Keccak_256, Keccak_384 and Keccak_512. + /// Library users should instantiate a derived class, and only use Keccak + /// as a base class reference or pointer. + /// \since Crypto++ 5.6.4 + Keccak(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + unsigned int DigestSize() const {return m_digestSize;} + std::string AlgorithmName() const {return "Keccak-" + IntToString(m_digestSize*8);} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "Keccak"; } + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + + //unsigned int BlockSize() const { return r(); } // that's the idea behind it + +protected: + inline unsigned int r() const {return 200 - 2 * m_digestSize;} + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief Keccak message digest template +/// \tparam T_DigestSize the size of the digest, in bytes +/// \since Crypto++ 6.0 +template +class Keccak_Final : public Keccak +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize) + CRYPTOPP_CONSTANT(BLOCKSIZE = 200 - 2 * DIGESTSIZE) + + /// \brief Construct a Keccak-X message digest + Keccak_Final() : Keccak(DIGESTSIZE) {} + static std::string StaticAlgorithmName() { return "Keccak-" + IntToString(DIGESTSIZE * 8); } + unsigned int BlockSize() const { return BLOCKSIZE; } +private: + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE > (int)T_DigestSize); // this is a general expectation by HMAC +}; + +/// \brief Keccak-224 message digest +/// \since Crypto++ 5.6.4 +typedef Keccak_Final<28> Keccak_224; + +/// \brief Keccak-256 message digest +/// \since Crypto++ 5.6.4 +typedef Keccak_Final<32> Keccak_256; + +/// \brief Keccak-384 message digest +/// \since Crypto++ 5.6.4 +typedef Keccak_Final<48> Keccak_384; + +/// \brief Keccak-512 message digest +/// \since Crypto++ 5.6.4 +typedef Keccak_Final<64> Keccak_512; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/lubyrack.h b/include/cryptlib/lubyrack.h new file mode 100644 index 0000000..cc583ff --- /dev/null +++ b/include/cryptlib/lubyrack.h @@ -0,0 +1,137 @@ +// lubyrack.h - originally written and placed in the public domain by Wei Dai + +/// \file lubyrack.h +/// \brief Classes for the Luby-Rackoff block cipher + +#ifndef CRYPTOPP_LUBYRACK_H +#define CRYPTOPP_LUBYRACK_H + +#include "simple.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Luby-Rackoff block cipher information +template +struct LR_Info : public VariableKeyLength<16, 0, 2*(INT_MAX/2), 2>, public FixedBlockSize<2*T::DIGESTSIZE> +{ + static std::string StaticAlgorithmName() {return std::string("LR/")+T::StaticAlgorithmName();} +}; + +/// \brief Luby-Rackoff block cipher +template +class LR : public LR_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl > + { + public: + // VC60 workaround: have to define these functions within class definition + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) + { + this->AssertValidKeyLength(length); + + L = length/2; + buffer.New(2*S); + digest.New(S); + key.Assign(userKey, 2*L); + } + + protected: + CRYPTOPP_CONSTANT(S=T::DIGESTSIZE) + unsigned int L; // key length / 2 + SecByteBlock key; + + mutable T hm; + mutable SecByteBlock buffer, digest; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + +#define KL this->key +#define KR this->key+this->L +#define BL this->buffer +#define BR this->buffer+this->S +#define IL inBlock +#define IR inBlock+this->S +#define OL outBlock +#define OR outBlock+this->S + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + this->hm.Update(KL, this->L); + this->hm.Update(IL, this->S); + this->hm.Final(BR); + xorbuf(BR, IR, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(BR, this->S); + this->hm.Final(BL); + xorbuf(BL, IL, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(BL, this->S); + this->hm.Final(this->digest); + xorbuf(BR, this->digest, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(OR, this->S); + this->hm.Final(this->digest); + xorbuf(BL, this->digest, this->S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, this->buffer, 2*this->S); + else + memcpy_s(outBlock, 2*this->S, this->buffer, 2*this->S); + } + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + this->hm.Update(KR, this->L); + this->hm.Update(IR, this->S); + this->hm.Final(BL); + xorbuf(BL, IL, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(BL, this->S); + this->hm.Final(BR); + xorbuf(BR, IR, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(BR, this->S); + this->hm.Final(this->digest); + xorbuf(BL, this->digest, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(OL, this->S); + this->hm.Final(this->digest); + xorbuf(BR, this->digest, this->S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, this->buffer, 2*this->S); + else + memcpy(outBlock, this->buffer, 2*this->S); + } +#undef KL +#undef KR +#undef BL +#undef BR +#undef IL +#undef IR +#undef OL +#undef OR + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/luc.h b/include/cryptlib/luc.h new file mode 100644 index 0000000..7c0c1b7 --- /dev/null +++ b/include/cryptlib/luc.h @@ -0,0 +1,338 @@ +// luc.h - originally written and placed in the public domain by Wei Dai + +/// \file luc.h +/// \brief Classes for the LUC cryptosystem +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_LUC_H +#define CRYPTOPP_LUC_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "integer.h" +#include "algebra.h" +#include "secblock.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189) +#endif + +#include "pkcspad.h" +#include "integer.h" +#include "oaep.h" +#include "dh.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief The LUC function. +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +class LUCFunction : public TrapdoorFunction, public PublicKey +{ + typedef LUCFunction ThisClass; + +public: + virtual ~LUCFunction() {} + + /// \brief Initialize a LUC public key with {n,e} + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +/// \brief The LUC inverse function. +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +class InvertibleLUCFunction : public LUCFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleLUCFunction ThisClass; + +public: + virtual ~InvertibleLUCFunction() {} + + /// \brief Create a LUC private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \param eStart the desired starting public exponent + /// \details Initialize() creates a new keypair using a starting public exponent of 17. + /// \details This function overload of Initialize() creates a new keypair because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &eStart=17); + + /// \brief Initialize a LUC private key with {n,e,p,q,dp,dq,u} + /// \param n modulus + /// \param e public exponent + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_e = e; m_p = p; m_q = q; m_u = u;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize, PublicExponent (default 17)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +/// \brief LUC cryptosystem +/// \since Crypto++ 2.1 +struct LUC +{ + static std::string StaticAlgorithmName() {return "LUC";} + typedef LUCFunction PublicKey; + typedef InvertibleLUCFunction PrivateKey; +}; + +/// \brief LUC encryption scheme +/// \tparam STANDARD signature standard +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUCES : public TF_ES +{ +}; + +/// \brief LUC signature scheme with appendix +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUCSS : public TF_SS +{ +}; + +// analogous to the RSA schemes defined in PKCS #1 v2.0 +typedef LUCES >::Decryptor LUCES_OAEP_SHA_Decryptor; +typedef LUCES >::Encryptor LUCES_OAEP_SHA_Encryptor; + +typedef LUCSS::Signer LUCSSA_PKCS1v15_SHA_Signer; +typedef LUCSS::Verifier LUCSSA_PKCS1v15_SHA_Verifier; + +// ******************************************************** + +/// \brief LUC GroupParameters precomputation +/// \details No actual precomputation is performed +/// \since Crypto++ 2.1 +class DL_GroupPrecomputation_LUC : public DL_GroupPrecomputation +{ +public: + virtual ~DL_GroupPrecomputation_LUC() {} + + const AbstractGroup & GetGroup() const {CRYPTOPP_ASSERT(false); throw 0;} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_p = v;} + const Integer & GetModulus() const {return m_p;} + +private: + Integer m_p; +}; + +/// \brief LUC Precomputation +/// \since Crypto++ 2.1 +class DL_BasePrecomputation_LUC : public DL_FixedBasePrecomputation +{ +public: + virtual ~DL_BasePrecomputation_LUC() {} + + // DL_FixedBasePrecomputation + bool IsInitialized() const {return m_g.NotZero();} + void SetBase(const DL_GroupPrecomputation &group, const Integer &base) + {CRYPTOPP_UNUSED(group); m_g = base;} + const Integer & GetBase(const DL_GroupPrecomputation &group) const + {CRYPTOPP_UNUSED(group); return m_g;} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(maxExpBits); CRYPTOPP_UNUSED(storage);} + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(storedPrecomputation);} + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(storedPrecomputation);} + Integer Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Integer CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const + { + CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(exponent); CRYPTOPP_UNUSED(pc2); CRYPTOPP_UNUSED(exponent2); + // shouldn't be called + throw NotImplemented("DL_BasePrecomputation_LUC: CascadeExponentiate not implemented"); + } + +private: + Integer m_g; +}; + +/// \brief LUC GroupParameters specialization +/// \since Crypto++ 2.1 +class DL_GroupParameters_LUC : public DL_GroupParameters_IntegerBasedImpl +{ +public: + virtual ~DL_GroupParameters_LUC() {} + + // DL_GroupParameters + bool IsIdentity(const Integer &element) const {return element == Integer::Two();} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + Element MultiplyElements(const Element &a, const Element &b) const + { + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented"); + } + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const + { + CRYPTOPP_UNUSED(element1); CRYPTOPP_UNUSED(exponent1); CRYPTOPP_UNUSED(element2); CRYPTOPP_UNUSED(exponent2); + throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented"); + } + + // NameValuePairs interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue).Assignable(); + } + +private: + int GetFieldType() const {return 2;} +}; + +/// \brief GF(p) group parameters that default to safe primes +/// \since Crypto++ 2.1 +class DL_GroupParameters_LUC_DefaultSafePrime : public DL_GroupParameters_LUC +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +/// \brief LUC HMP signature algorithm +/// \since Crypto++ 2.1 +class DL_Algorithm_LUC_HMP : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "LUC-HMP";} + + virtual ~DL_Algorithm_LUC_HMP() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const; + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const; + + size_t RLen(const DL_GroupParameters ¶ms) const + {return params.GetGroupOrder().ByteCount();} +}; + +/// \brief LUC signature keys +/// \since Crypto++ 2.1 +struct DL_SignatureKeys_LUC +{ + typedef DL_GroupParameters_LUC GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief LUC-HMP, based on "Digital signature schemes based on Lucas functions" by Patrick Horster, Markus Michels, Holger Petersen +/// \tparam H hash transformation +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUC_HMP : public DL_SS +{ +}; + +/// \brief LUC encryption keys +/// \since Crypto++ 2.1 +struct DL_CryptoKeys_LUC +{ + typedef DL_GroupParameters_LUC_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief LUC Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as u·V, v·U and label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \sa CofactorMultiplicationOption +/// \since Crypto++ 2.1, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct LUC_IES + : public DL_ES< + DL_CryptoKeys_LUC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + LUC_IES<> > +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "LUC-IES";} // non-standard name +}; + +// ******************************************************** + +/// \brief LUC-DH +typedef DH_Domain LUC_DH; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/mars.h b/include/cryptlib/mars.h new file mode 100644 index 0000000..53c093c --- /dev/null +++ b/include/cryptlib/mars.h @@ -0,0 +1,60 @@ +// mars.h - originally written and placed in the public domain by Wei Dai + +/// \file mars.h +/// \brief Classes for the MARS block cipher (IBM AES submission) +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MARS_H +#define CRYPTOPP_MARS_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief MARS block cipher information +/// \since Crypto++ 3.0 +struct MARS_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 56, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARS";} +}; + +/// \brief MARS block cipher +/// \sa MARS +/// \since Crypto++ 3.0 +class MARS : public MARS_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static const word32 Sbox[512]; + + FixedSizeSecBlock m_k; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef MARS::Encryption MARSEncryption; +typedef MARS::Decryption MARSDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/md2.h b/include/cryptlib/md2.h new file mode 100644 index 0000000..f3a5a24 --- /dev/null +++ b/include/cryptlib/md2.h @@ -0,0 +1,54 @@ +// md2.h - originally written and placed in the public domain by Wei Dai + +/// \file md2.h +/// \brief Classes for the MD2 message digest +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MD2_H +#define CRYPTOPP_MD2_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief MD2 message digest +/// \sa MD2 +/// \since Crypto++ 3.0 +class MD2 : public HashTransformation +{ +public: + MD2(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + unsigned int BlockSize() const {return BLOCKSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD2";} + + CRYPTOPP_CONSTANT(DIGESTSIZE = 16) + CRYPTOPP_CONSTANT(BLOCKSIZE = 16) + +private: + void Transform(); + void Init(); + SecByteBlock m_X, m_C, m_buf; + unsigned int m_count; +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/md4.h b/include/cryptlib/md4.h new file mode 100644 index 0000000..8984b5e --- /dev/null +++ b/include/cryptlib/md4.h @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_MD4_H +#define CRYPTOPP_MD4_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// MD4 +/*! \warning MD4 is considered insecure, and should not be used + unless you absolutely need it for compatibility. */ +class MD4 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD4";} +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/md5.h b/include/cryptlib/md5.h new file mode 100644 index 0000000..2b3e2c3 --- /dev/null +++ b/include/cryptlib/md5.h @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_MD5_H +#define CRYPTOPP_MD5_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief MD5 message digest +/// \sa MD5 +/// \since Crypto++ 1.0 +class MD5 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD5";} +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/mdc.h b/include/cryptlib/mdc.h new file mode 100644 index 0000000..68d5ab8 --- /dev/null +++ b/include/cryptlib/mdc.h @@ -0,0 +1,84 @@ +// mdc.h - originally written and placed in the public domain by Wei Dai + +/// \file mdc.h +/// \brief Classes for the MDC message digest + +#ifndef CRYPTOPP_MDC_H +#define CRYPTOPP_MDC_H + +#include "seckey.h" +#include "secblock.h" +#include "misc.h" + +// GCC cast warning +#define HashWordPtr(x) ((HashWordType*)(void*)(x)) +#define ConstHashWordPtr(x) ((const HashWordType*)(const void*)(x)) + +NAMESPACE_BEGIN(CryptoPP) + +/// \tparam B BlockCipher derived class +/// \brief MDC_Info cipher information +template +struct MDC_Info : public FixedBlockSize, public FixedKeyLength +{ + static std::string StaticAlgorithmName() {return std::string("MDC/")+B::StaticAlgorithmName();} +}; + +/// \brief MDC cipher +/// \tparam H HashTransformation derived class +/// \details MDC() is a construction by Peter Gutmann to turn an iterated hash function into a PRF +/// \sa MDC +template +class MDC : public MDC_Info +{ + /// \brief MDC cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public BlockCipherImpl > + { + typedef typename H::HashWordType HashWordType; + + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(params); + this->AssertValidKeyLength(length); + ConditionalByteReverse(BIG_ENDIAN_ORDER, Key(), ConstHashWordPtr(userKey), this->KEYLENGTH); + } + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, Buffer(), ConstHashWordPtr(inBlock), this->BLOCKSIZE); + H::Transform(Buffer(), Key()); + + if (xorBlock) + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, Buffer(), Buffer(), this->BLOCKSIZE); + xorbuf(outBlock, xorBlock, m_buffer, this->BLOCKSIZE); + } + else + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, HashWordPtr(outBlock), Buffer(), this->BLOCKSIZE); + } + } + + bool IsPermutation() const {return false;} + + unsigned int OptimalDataAlignment() const {return sizeof(HashWordType);} + + private: + HashWordType *Key() {return HashWordPtr(m_key.data());} + const HashWordType *Key() const {return ConstHashWordPtr(m_key.data());} + HashWordType *Buffer() const {return HashWordPtr(m_buffer.data());} + + // VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup + FixedSizeSecBlock::KEYLENGTH, AllocatorWithCleanup > m_key; + mutable FixedSizeSecBlock::BLOCKSIZE, AllocatorWithCleanup > m_buffer; + }; + +public: + // use BlockCipher interface + typedef BlockCipherFinal Encryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/mersenne.h b/include/cryptlib/mersenne.h new file mode 100644 index 0000000..6065c17 --- /dev/null +++ b/include/cryptlib/mersenne.h @@ -0,0 +1,228 @@ +// mersenne.h - written and placed in public domain by Jeffrey Walton. + +/// \file mersenne.h +/// \brief Class file for Mersenne Twister +/// \warning MersenneTwister is suitable for Monte-Carlo simulations, where uniformaly distrubuted +/// numbers are required quickly. It should not be used for cryptographic purposes. +/// \since Crypto++ 5.6.3 +#ifndef CRYPTOPP_MERSENNE_TWISTER_H +#define CRYPTOPP_MERSENNE_TWISTER_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Mersenne Twister class for Monte-Carlo simulations +/// \tparam K Magic constant +/// \tparam M Period parameter +/// \tparam N Size of the state vector +/// \tparam F Multiplier constant +/// \tparam S Initial seed +/// \details Provides the MersenneTwister implementation. The class is a header-only implementation. +/// \warning MersenneTwister is suitable for simulations, where uniformaly distrubuted numbers are +/// required quickly. It should not be used for cryptographic purposes. +/// \sa MT19937, MT19937ar +/// \since Crypto++ 5.6.3 +template +class MersenneTwister : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return (S==5489 ? "MT19937ar" : (S==4537 ? "MT19937" : "MT19937x")); } + + ~MersenneTwister() {} + + /// \brief Construct a Mersenne Twister + /// \param seed 32-bit seed + /// \details Defaults to template parameter S due to changing algorithm + /// parameters over time + MersenneTwister(word32 seed = S) : m_seed(seed), m_idx(N) + { + Reset(seed); + } + + bool CanIncorporateEntropy() const {return true;} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \details MersenneTwister uses the first 32-bits of input to reseed the + /// generator. If fewer bytes are provided, then the seed is padded with 0's. + void IncorporateEntropy(const byte *input, size_t length) + { + word32 temp = 0; + ::memcpy(&temp, input, STDMIN(sizeof(temp), length)); + Reset(temp); + + // Wipe temp + SecureWipeArray(&temp, 1); + } + + /// \brief Generate random array of bytes + /// \param output byte buffer + /// \param size length of the buffer, in bytes + /// \details Bytes are written to output in big endian order. If output length + /// is not a multiple of word32, then unused bytes are not accumulated for subsequent + /// calls to GenerateBlock. Rather, the unused tail bytes are discarded, and the + /// stream is continued at the next word32 boundary from the state array. + void GenerateBlock(byte *output, size_t size) + { + // Handle word32 size blocks + word32 temp; + for (size_t i=0; i < size/4; i++, output += 4) + { + temp = NextMersenneWord(); + memcpy(output, &temp, 4); + } + + // No tail bytes + if (size%4 == 0) + { + // Wipe temp + SecureWipeArray(&temp, 1); + return; + } + + // Handle tail bytes + temp = NextMersenneWord(); + switch (size%4) + { + case 3: output[2] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 1); /* fall through */ + case 2: output[1] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 2); /* fall through */ + case 1: output[0] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 3); break; + + default: CRYPTOPP_ASSERT(0); ;; + } + + // Wipe temp + SecureWipeArray(&temp, 1); + } + + /// \brief Generate a random 32-bit word in the range min to max, inclusive + /// \returns random 32-bit word in the range min to max, inclusive + /// \details If the 32-bit candidate is not within the range, then it is discarded + /// and a new candidate is used. + word32 GenerateWord32(word32 min=0, word32 max=0xffffffffL) + { + const word32 range = max-min; + if (range == 0xffffffffL) + return NextMersenneWord(); + + const int maxBits = BitPrecision(range); + word32 value; + + do{ + value = Crop(NextMersenneWord(), maxBits); + } while (value > range); + + return value+min; + } + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to discard, rounded up to a word32 size + /// \details If n is not a multiple of word32, then unused bytes are + /// not accumulated for subsequent calls to GenerateBlock. Rather, the unused + /// tail bytes are discarded, and the stream is continued at the next + /// word32 boundary from the state array. + void DiscardBytes(size_t n) + { + for(size_t i=0; i < RoundUpToMultipleOf(n, 4U); i++) + NextMersenneWord(); + } + +protected: + + void Reset(word32 seed) + { + m_seed = seed; + m_idx = N; + + m_state[0] = seed; + for (unsigned int i = 1; i < N+1; i++) + m_state[i] = word32(F * (m_state[i-1] ^ (m_state[i-1] >> 30)) + i); + } + + /// \brief Returns the next 32-bit word from the state array + /// \returns the next 32-bit word from the state array + /// \details fetches the next word frm the state array, performs bit operations on + /// it, and then returns the value to the caller. + word32 NextMersenneWord() + { + if (m_idx >= N) { Twist(); } + + word32 temp = m_state[m_idx++]; + + temp ^= (temp >> 11); + temp ^= (temp << 7) & 0x9D2C5680; // 0x9D2C5680 (2636928640) + temp ^= (temp << 15) & 0xEFC60000; // 0xEFC60000 (4022730752) + + return temp ^ (temp >> 18); + } + + /// \brief Performs the twist operaton on the state array + void Twist() + { + static const word32 magic[2]={0x0UL, K}; + word32 kk, temp; + + CRYPTOPP_ASSERT(N >= M); + for (kk=0;kk> 1) ^ magic[temp & 0x1UL]; + } + + for (;kk> 1) ^ magic[temp & 0x1UL]; + } + + temp = (m_state[N-1] & 0x80000000)|(m_state[0] & 0x7FFFFFFF); + m_state[N-1] = m_state[M-1] ^ (temp >> 1) ^ magic[temp & 0x1UL]; + + // Reset index + m_idx = 0; + + // Wipe temp + SecureWipeArray(&temp, 1); + } + +private: + + /// \brief 32-bit word state array of size N + FixedSizeSecBlock m_state; + /// \brief the value used to seed the generator + word32 m_seed; + /// \brief the current index into the state array + word32 m_idx; +}; + +/// \brief Original MT19937 generator provided in the ACM paper. +/// \details MT19937 uses 4537 as default initial seed. +/// \sa MT19937ar, Mersenne twister: +/// a 623-dimensionally equidistributed uniform pseudo-random number generator +/// \since Crypto++ 5.6.3 +#if CRYPTOPP_DOXYGEN_PROCESSING +class MT19937 : public MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x10DCD /*69069*/, 4537> {}; +#else +typedef MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x10DCD /*69069*/, 4537> MT19937; +#endif + +/// \brief Updated MT19937 generator adapted to provide an array for initialization. +/// \details MT19937 uses 5489 as default initial seed. Use this generator when interoperating with C++11's +/// mt19937 class. +/// \sa MT19937, Mersenne Twister +/// with improved initialization +/// \since Crypto++ 5.6.3 +#if CRYPTOPP_DOXYGEN_PROCESSING +class MT19937ar : public MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x6C078965 /*1812433253*/, 5489> {}; +#else +typedef MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x6C078965 /*1812433253*/, 5489> MT19937ar; +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_MERSENNE_TWISTER_H + diff --git a/include/cryptlib/misc.h b/include/cryptlib/misc.h new file mode 100644 index 0000000..1937aaa --- /dev/null +++ b/include/cryptlib/misc.h @@ -0,0 +1,2572 @@ +// misc.h - originally written and placed in the public domain by Wei Dai + +/// \file misc.h +/// \brief Utility functions for the Crypto++ library. + +#ifndef CRYPTOPP_MISC_H +#define CRYPTOPP_MISC_H + +#include "config.h" + +#if !defined(CRYPTOPP_DOXYGEN_PROCESSING) + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(push) +# pragma warning(disable: 4146 4514) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6326) +# endif +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#include "cryptlib.h" +#include "stdcpp.h" +#include "smartptr.h" + +#ifdef _MSC_VER + #if _MSC_VER >= 1400 + // VC2005 workaround: disable declarations that conflict with winnt.h + #define _interlockedbittestandset CRYPTOPP_DISABLED_INTRINSIC_1 + #define _interlockedbittestandreset CRYPTOPP_DISABLED_INTRINSIC_2 + #define _interlockedbittestandset64 CRYPTOPP_DISABLED_INTRINSIC_3 + #define _interlockedbittestandreset64 CRYPTOPP_DISABLED_INTRINSIC_4 + #include + #undef _interlockedbittestandset + #undef _interlockedbittestandreset + #undef _interlockedbittestandset64 + #undef _interlockedbittestandreset64 + #define CRYPTOPP_FAST_ROTATE(x) 1 + #elif _MSC_VER >= 1300 + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32 | (x) == 64) + #else + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) + #endif +#elif (defined(__MWERKS__) && TARGET_CPU_PPC) || \ + (defined(__GNUC__) && (defined(_ARCH_PWR2) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_ARCH_COM))) + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) +#elif defined(__GNUC__) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) // depend on GCC's peephole optimization to generate rotate instructions + #define CRYPTOPP_FAST_ROTATE(x) 1 +#else + #define CRYPTOPP_FAST_ROTATE(x) 0 +#endif + +#ifdef __BORLANDC__ +#include +#include +#endif + +#if defined(__GNUC__) && defined(__linux__) +#define CRYPTOPP_BYTESWAP_AVAILABLE +#include +#endif + +#if defined(__BMI__) +# include +#endif // GCC and BMI + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief The maximum value of a machine word +/// \details SIZE_MAX provides the maximum value of a machine word. The value is +/// 0xffffffff on 32-bit machines, and 0xffffffffffffffff on 64-bit machines. +/// Internally, SIZE_MAX is defined as __SIZE_MAX__ if __SIZE_MAX__ is defined. If not +/// defined, then SIZE_T_MAX is tried. If neither __SIZE_MAX__ nor SIZE_T_MAX is +/// is defined, the library uses std::numeric_limits::max(). The library +/// prefers __SIZE_MAX__ because its a constexpr that is optimized well +/// by all compilers. std::numeric_limits::max() is not a constexpr, +/// and it is not always optimized well. +# define SIZE_MAX ... +#else +// Its amazing portability problems still plague this simple concept in 2015. +// http://stackoverflow.com/questions/30472731/which-c-standard-header-defines-size-max +// Avoid NOMINMAX macro on Windows. http://support.microsoft.com/en-us/kb/143208 +#ifndef SIZE_MAX +# if defined(__SIZE_MAX__) && (__SIZE_MAX__ > 0) +# define SIZE_MAX __SIZE_MAX__ +# elif defined(SIZE_T_MAX) && (SIZE_T_MAX > 0) +# define SIZE_MAX SIZE_T_MAX +# elif defined(__SIZE_TYPE__) +# define SIZE_MAX (~(__SIZE_TYPE__)0) +# else +# define SIZE_MAX ((std::numeric_limits::max)()) +# endif +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// NumericLimitsMin and NumericLimitsMax added for word128 types, +// see http://github.com/weidai11/cryptopp/issues/364 +ANONYMOUS_NAMESPACE_BEGIN +template +T NumericLimitsMin() +{ + CRYPTOPP_ASSERT(std::numeric_limits::is_specialized); + return (std::numeric_limits::min)(); +} +template +T NumericLimitsMax() +{ + CRYPTOPP_ASSERT(std::numeric_limits::is_specialized); + return (std::numeric_limits::max)(); +} +#if defined(CRYPTOPP_WORD128_AVAILABLE) +template<> +CryptoPP::word128 NumericLimitsMin() +{ + return 0; +} +template<> +CryptoPP::word128 NumericLimitsMax() +{ + return (((CryptoPP::word128)W64LIT(0xffffffffffffffff)) << 64U) | (CryptoPP::word128)W64LIT(0xffffffffffffffff); +} +#endif +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +// Forward declaration for IntToString specialization +class Integer; + +// ************** compile-time assertion *************** + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Compile time assertion +/// \param expr the expression to evaluate +/// \details Asserts the expression expr though a dummy struct. +#define CRYPTOPP_COMPILE_ASSERT(expr) { ... } +#else // CRYPTOPP_DOXYGEN_PROCESSING +template +struct CompileAssert +{ + static char dummy[2*b-1]; +}; + +#define CRYPTOPP_COMPILE_ASSERT(assertion) CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) +#if defined(CRYPTOPP_EXPORTS) || defined(CRYPTOPP_IMPORTS) +#define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) +#else +# if defined(__GNUC__) +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + static CompileAssert<(assertion)> \ + CRYPTOPP_ASSERT_JOIN(cryptopp_CRYPTOPP_ASSERT_, instance) __attribute__ ((unused)) +# else +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + static CompileAssert<(assertion)> \ + CRYPTOPP_ASSERT_JOIN(cryptopp_CRYPTOPP_ASSERT_, instance) +# endif // __GNUC__ +#endif +#define CRYPTOPP_ASSERT_JOIN(X, Y) CRYPTOPP_DO_ASSERT_JOIN(X, Y) +#define CRYPTOPP_DO_ASSERT_JOIN(X, Y) X##Y + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ************** count elements in an array *************** + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Counts elements in an array +/// \param arr an array of elements +/// \details COUNTOF counts elements in an array. On Windows COUNTOF(x) is defined +/// to _countof(x) to ensure correct results for pointers. +/// \note COUNTOF does not produce correct results with pointers, and an array must be used. +/// sizeof(x)/sizeof(x[0]) suffers the same problem. The risk is eliminated by using +/// _countof(x) on Windows. Windows will provide the immunity for other platforms. +# define COUNTOF(arr) +#else +// VS2005 added _countof +#ifndef COUNTOF +# if defined(_MSC_VER) && (_MSC_VER >= 1400) +# define COUNTOF(x) _countof(x) +# else +# define COUNTOF(x) (sizeof(x)/sizeof(x[0])) +# endif +#endif // COUNTOF +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ************** misc classes *************** + +/// \brief An Empty class +/// \details The Empty class can be used as a template parameter BASE when no base class exists. +class CRYPTOPP_DLL Empty +{ +}; + +#if !defined(CRYPTOPP_DOXYGEN_PROCESSING) +template +class CRYPTOPP_NO_VTABLE TwoBases : public BASE1, public BASE2 +{ +}; + +template +class CRYPTOPP_NO_VTABLE ThreeBases : public BASE1, public BASE2, public BASE3 +{ +}; +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \tparam T class or type +/// \brief Uses encapsulation to hide an object in derived classes +/// \details The object T is declared as protected. +template +class ObjectHolder +{ +protected: + T m_object; +}; + +/// \brief Ensures an object is not copyable +/// \details NotCopyable ensures an object is not copyable by making the +/// copy constructor and assignment operator private. Deleters are not +/// used under C++11. +/// \sa Clonable class +class NotCopyable +{ +public: + NotCopyable() {} +private: + NotCopyable(const NotCopyable &); + void operator=(const NotCopyable &); +}; + +/// \brief An object factory function +/// \tparam T class or type +/// \details NewObject overloads operator()(). +template +struct NewObject +{ + T* operator()() const {return new T;} +}; + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief A memory barrier +/// \details MEMORY_BARRIER attempts to ensure reads and writes are completed +/// in the absence of a language synchronization point. It is used by the +/// Singleton class if the compiler supports it. The barrier is provided at the +/// customary places in a double-checked initialization. +/// \details Internally, MEMORY_BARRIER uses std::atomic_thread_fence if +/// C++11 atomics are available. Otherwise, intrinsic(_ReadWriteBarrier), +/// _ReadWriteBarrier() or __asm__("" ::: "memory") is used. +#define MEMORY_BARRIER ... +#else +#if defined(CRYPTOPP_CXX11_ATOMICS) +# define MEMORY_BARRIER() std::atomic_thread_fence(std::memory_order_acq_rel) +#elif (_MSC_VER >= 1400) +# pragma intrinsic(_ReadWriteBarrier) +# define MEMORY_BARRIER() _ReadWriteBarrier() +#elif defined(__INTEL_COMPILER) +# define MEMORY_BARRIER() __memory_barrier() +#elif defined(__GNUC__) || defined(__clang__) +# define MEMORY_BARRIER() __asm__ __volatile__ ("" ::: "memory") +#else +# define MEMORY_BARRIER() +#endif +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \brief Restricts the instantiation of a class to one static object without locks +/// \tparam T the class or type +/// \tparam F the object factory for T +/// \tparam instance an instance counter for the class object +/// \details This class safely initializes a static object in a multithreaded environment. For C++03 +/// and below it will do so without using locks for portability. If two threads call Ref() at the same +/// time, they may get back different references, and one object may end up being memory leaked. This +/// is by design and it avoids a subltle initialization problem ina multithreaded environment with thread +/// local storage on early Windows platforms, like Windows XP and Windows 2003. +/// \details For C++11 and above, a standard double-checked locking pattern with thread fences +/// are used. The locks and fences are standard and do not hinder portability. +/// \details Microsoft's C++11 implementation provides the necessary primitive support on Windows Vista and +/// above when using Visual Studio 2015 (cl.exe version 19.00). If C++11 is desired, you should +/// set WINVER or _WIN32_WINNT to 0x600 (or above), and compile with Visual Studio 2015. +/// \sa Double-Checked Locking +/// is Fixed In C++11, Dynamic +/// Initialization and Destruction with Concurrency and +/// Thread Local Storage (TLS) on MSDN. +/// \since Crypto++ 5.2 +template , int instance=0> +class Singleton +{ +public: + Singleton(F objectFactory = F()) : m_objectFactory(objectFactory) {} + + // prevent this function from being inlined + CRYPTOPP_NOINLINE const T & Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const; + +private: + F m_objectFactory; +}; + +/// \brief Return a reference to the inner Singleton object +/// \tparam T the class or type +/// \tparam F the object factory for T +/// \tparam instance an instance counter for the class object +/// \details Ref() is used to create the object using the object factory. The +/// object is only created once with the limitations discussed in the class documentation. +/// \sa Double-Checked Locking is Fixed In C++11 +/// \since Crypto++ 5.2 +template + const T & Singleton::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const +{ +#if defined(CRYPTOPP_CXX11_ATOMICS) && defined(CRYPTOPP_CXX11_SYNCHRONIZATION) && defined(CRYPTOPP_CXX11_DYNAMIC_INIT) + static std::mutex s_mutex; + static std::atomic s_pObject; + + T *p = s_pObject.load(std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (p) + return *p; + + std::lock_guard lock(s_mutex); + p = s_pObject.load(std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (p) + return *p; + + T *newObject = m_objectFactory(); + s_pObject.store(newObject, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + + return *newObject; +#else + static volatile simple_ptr s_pObject; + T *p = s_pObject.m_p; + MEMORY_BARRIER(); + + if (p) + return *p; + + T *newObject = m_objectFactory(); + p = s_pObject.m_p; + MEMORY_BARRIER(); + + if (p) + { + delete newObject; + return *p; + } + + s_pObject.m_p = newObject; + MEMORY_BARRIER(); + + return *newObject; +#endif +} + +// ************** misc functions *************** + +#if (!__STDC_WANT_SECURE_LIB__ && !defined(_MEMORY_S_DEFINED)) || defined(CRYPTOPP_WANT_SECURE_LIB) + +/// \brief Bounds checking replacement for memcpy() +/// \param dest pointer to the desination memory block +/// \param sizeInBytes size of the desination memory block, in bytes +/// \param src pointer to the source memory block +/// \param count the number of bytes to copy +/// \throws InvalidArgument +/// \details ISO/IEC TR-24772 provides bounds checking interfaces for potentially +/// unsafe functions like memcpy(), strcpy() and memmove(). However, +/// not all standard libraries provides them, like Glibc. The library's +/// memcpy_s() is a near-drop in replacement. Its only a near-replacement +/// because the library's version throws an InvalidArgument on a bounds violation. +/// \details memcpy_s() and memmove_s() are guarded by __STDC_WANT_SECURE_LIB__. +/// If __STDC_WANT_SECURE_LIB__ is not defined or defined to 0, then the library +/// makes memcpy_s() and memmove_s() available. The library will also optionally +/// make the symbols available if CRYPTOPP_WANT_SECURE_LIB is defined. +/// CRYPTOPP_WANT_SECURE_LIB is in config.h, but it is disabled by default. +/// \details memcpy_s() will assert the pointers src and dest are not NULL +/// in debug builds. Passing NULL for either pointer is undefined behavior. +inline void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count) +{ + // Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 + + // Pointers must be valid; otherwise undefined behavior + CRYPTOPP_ASSERT(dest != NULLPTR); CRYPTOPP_ASSERT(src != NULLPTR); + // Restricted pointers. We want to check ranges, but it is not clear how to do it. + CRYPTOPP_ASSERT(src != dest); + // Destination buffer must be large enough to satsify request + CRYPTOPP_ASSERT(sizeInBytes >= count); + + if (count > sizeInBytes) + throw InvalidArgument("memcpy_s: buffer overflow"); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4996) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + memcpy(dest, src, count); +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif +} + +/// \brief Bounds checking replacement for memmove() +/// \param dest pointer to the desination memory block +/// \param sizeInBytes size of the desination memory block, in bytes +/// \param src pointer to the source memory block +/// \param count the number of bytes to copy +/// \throws InvalidArgument +/// \details ISO/IEC TR-24772 provides bounds checking interfaces for potentially +/// unsafe functions like memcpy(), strcpy() and memmove(). However, +/// not all standard libraries provides them, like Glibc. The library's +/// memmove_s() is a near-drop in replacement. Its only a near-replacement +/// because the library's version throws an InvalidArgument on a bounds violation. +/// \details memcpy_s() and memmove_s() are guarded by __STDC_WANT_SECURE_LIB__. +/// If __STDC_WANT_SECURE_LIB__ is not defined or defined to 0, then the library +/// makes memcpy_s() and memmove_s() available. The library will also optionally +/// make the symbols available if CRYPTOPP_WANT_SECURE_LIB is defined. +/// CRYPTOPP_WANT_SECURE_LIB is in config.h, but it is disabled by default. +/// \details memmove_s() will assert the pointers src and dest are not NULL +/// in debug builds. Passing NULL for either pointer is undefined behavior. +inline void memmove_s(void *dest, size_t sizeInBytes, const void *src, size_t count) +{ + // Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 + + // Pointers must be valid; otherwise undefined behavior + CRYPTOPP_ASSERT(dest != NULLPTR); CRYPTOPP_ASSERT(src != NULLPTR); + // Destination buffer must be large enough to satsify request + CRYPTOPP_ASSERT(sizeInBytes >= count); + + if (count > sizeInBytes) + throw InvalidArgument("memmove_s: buffer overflow"); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4996) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + memmove(dest, src, count); +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif +} + +#if __BORLANDC__ >= 0x620 +// C++Builder 2010 workaround: can't use std::memcpy_s because it doesn't allow 0 lengths +# define memcpy_s CryptoPP::memcpy_s +# define memmove_s CryptoPP::memmove_s +#endif + +#endif // __STDC_WANT_SECURE_LIB__ + +/// \brief Swaps two variables which are arrays +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \details C++03 does not provide support for std::swap(__m128i a, __m128i b) +/// because __m128i is an unsigned long long[2]. Most compilers +/// support it out of the box, but Sun Studio C++ compilers 12.2 and 12.3 do not. +/// \sa How to swap two __m128i variables +/// in C++03 given its an opaque type and an array? on Stack Overflow. +template +inline void vec_swap(T& a, T& b) +{ + // __m128i is an unsigned long long[2], and support for swapping it was + // not added until C++11. SunCC 12.1 - 12.3 fail to consume the swap; while + // SunCC 12.4 consumes it without -std=c++11. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) + T t; + t=a, a=b, b=t; +#else + std::swap(a, b); +#endif +} + +/// \brief Memory block initializer and eraser that attempts to survive optimizations +/// \param ptr pointer to the memory block being written +/// \param value the integer value to write for each byte +/// \param num the size of the source memory block, in bytes +/// \details Internally the function calls memset with the value value, and receives the +/// return value from memset as a volatile pointer. +inline void * memset_z(void *ptr, int value, size_t num) +{ +// avoid extranous warning on GCC 4.3.2 Ubuntu 8.10 +#if CRYPTOPP_GCC_VERSION >= 30001 + if (__builtin_constant_p(num) && num==0) + return ptr; +#endif + volatile void* x = memset(ptr, value, num); + return const_cast(x); +} + +/// \brief Replacement function for std::min +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \returns the minimum value based on a comparison of b \< a using operator\< +/// \details STDMIN was provided because the library could not easily use std::min or std::max in Windows or Cygwin 1.1.0 +template inline const T& STDMIN(const T& a, const T& b) +{ + return b < a ? b : a; +} + +/// \brief Replacement function for std::max +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \returns the minimum value based on a comparison of a \< b using operator\< +/// \details STDMAX was provided because the library could not easily use std::min or std::max in Windows or Cygwin 1.1.0 +template inline const T& STDMAX(const T& a, const T& b) +{ + return a < b ? b : a; +} + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4389) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-compare" +# pragma GCC diagnostic ignored "-Wstrict-overflow" +# if (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) +# pragma GCC diagnostic ignored "-Wtautological-compare" +# elif (CRYPTOPP_GCC_VERSION >= 40300) +# pragma GCC diagnostic ignored "-Wtype-limits" +# endif +#endif + +/// \brief Safe comparison of values that could be neagtive and incorrectly promoted +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the first value +/// \param b the second value +/// \returns the minimum value based on a comparison a and b using operator<. +/// \details The comparison b \< a is performed and the value returned is a's type T1. +template inline const T1 UnsignedMin(const T1& a, const T2& b) +{ + CRYPTOPP_COMPILE_ASSERT((sizeof(T1)<=sizeof(T2) && T2(-1)>0) || (sizeof(T1)>sizeof(T2) && T1(-1)>0)); + if (sizeof(T1)<=sizeof(T2)) + return b < (T2)a ? (T1)b : a; + else + return (T1)b < a ? (T1)b : a; +} + +/// \brief Tests whether a conversion from -> to is safe to perform +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param from the first value +/// \param to the second value +/// \returns true if its safe to convert from into to, false otherwise. +template +inline bool SafeConvert(T1 from, T2 &to) +{ + to = (T2)from; + if (from != to || (from > 0) != (to > 0)) + return false; + return true; +} + +/// \brief Converts a value to a string +/// \tparam T class or type +/// \param value the value to convert +/// \param base the base to use during the conversion +/// \returns the string representation of value in base. +template +std::string IntToString(T value, unsigned int base = 10) +{ + // Hack... set the high bit for uppercase. + static const unsigned int HIGH_BIT = (1U << 31); + const char CH = !!(base & HIGH_BIT) ? 'A' : 'a'; + base &= ~HIGH_BIT; + + CRYPTOPP_ASSERT(base >= 2); + if (value == 0) + return "0"; + + bool negate = false; + if (value < 0) + { + negate = true; + value = 0-value; // VC .NET does not like -a + } + std::string result; + while (value > 0) + { + T digit = value % base; + result = char((digit < 10 ? '0' : (CH - 10)) + digit) + result; + value /= base; + } + if (negate) + result = "-" + result; + return result; +} + +/// \brief Converts an unsigned value to a string +/// \param value the value to convert +/// \param base the base to use during the conversion +/// \returns the string representation of value in base. +/// \details this template function specialization was added to suppress +/// Coverity findings on IntToString() with unsigned types. +template <> CRYPTOPP_DLL +std::string IntToString(word64 value, unsigned int base); + +/// \brief Converts an Integer to a string +/// \param value the Integer to convert +/// \param base the base to use during the conversion +/// \returns the string representation of value in base. +/// \details This is a template specialization of IntToString(). Use it +/// like IntToString(): +///
+///   // Print integer in base 10
+///   Integer n...
+///   std::string s = IntToString(n, 10);
+/// 
+/// \details The string is presented with lowercase letters by default. A +/// hack is available to switch to uppercase letters without modifying +/// the function signature. +///
+///   // Print integer in base 16, uppercase letters
+///   Integer n...
+///   const unsigned int UPPER = (1 << 31);
+///   std::string s = IntToString(n, (UPPER | 16));
+template <> CRYPTOPP_DLL +std::string IntToString(Integer value, unsigned int base); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#define RETURN_IF_NONZERO(x) size_t returnedValue = x; if (returnedValue) return returnedValue + +// this version of the macro is fastest on Pentium 3 and Pentium 4 with MSVC 6 SP5 w/ Processor Pack +#define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) +// these may be faster on other CPUs/compilers +// #define GETBYTE(x, y) (unsigned int)(((x)>>(8*(y)))&255) +// #define GETBYTE(x, y) (((byte *)&(x))[y]) + +#define CRYPTOPP_GET_BYTE_AS_BYTE(x, y) byte((x)>>(8*(y))) + +/// \brief Returns the parity of a value +/// \tparam T class or type +/// \param value the value to provide the parity +/// \returns 1 if the number 1-bits in the value is odd, 0 otherwise +template +unsigned int Parity(T value) +{ + for (unsigned int i=8*sizeof(value)/2; i>0; i/=2) + value ^= value >> i; + return (unsigned int)value&1; +} + +/// \brief Returns the number of 8-bit bytes or octets required for a value +/// \tparam T class or type +/// \param value the value to test +/// \returns the minimum number of 8-bit bytes or octets required to represent a value +template +unsigned int BytePrecision(const T &value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + while (h-l > 8) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h/8; +} + +/// \brief Returns the number of bits required for a value +/// \tparam T class or type +/// \param value the value to test +/// \returns the maximum number of bits required to represent a value. +template +unsigned int BitPrecision(const T &value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + + while (h-l > 1) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h; +} + +/// Determines the number of trailing 0-bits in a value +/// \param v the 32-bit value to test +/// \returns the number of trailing 0-bits in v, starting at the least significant bit position +/// \details TrailingZeros returns the number of trailing 0-bits in v, starting at the least +/// significant bit position. The return value is undefined if there are no 1-bits set in the value v. +/// \note The function does not return 0 if no 1-bits are set because 0 collides with a 1-bit at the 0-th position. +inline unsigned int TrailingZeros(word32 v) +{ + // GCC 4.7 and VS2012 provides tzcnt on AVX2/BMI enabled processors + // We don't enable for Microsoft because it requires a runtime check. + // http://msdn.microsoft.com/en-us/library/hh977023%28v=vs.110%29.aspx + CRYPTOPP_ASSERT(v != 0); +#if defined(__BMI__) + return (unsigned int)_tzcnt_u32(v); +#elif defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 30400) + return (unsigned int)__builtin_ctz(v); +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + unsigned long result; + _BitScanForward(&result, v); + return (unsigned int)result; +#else + // from http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup + static const int MultiplyDeBruijnBitPosition[32] = + { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return MultiplyDeBruijnBitPosition[((word32)((v & -v) * 0x077CB531U)) >> 27]; +#endif +} + +/// Determines the number of trailing 0-bits in a value +/// \param v the 64-bit value to test +/// \returns the number of trailing 0-bits in v, starting at the least significant bit position +/// \details TrailingZeros returns the number of trailing 0-bits in v, starting at the least +/// significant bit position. The return value is undefined if there are no 1-bits set in the value v. +/// \note The function does not return 0 if no 1-bits are set because 0 collides with a 1-bit at the 0-th position. +inline unsigned int TrailingZeros(word64 v) +{ + // GCC 4.7 and VS2012 provides tzcnt on AVX2/BMI enabled processors + // We don't enable for Microsoft because it requires a runtime check. + // http://msdn.microsoft.com/en-us/library/hh977023%28v=vs.110%29.aspx + CRYPTOPP_ASSERT(v != 0); +#if defined(__BMI__) && defined(__x86_64__) + return (unsigned int)_tzcnt_u64(v); +#elif defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 30400) + return (unsigned int)__builtin_ctzll(v); +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && (defined(_M_X64) || defined(_M_IA64)) + unsigned long result; + _BitScanForward64(&result, v); + return (unsigned int)result; +#else + return word32(v) ? TrailingZeros(word32(v)) : 32 + TrailingZeros(word32(v>>32)); +#endif +} + +/// \brief Truncates the value to the specified number of bits. +/// \tparam T class or type +/// \param value the value to truncate or mask +/// \param bits the number of bits to truncate or mask +/// \returns the value truncated to the specified number of bits, starting at the least +/// significant bit position +/// \details This function masks the low-order bits of value and returns the result. The +/// mask is created with (1 << bits) - 1. +template +inline T Crop(T value, size_t bits) +{ + if (bits < 8*sizeof(value)) + return T(value & ((T(1) << bits) - 1)); + else + return value; +} + +/// \brief Returns the number of 8-bit bytes or octets required for the specified number of bits +/// \param bitCount the number of bits +/// \returns the minimum number of 8-bit bytes or octets required by bitCount +/// \details BitsToBytes is effectively a ceiling function based on 8-bit bytes. +inline size_t BitsToBytes(size_t bitCount) +{ + return ((bitCount+7)/(8)); +} + +/// \brief Returns the number of words required for the specified number of bytes +/// \param byteCount the number of bytes +/// \returns the minimum number of words required by byteCount +/// \details BytesToWords is effectively a ceiling function based on WORD_SIZE. +/// WORD_SIZE is defined in config.h +inline size_t BytesToWords(size_t byteCount) +{ + return ((byteCount+WORD_SIZE-1)/WORD_SIZE); +} + +/// \brief Returns the number of words required for the specified number of bits +/// \param bitCount the number of bits +/// \returns the minimum number of words required by bitCount +/// \details BitsToWords is effectively a ceiling function based on WORD_BITS. +/// WORD_BITS is defined in config.h +inline size_t BitsToWords(size_t bitCount) +{ + return ((bitCount+WORD_BITS-1)/(WORD_BITS)); +} + +/// \brief Returns the number of double words required for the specified number of bits +/// \param bitCount the number of bits +/// \returns the minimum number of double words required by bitCount +/// \details BitsToDwords is effectively a ceiling function based on 2*WORD_BITS. +/// WORD_BITS is defined in config.h +inline size_t BitsToDwords(size_t bitCount) +{ + return ((bitCount+2*WORD_BITS-1)/(2*WORD_BITS)); +} + +/// Performs an XOR of a buffer with a mask +/// \param buf the buffer to XOR with the mask +/// \param mask the mask to XOR with the buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively visits each element in the buffers and performs +/// buf[i] ^= mask[i]. buf and mask must be of equal size. +CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *buf, const byte *mask, size_t count); + +/// Performs an XOR of an input buffer with a mask and stores the result in an output buffer +/// \param output the destination buffer +/// \param input the source buffer to XOR with the mask +/// \param mask the mask buffer to XOR with the input buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively visits each element in the buffers and performs +/// output[i] = input[i] ^ mask[i]. output, input and mask must be of equal size. +CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *output, const byte *input, const byte *mask, size_t count); + +/// \brief Performs a near constant-time comparison of two equally sized buffers +/// \param buf1 the first buffer +/// \param buf2 the second buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively performs an XOR of the elements in two equally sized buffers +/// and retruns a result based on the XOR operation. The function is near constant-time because +/// CPU micro-code timings could affect the "constant-ness". Calling code is responsible for +/// mitigating timing attacks if the buffers are not equally sized. +/// \sa ModPowerOf2 +CRYPTOPP_DLL bool CRYPTOPP_API VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count); + +/// \brief Tests whether a value is a power of 2 +/// \param value the value to test +/// \returns true if value is a power of 2, false otherwise +/// \details The function creates a mask of value - 1 and returns the result of +/// an AND operation compared to 0. If value is 0 or less than 0, then the function returns false. +template +inline bool IsPowerOf2(const T &value) +{ + return value > 0 && (value & (value-1)) == 0; +} + +#if defined(__BMI__) +template <> +inline bool IsPowerOf2(const word32 &value) +{ + return value > 0 && _blsr_u32(value) == 0; +} + +# if defined(__x86_64__) +template <> +inline bool IsPowerOf2(const word64 &value) +{ + return value > 0 && _blsr_u64(value) == 0; +} +# endif // __x86_64__ +#endif // __BMI__ + +/// \brief Performs a saturating subtract clamped at 0 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the minuend +/// \param b the subtrahend +/// \returns the difference produced by the saturating subtract +/// \details Saturating arithmetic restricts results to a fixed range. Results that are less than 0 are clamped at 0. +/// \details Use of saturating arithmetic in places can be advantageous because it can +/// avoid a branch by using an instruction like a conditional move (CMOVE). +template +inline T1 SaturatingSubtract(const T1 &a, const T2 &b) +{ + // Generated ASM of a typical clamp, http://gcc.gnu.org/ml/gcc-help/2014-10/msg00112.html + return T1((a > b) ? (a - b) : 0); +} + +/// \brief Performs a saturating subtract clamped at 1 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the minuend +/// \param b the subtrahend +/// \returns the difference produced by the saturating subtract +/// \details Saturating arithmetic restricts results to a fixed range. Results that are less than +/// 1 are clamped at 1. +/// \details Use of saturating arithmetic in places can be advantageous because it can +/// avoid a branch by using an instruction like a conditional move (CMOVE). +template +inline T1 SaturatingSubtract1(const T1 &a, const T2 &b) +{ + // Generated ASM of a typical clamp, http://gcc.gnu.org/ml/gcc-help/2014-10/msg00112.html + return T1((a > b) ? (a - b) : 1); +} + +/// \brief Reduces a value to a power of 2 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the first value +/// \param b the second value +/// \returns ModPowerOf2() returns a & (b-1). b must be a power of 2. +/// Use IsPowerOf2() to determine if b is a suitable candidate. +/// \sa IsPowerOf2 +template +inline T2 ModPowerOf2(const T1 &a, const T2 &b) +{ + CRYPTOPP_ASSERT(IsPowerOf2(b)); + // Coverity finding CID 170383 Overflowed return value (INTEGER_OVERFLOW) + return T2(a) & SaturatingSubtract(b,1U); +} + +/// \brief Rounds a value down to a multiple of a second value +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param n the value to reduce +/// \param m the value to reduce \n to to a multiple +/// \returns the possibly unmodified value \n +/// \details RoundDownToMultipleOf is effectively a floor function based on m. The function returns +/// the value n - n\%m. If n is a multiple of m, then the original value is returned. +/// \note T1 and T2 should be usigned arithmetic types. If T1 or +/// T2 is signed, then the value should be non-negative. The library asserts in +/// debug builds when practical, but allows you to perform the operation in release builds. +template +inline T1 RoundDownToMultipleOf(const T1 &n, const T2 &m) +{ + // http://github.com/weidai11/cryptopp/issues/364 +#if !defined(CRYPTOPP_APPLE_CLANG_VERSION) || (CRYPTOPP_APPLE_CLANG_VERSION >= 80000) + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); +#endif + + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || n > 0); + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || m > 0); + + if (IsPowerOf2(m)) + return n - ModPowerOf2(n, m); + else + return n - n%m; +} + +/// \brief Rounds a value up to a multiple of a second value +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param n the value to reduce +/// \param m the value to reduce \n to to a multiple +/// \returns the possibly unmodified value \n +/// \details RoundUpToMultipleOf is effectively a ceiling function based on m. The function +/// returns the value n + n\%m. If n is a multiple of m, then the original value is +/// returned. If the value n would overflow, then an InvalidArgument exception is thrown. +/// \note T1 and T2 should be usigned arithmetic types. If T1 or +/// T2 is signed, then the value should be non-negative. The library asserts in +/// debug builds when practical, but allows you to perform the operation in release builds. +template +inline T1 RoundUpToMultipleOf(const T1 &n, const T2 &m) +{ + // http://github.com/weidai11/cryptopp/issues/364 +#if !defined(CRYPTOPP_APPLE_CLANG_VERSION) || (CRYPTOPP_APPLE_CLANG_VERSION >= 80000) + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); +#endif + + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || n > 0); + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || m > 0); + + if (NumericLimitsMax() - m + 1 < n) + throw InvalidArgument("RoundUpToMultipleOf: integer overflow"); + return RoundDownToMultipleOf(T1(n+m-1), m); +} + +/// \brief Returns the minimum alignment requirements of a type +/// \tparam T class or type +/// \returns the minimum alignment requirements of T, in bytes +/// \details Internally the function calls C++11's alignof if available. If not available, +/// then the function uses compiler specific extensions such as __alignof and +/// _alignof_. If an extension is not available, then the function uses +/// __BIGGEST_ALIGNMENT__ if __BIGGEST_ALIGNMENT__ is smaller than sizeof(T). +/// sizeof(T) is used if all others are not available. +/// In all cases, if CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS is defined, then the +/// function returns 1. +template +inline unsigned int GetAlignmentOf() +{ +// GCC 4.6 (circa 2008) and above aggressively uses vectorization. +#if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) + if (sizeof(T) < 16) + return 1; +#endif + +#if defined(CRYPTOPP_CXX11_ALIGNOF) + return alignof(T); +#elif (_MSC_VER >= 1300) + return __alignof(T); +#elif defined(__GNUC__) + return __alignof__(T); +#elif CRYPTOPP_BOOL_SLOW_WORD64 + return UnsignedMin(4U, sizeof(T)); +#else +# if __BIGGEST_ALIGNMENT__ + if (__BIGGEST_ALIGNMENT__ < sizeof(T)) + return __BIGGEST_ALIGNMENT__; + else +# endif + return sizeof(T); +#endif +} + +/// \brief Determines whether ptr is aligned to a minimum value +/// \param ptr the pointer being checked for alignment +/// \param alignment the alignment value to test the pointer against +/// \returns true if ptr is aligned on at least alignment boundary, false otherwise +/// \details Internally the function tests whether alignment is 1. If so, the function returns true. +/// If not, then the function effectively performs a modular reduction and returns true if the residue is 0 +inline bool IsAlignedOn(const void *ptr, unsigned int alignment) +{ + return alignment==1 || (IsPowerOf2(alignment) ? ModPowerOf2((size_t)ptr, alignment) == 0 : (size_t)ptr % alignment == 0); +} + +/// \brief Determines whether ptr is minimally aligned +/// \tparam T class or type +/// \param ptr the pointer to check for alignment +/// \returns true if ptr is aligned to at least T boundary, false otherwise +/// \details Internally the function calls IsAlignedOn with a second parameter of GetAlignmentOf +template +inline bool IsAligned(const void *ptr) +{ + return IsAlignedOn(ptr, GetAlignmentOf()); +} + +#if defined(CRYPTOPP_LITTLE_ENDIAN) + typedef LittleEndian NativeByteOrder; +#elif defined(CRYPTOPP_BIG_ENDIAN) + typedef BigEndian NativeByteOrder; +#else +# error "Unable to determine endian-ness" +#endif + +/// \brief Returns NativeByteOrder as an enumerated ByteOrder value +/// \returns LittleEndian if the native byte order is little-endian, and BigEndian if the +/// native byte order is big-endian +/// \details NativeByteOrder is a typedef depending on the platform. If CRYPTOPP_LITTLE_ENDIAN is +/// set in config.h, then GetNativeByteOrder returns LittleEndian. If +/// CRYPTOPP_BIG_ENDIAN is set, then GetNativeByteOrder returns BigEndian. +/// \note There are other byte orders besides little- and big-endian, and they include bi-endian +/// and PDP-endian. If a system is neither little-endian nor big-endian, then a compile time +/// error occurs. +inline ByteOrder GetNativeByteOrder() +{ + return NativeByteOrder::ToEnum(); +} + +/// \brief Determines whether order follows native byte ordering +/// \param order the ordering being tested against native byte ordering +/// \returns true if order follows native byte ordering, false otherwise +inline bool NativeByteOrderIs(ByteOrder order) +{ + return order == GetNativeByteOrder(); +} + +/// \brief Returns the direction the cipher is being operated +/// \tparam T class or type +/// \param obj the cipher object being queried +/// \returns ENCRYPTION if the cipher obj is being operated in its forward direction, +/// DECRYPTION otherwise +/// \details A cipher can be operated in a "forward" direction (encryption) or a "reverse" +/// direction (decryption). The operations do not have to be symmetric, meaning a second +/// application of the transformation does not necessariy return the original message. +/// That is, E(D(m)) may not equal E(E(m)); and D(E(m)) may not +/// equal D(D(m)). +template +inline CipherDir GetCipherDir(const T &obj) +{ + return obj.IsForwardTransformation() ? ENCRYPTION : DECRYPTION; +} + +/// \brief Attempts to reclaim unused memory +/// \throws bad_alloc +/// \details In the normal course of running a program, a request for memory normally succeeds. If a +/// call to AlignedAllocate or UnalignedAllocate fails, then CallNewHandler is called in +/// an effort to recover. Internally, CallNewHandler calls set_new_handler(NULLPTR) in an effort +/// to free memory. There is no guarantee CallNewHandler will be able to procure more memory so +/// an allocation succeeds. If the call to set_new_handler fails, then CallNewHandler throws +/// a bad_alloc exception. +CRYPTOPP_DLL void CRYPTOPP_API CallNewHandler(); + +/// \brief Performs an addition with carry on a block of bytes +/// \param inout the byte block +/// \param size the size of the block, in bytes +/// \details Performs an addition with carry by adding 1 on a block of bytes starting at the least +/// significant byte. Once carry is 0, the function terminates and returns to the caller. +/// \note The function is not constant time because it stops processing when the carry is 0. +inline void IncrementCounterByOne(byte *inout, unsigned int size) +{ + CRYPTOPP_ASSERT(inout != NULLPTR); CRYPTOPP_ASSERT(size < INT_MAX); + for (int i=int(size-1), carry=1; i>=0 && carry; i--) + carry = !++inout[i]; +} + +/// \brief Performs an addition with carry on a block of bytes +/// \param output the destination block of bytes +/// \param input the source block of bytes +/// \param size the size of the block +/// \details Performs an addition with carry on a block of bytes starting at the least significant +/// byte. Once carry is 0, the remaining bytes from input are copied to output using memcpy. +/// \details The function is close to near-constant time because it operates on all the bytes in the blocks. +inline void IncrementCounterByOne(byte *output, const byte *input, unsigned int size) +{ + CRYPTOPP_ASSERT(output != NULLPTR); CRYPTOPP_ASSERT(input != NULLPTR); CRYPTOPP_ASSERT(size < INT_MAX); + + int i, carry; + for (i=int(size-1), carry=1; i>=0 && carry; i--) + carry = ((output[i] = input[i]+1) == 0); + memcpy_s(output, size, input, size_t(i)+1); +} + +/// \brief Performs a branchless swap of values a and b if condition c is true +/// \tparam T class or type +/// \param c the condition to perform the swap +/// \param a the first value +/// \param b the second value +template +inline void ConditionalSwap(bool c, T &a, T &b) +{ + T t = c * (a ^ b); + a ^= t; + b ^= t; +} + +/// \brief Performs a branchless swap of pointers a and b if condition c is true +/// \tparam T class or type +/// \param c the condition to perform the swap +/// \param a the first pointer +/// \param b the second pointer +template +inline void ConditionalSwapPointers(bool c, T &a, T &b) +{ + ptrdiff_t t = size_t(c) * (a - b); + a -= t; + b += t; +} + +// see http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html +// and http://www.securecoding.cert.org/confluence/display/cplusplus/MSC06-CPP.+Be+aware+of+compiler+optimization+when+dealing+with+sensitive+data + +/// \brief Sets each element of an array to 0 +/// \tparam T class or type +/// \param buf an array of elements +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function attempts to survive optimizations and dead code removal +template +void SecureWipeBuffer(T *buf, size_t n) +{ + // GCC 4.3.2 on Cygwin optimizes away the first store if this loop is done in the forward direction + volatile T *p = buf+n; + while (n--) + *(--p) = 0; +} + +#if (_MSC_VER >= 1400 || defined(__GNUC__)) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86) + +/// \brief Sets each byte of an array to 0 +/// \param buf an array of bytes +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(byte *buf, size_t n) +{ + volatile byte *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosb" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosb((byte *)(size_t)p, 0, n); +#endif +} + +/// \brief Sets each 16-bit element of an array to 0 +/// \param buf an array of 16-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word16 *buf, size_t n) +{ + volatile word16 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosw" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosw((word16 *)(size_t)p, 0, n); +#endif +} + +/// \brief Sets each 32-bit element of an array to 0 +/// \param buf an array of 32-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word32 *buf, size_t n) +{ + volatile word32 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosl" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosd((unsigned long *)(size_t)p, 0, n); +#endif +} + +/// \brief Sets each 64-bit element of an array to 0 +/// \param buf an array of 64-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word64 *buf, size_t n) +{ +#if CRYPTOPP_BOOL_X64 + volatile word64 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosq" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosq((word64 *)(size_t)p, 0, n); +#endif +#else + SecureWipeBuffer((word32 *)buf, 2*n); +#endif +} + +#endif // #if (_MSC_VER >= 1400 || defined(__GNUC__)) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86) + +#if (_MSC_VER >= 1700) && defined(_M_ARM) +template<> inline void SecureWipeBuffer(byte *buf, size_t n) +{ + char *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store8(--p, 0); +} + +template<> inline void SecureWipeBuffer(word16 *buf, size_t n) +{ + short *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store16(--p, 0); +} + +template<> inline void SecureWipeBuffer(word32 *buf, size_t n) +{ + int *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store32(--p, 0); +} + +template<> inline void SecureWipeBuffer(word64 *buf, size_t n) +{ + __int64 *p = reinterpret_cast<__int64*>(buf+n); + while (n--) + __iso_volatile_store64(--p, 0); +} +#endif + +/// \brief Sets each element of an array to 0 +/// \tparam T class or type +/// \param buf an array of elements +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function attempts to survive optimizations and dead code removal. +template +inline void SecureWipeArray(T *buf, size_t n) +{ + if (sizeof(T) % 8 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer((word64 *)(void *)buf, n * (sizeof(T)/8)); + else if (sizeof(T) % 4 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer((word32 *)(void *)buf, n * (sizeof(T)/4)); + else if (sizeof(T) % 2 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer((word16 *)(void *)buf, n * (sizeof(T)/2)); + else + SecureWipeBuffer((byte *)(void *)buf, n * sizeof(T)); +} + +/// \brief Converts a wide character C-string to a multibyte string +/// \param str C-string consisting of wide characters +/// \param throwOnError flag indicating the function should throw on error +/// \returns str converted to a multibyte string or an empty string. +/// \details StringNarrow() converts a wide string to a narrow string using C++ std::wcstombs() under +/// the executing thread's locale. A locale must be set before using this function, and it can be +/// set with std::setlocale() if needed. Upon success, the converted string is returned. +/// \details Upon failure with throwOnError as false, the function returns an empty string. If +/// throwOnError as true, the function throws an InvalidArgument() exception. +/// \note If you try to convert, say, the Chinese character for "bone" from UTF-16 (0x9AA8) to UTF-8 +/// (0xE9 0xAA 0xA8), then you must ensure the locale is available. If the locale is not available, +/// then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::string StringNarrow(const wchar_t *str, bool throwOnError = true); + +/// \brief Converts a multibyte C-string to a wide character string +/// \param str C-string consisting of wide characters +/// \param throwOnError flag indicating the function should throw on error +/// \returns str converted to a multibyte string or an empty string. +/// \details StringWiden() converts a narrow string to a wide string using C++ std::mbstowcs() under +/// the executing thread's locale. A locale must be set before using this function, and it can be +/// set with std::setlocale() if needed. Upon success, the converted string is returned. +/// \details Upon failure with throwOnError as false, the function returns an empty string. If +/// throwOnError as true, the function throws an InvalidArgument() exception. +/// \note If you try to convert, say, the Chinese character for "bone" from UTF-8 (0xE9 0xAA 0xA8) +/// to UTF-16 (0x9AA8), then you must ensure the locale is available. If the locale is not available, +/// then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::wstring StringWiden(const char *str, bool throwOnError = true); + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING + +/// \brief Allocates a buffer on 16-byte boundary +/// \param size the size of the buffer +/// \details AlignedAllocate is primarily used when the data will be proccessed by MMX, SSE2 and NEON +/// instructions. The assembly language routines rely on the alignment. If the alignment is not +/// respected, then a SIGBUS could be generated on Unix and Linux, and an +/// EXCEPTION_DATATYPE_MISALIGNMENT could be generated on Windows. +/// \note AlignedAllocate and AlignedDeallocate are available when CRYPTOPP_BOOL_ALIGN16 is +/// defined. CRYPTOPP_BOOL_ALIGN16 is defined in config.h +CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size); + +/// \brief Frees a buffer allocated with AlignedAllocate +/// \param ptr the buffer to free +/// \note AlignedAllocate and AlignedDeallocate are available when CRYPTOPP_BOOL_ALIGN16 is +/// defined. CRYPTOPP_BOOL_ALIGN16 is defined in config.h +CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr); + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_BOOL_ALIGN16 +CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size); +CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr); +#endif // CRYPTOPP_BOOL_ALIGN16 + +/// \brief Allocates a buffer +/// \param size the size of the buffer +CRYPTOPP_DLL void * CRYPTOPP_API UnalignedAllocate(size_t size); + +/// \brief Frees a buffer allocated with UnalignedAllocate +/// \param ptr the buffer to free +CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr); + +// ************** rotate functions *************** + +/// \brief Performs a left rotate +/// \tparam R the number of bit positions to rotate the value +/// \tparam T the word type +/// \param x the value to rotate +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details R must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount R is outside the range. +/// \details Use rotlConstant when the rotate amount is constant. The template function was added +/// because Clang did not propagate the constant when passed as a function parameter. Clang's +/// need for a constexpr meant rotlFixed failed to compile on occassion. +/// \note rotlConstant attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 6.0 +template inline T rotlConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(R < THIS_SIZE); + return T((x<>(-R&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam R the number of bit positions to rotate the value +/// \tparam T the word type +/// \param x the value to rotate +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details R must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount R is outside the range. +/// \details Use rotrConstant when the rotate amount is constant. The template function was added +/// because Clang did not propagate the constant when passed as a function parameter. Clang's +/// need for a constexpr meant rotrFixed failed to compile on occassion. +/// \note rotrConstant attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +template inline T rotrConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(R < THIS_SIZE); + return T((x >> R)|(x<<(-R&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount y is outside the range. +/// \note rotlFixed attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. New code should use rotlConstant, which accepts the rotate amount as a +/// template parameter. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 6.0 +template inline T rotlFixed(T x, unsigned int y) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(y < THIS_SIZE); + return T((x<>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount y is outside the range. +/// \note rotrFixed attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. New code should use rotrConstant, which accepts the rotate amount as a +/// template parameter. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrFixed(T x, unsigned int y) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(y < THIS_SIZE); + return T((x >> y)|(x<<(-y&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount y is outside the range. +/// \note rotlVariable attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotlVariable(T x, unsigned int y) +{ + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(y < THIS_SIZE); + return T((x<>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount y is outside the range. +/// \note rotrVariable attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrVariable(T x, unsigned int y) +{ + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(y < THIS_SIZE); + return T((x>>y)|(x<<(-y&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will use either rotate IMM or rotate REG. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotlMod(T x, unsigned int y) +{ + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + return T((x<<(y&MASK))|(x>>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will use either rotate IMM or rotate REG. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrMod(T x, unsigned int y) +{ + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + return T((x>>(y&MASK))|(x<<(-y&MASK))); +} + +#ifdef _MSC_VER + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _lrotl(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _lrotr(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _lrotl(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _lrotr(x, static_cast(y)); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + y %= 8*sizeof(x); + return _lrotl(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + y %= 8*sizeof(x); + return _lrotr(x, static_cast(y)); +} + +#endif // #ifdef _MSC_VER + +#if (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) +// Intel C++ Compiler 10.0 calls a function instead of using the rotate instruction when using these instructions + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotlFixed(word64 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotl64(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotrFixed(word64 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotlVariable(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _rotl64(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotrVariable(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word64 rotlMod(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotl64(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word64 rotrMod(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +#endif // #if _MSC_VER >= 1310 + +#if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) +// Intel C++ Compiler 10.0 gives undefined externals with these +template<> inline word16 rotlFixed(word16 x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrFixed(word16 x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotr16(x, static_cast(y)); +} + +template<> inline word16 rotlVariable(word16 x, unsigned int y) +{ + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrVariable(word16 x, unsigned int y) +{ + return _rotr16(x, static_cast(y)); +} + +template<> inline word16 rotlMod(word16 x, unsigned int y) +{ + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrMod(word16 x, unsigned int y) +{ + return _rotr16(x, static_cast(y)); +} + +template<> inline byte rotlFixed(byte x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrFixed(byte x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotr8(x, static_cast(y)); +} + +template<> inline byte rotlVariable(byte x, unsigned int y) +{ + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrVariable(byte x, unsigned int y) +{ + return _rotr8(x, static_cast(y)); +} + +template<> inline byte rotlMod(byte x, unsigned int y) +{ + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrMod(byte x, unsigned int y) +{ + return _rotr8(x, static_cast(y)); +} + +#endif // #if _MSC_VER >= 1400 + +#if (defined(__MWERKS__) && TARGET_CPU_PPC) + +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return y ? __rlwinm(x,y,0,31) : x; +} + +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return y ? __rlwinm(x,32-y,0,31) : x; +} + +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return (__rlwnm(x,32-y,0,31)); +} + +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,32-y,0,31)); +} + +#endif // #if (defined(__MWERKS__) && TARGET_CPU_PPC) + +// ************** endian reversal *************** + +/// \brief Gets a byte from a value +/// \param order the ByteOrder of the value +/// \param value the value to retrieve the byte +/// \param index the location of the byte to retrieve +template +inline unsigned int GetByte(ByteOrder order, T value, unsigned int index) +{ + if (order == LITTLE_ENDIAN_ORDER) + return GETBYTE(value, index); + else + return GETBYTE(value, sizeof(T)-index-1); +} + +/// \brief Reverses bytes in a 8-bit value +/// \param value the 8-bit value to reverse +/// \note ByteReverse returns the value passed to it since there is nothing to reverse +inline byte ByteReverse(byte value) +{ + return value; +} + +/// \brief Reverses bytes in a 16-bit value +/// \param value the 16-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function performs a 8-bit rotate on the word16 +inline word16 ByteReverse(word16 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_16(value); +#elif (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) + return _byteswap_ushort(value); +#else + return rotlFixed(value, 8U); +#endif +} + +/// \brief Reverses bytes in a 32-bit value +/// \param value the 32-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses a combination of rotates on the word32 +inline word32 ByteReverse(word32 value) +{ +#if defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_32(value); +#elif defined(__MWERKS__) && TARGET_CPU_PPC + return (word32)__lwbrx(&value,0); +#elif (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) + return _byteswap_ulong(value); +#elif CRYPTOPP_FAST_ROTATE(32) && !defined(__xlC__) + // 5 instructions with rotate instruction, 9 without + return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); +#else + // 6 instructions with rotate instruction, 8 without + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + +/// \brief Reverses bytes in a 64-bit value +/// \param value the 64-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses a combination of rotates on the word64 +inline word64 ByteReverse(word64 value) +{ +#if defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__x86_64__) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_64(value); +#elif (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) + return _byteswap_uint64(value); +#elif CRYPTOPP_BOOL_SLOW_WORD64 + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); +#else + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); + return rotlFixed(value, 32U); +#endif +} + +/// \brief Reverses bits in a 8-bit value +/// \param value the 8-bit value to reverse +/// \details BitReverse performs a combination of shifts on the byte +inline byte BitReverse(byte value) +{ + value = byte((value & 0xAA) >> 1) | byte((value & 0x55) << 1); + value = byte((value & 0xCC) >> 2) | byte((value & 0x33) << 2); + return rotlFixed(value, 4U); +} + +/// \brief Reverses bits in a 16-bit value +/// \param value the 16-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word16 +inline word16 BitReverse(word16 value) +{ + value = word16((value & 0xAAAA) >> 1) | word16((value & 0x5555) << 1); + value = word16((value & 0xCCCC) >> 2) | word16((value & 0x3333) << 2); + value = word16((value & 0xF0F0) >> 4) | word16((value & 0x0F0F) << 4); + return ByteReverse(value); +} + +/// \brief Reverses bits in a 32-bit value +/// \param value the 32-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word32 +inline word32 BitReverse(word32 value) +{ + value = word32((value & 0xAAAAAAAA) >> 1) | word32((value & 0x55555555) << 1); + value = word32((value & 0xCCCCCCCC) >> 2) | word32((value & 0x33333333) << 2); + value = word32((value & 0xF0F0F0F0) >> 4) | word32((value & 0x0F0F0F0F) << 4); + return ByteReverse(value); +} + +/// \brief Reverses bits in a 64-bit value +/// \param value the 64-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word64 +inline word64 BitReverse(word64 value) +{ +#if CRYPTOPP_BOOL_SLOW_WORD64 + return (word64(BitReverse(word32(value))) << 32) | BitReverse(word32(value>>32)); +#else + value = word64((value & W64LIT(0xAAAAAAAAAAAAAAAA)) >> 1) | word64((value & W64LIT(0x5555555555555555)) << 1); + value = word64((value & W64LIT(0xCCCCCCCCCCCCCCCC)) >> 2) | word64((value & W64LIT(0x3333333333333333)) << 2); + value = word64((value & W64LIT(0xF0F0F0F0F0F0F0F0)) >> 4) | word64((value & W64LIT(0x0F0F0F0F0F0F0F0F)) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a value +/// \param value the value to reverse +/// \details The template overload of BitReverse operates on signed and unsigned values. +/// Internally the size of T is checked, and then value is cast to a byte, +/// word16, word32 or word64. After the cast, the appropriate BitReverse +/// overload is called. +template +inline T BitReverse(T value) +{ + if (sizeof(T) == 1) + return (T)BitReverse((byte)value); + else if (sizeof(T) == 2) + return (T)BitReverse((word16)value); + else if (sizeof(T) == 4) + return (T)BitReverse((word32)value); + else + { + CRYPTOPP_ASSERT(sizeof(T) == 8); + return (T)BitReverse((word64)value); + } +} + +/// \brief Reverses bytes in a value depending upon endianness +/// \tparam T the class or type +/// \param order the ByteOrder of the data +/// \param value the value to conditionally reverse +/// \details Internally, the ConditionalByteReverse calls NativeByteOrderIs. +/// If order matches native byte order, then the original value is returned. +/// If not, then ByteReverse is called on the value before returning to the caller. +template +inline T ConditionalByteReverse(ByteOrder order, T value) +{ + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +/// \brief Reverses bytes in an element from an array of elements +/// \tparam T the class or type +/// \param out the output array of elements +/// \param in the input array of elements +/// \param byteCount the total number of bytes in the array +/// \details Internally, ByteReverse visits each element in the in array +/// calls ByteReverse on it, and writes the result to out. +/// \details ByteReverse does not process tail byes, or bytes that are +/// not part of a full element. If T is int (and int is 4 bytes), then +/// byteCount = 10 means only the first 2 elements or 8 bytes are +/// reversed. +/// \details The follwoing program should help illustrate the behavior. +///
vector v1, v2;
+///
+/// v1.push_back(1);
+/// v1.push_back(2);
+/// v1.push_back(3);
+/// v1.push_back(4);
+///
+/// v2.resize(v1.size());
+/// ByteReverse(&v2[0], &v1[0], 16);
+///
+/// cout << "V1: ";
+/// for(unsigned int i = 0; i < v1.size(); i++)
+///   cout << std::hex << v1[i] << " ";
+/// cout << endl;
+///
+/// cout << "V2: ";
+/// for(unsigned int i = 0; i < v2.size(); i++)
+///   cout << std::hex << v2[i] << " ";
+/// cout << endl;
+/// The program above results in the follwoing output. +///
V1: 00000001 00000002 00000003 00000004
+/// V2: 01000000 02000000 03000000 04000000
+/// \sa ConditionalByteReverse +template +void ByteReverse(T *out, const T *in, size_t byteCount) +{ + CRYPTOPP_ASSERT(byteCount % sizeof(T) == 0); + size_t count = byteCount/sizeof(T); + for (size_t i=0; ibyteCount = 10 means only the first 2 elements or 8 bytes are +/// reversed. +/// \sa ByteReverse +template +inline void ConditionalByteReverse(ByteOrder order, T *out, const T *in, size_t byteCount) +{ + if (!NativeByteOrderIs(order)) + ByteReverse(out, in, byteCount); + else if (in != out) + memcpy_s(out, byteCount, in, byteCount); +} + +template +inline void GetUserKey(ByteOrder order, T *out, size_t outlen, const byte *in, size_t inlen) +{ + const size_t U = sizeof(T); + CRYPTOPP_ASSERT(inlen <= outlen*U); + memcpy_s(out, outlen*U, in, inlen); + memset_z((byte *)out+inlen, 0, outlen*U-inlen); + ConditionalByteReverse(order, out, out, RoundUpToMultipleOf(inlen, U)); +} + +#ifndef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS +inline byte UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const byte *) +{ + CRYPTOPP_UNUSED(order); + return block[0]; +} + +inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word16 *) +{ + return (order == BIG_ENDIAN_ORDER) + ? block[1] | (block[0] << 8) + : block[0] | (block[1] << 8); +} + +inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word32 *) +{ + return (order == BIG_ENDIAN_ORDER) + ? word32(block[3]) | (word32(block[2]) << 8) | (word32(block[1]) << 16) | (word32(block[0]) << 24) + : word32(block[0]) | (word32(block[1]) << 8) | (word32(block[2]) << 16) | (word32(block[3]) << 24); +} + +inline word64 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word64 *) +{ + return (order == BIG_ENDIAN_ORDER) + ? + (word64(block[7]) | + (word64(block[6]) << 8) | + (word64(block[5]) << 16) | + (word64(block[4]) << 24) | + (word64(block[3]) << 32) | + (word64(block[2]) << 40) | + (word64(block[1]) << 48) | + (word64(block[0]) << 56)) + : + (word64(block[0]) | + (word64(block[1]) << 8) | + (word64(block[2]) << 16) | + (word64(block[3]) << 24) | + (word64(block[4]) << 32) | + (word64(block[5]) << 40) | + (word64(block[6]) << 48) | + (word64(block[7]) << 56)); +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, byte value, const byte *xorBlock) +{ + CRYPTOPP_UNUSED(order); + block[0] = (byte)(xorBlock ? (value ^ xorBlock[0]) : value); +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word16 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + } + } +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word32 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + } + } +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word64 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + } + } +} +#endif // #ifndef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param block the byte buffer to be processed +/// \returns the word in the specified byte order +/// \details GetWord() provides alternate read access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +/// \details An example of reading two word32 values from a block of memory is shown below. w +/// will be 0x03020100. +///
+///    word32 w;
+///    byte buffer[4] = {0,1,2,3};
+///    w = GetWord(false, LITTLE_ENDIAN_ORDER, buffer);
+/// 
+template +inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) +{ + CRYPTOPP_UNUSED(assumeAligned); +#ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS + return ConditionalByteReverse(order, *reinterpret_cast((const void *)block)); +#else + T temp; + memcpy(&temp, block, sizeof(T)); + return ConditionalByteReverse(order, temp); +#endif +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param result the word in the specified byte order +/// \param block the byte buffer to be processed +/// \details GetWord() provides alternate read access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +/// \details An example of reading two word32 values from a block of memory is shown below. w +/// will be 0x03020100. +///
+///    word32 w;
+///    byte buffer[4] = {0,1,2,3};
+///    w = GetWord(false, LITTLE_ENDIAN_ORDER, buffer);
+/// 
+template +inline void GetWord(bool assumeAligned, ByteOrder order, T &result, const byte *block) +{ + result = GetWord(assumeAligned, order, block); +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param block the destination byte buffer +/// \param value the word in the specified byte order +/// \param xorBlock an optional byte buffer to xor +/// \details PutWord() provides alternate write access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +template +inline void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock = NULLPTR) +{ + CRYPTOPP_UNUSED(assumeAligned); +#ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS + *reinterpret_cast((void *)block) = ConditionalByteReverse(order, value) ^ (xorBlock ? *reinterpret_cast((const void *)xorBlock) : 0); +#else + T t1, t2; + t1 = ConditionalByteReverse(order, value); + if (xorBlock) {memcpy(&t2, xorBlock, sizeof(T)); t1 ^= t2;} + memcpy(block, &t1, sizeof(T)); +#endif +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam A flag indicating alignment +/// \details GetBlock() provides alternate read access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// Repeatedly applying operator() results in advancing in the block of memory. +/// \details An example of reading two word32 values from a block of memory is shown below. w1 +/// will be 0x03020100 and w1 will be 0x07060504. +///
+///    word32 w1, w2;
+///    byte buffer[8] = {0,1,2,3,4,5,6,7};
+///    GetBlock block(buffer);
+///    block(w1)(w2);
+/// 
+template +class GetBlock +{ +public: + /// \brief Construct a GetBlock + /// \param block the memory block + GetBlock(const void *block) + : m_block((const byte *)block) {} + + /// \brief Access a block of memory + /// \tparam U class or type + /// \param x the value to read + /// \returns pointer to the remainder of the block after reading x + template + inline GetBlock & operator()(U &x) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); + x = GetWord(A, B::ToEnum(), m_block); + m_block += sizeof(T); + return *this; + } + +private: + const byte *m_block; +}; + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam A flag indicating alignment +/// \details PutBlock() provides alternate write access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// Repeatedly applying operator() results in advancing in the block of memory. +/// \details An example of writing two word32 values from a block of memory is shown below. After the code +/// executes, the byte buffer will be {0,1,2,3,4,5,6,7}. +///
+///    word32 w1=0x03020100, w2=0x07060504;
+///    byte buffer[8];
+///    PutBlock block(NULLPTR, buffer);
+///    block(w1)(w2);
+/// 
+template +class PutBlock +{ +public: + /// \brief Construct a PutBlock + /// \param block the memory block + /// \param xorBlock optional mask + PutBlock(const void *xorBlock, void *block) + : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} + + /// \brief Access a block of memory + /// \tparam U class or type + /// \param x the value to write + /// \returns pointer to the remainder of the block after writing x + template + inline PutBlock & operator()(U x) + { + PutWord(A, B::ToEnum(), m_block, (T)x, m_xorBlock); + m_block += sizeof(T); + if (m_xorBlock) + m_xorBlock += sizeof(T); + return *this; + } + +private: + const byte *m_xorBlock; + byte *m_block; +}; + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam GA flag indicating alignment for the Get operation +/// \tparam PA flag indicating alignment for the Put operation +/// \details GetBlock() provides alternate write access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// \sa GetBlock() and PutBlock(). +template +struct BlockGetAndPut +{ + // function needed because of C++ grammatical ambiguity between expression-statements and declarations + static inline GetBlock Get(const void *block) {return GetBlock(block);} + typedef PutBlock Put; +}; + +/// \brief Convert a word to a string +/// \tparam T class or type +/// \param value the word to convert +/// \param order byte order +/// \returns a string representing the value of the word +template +std::string WordToString(T value, ByteOrder order = BIG_ENDIAN_ORDER) +{ + if (!NativeByteOrderIs(order)) + value = ByteReverse(value); + + return std::string((char *)&value, sizeof(value)); +} + +/// \brief Convert a string to a word +/// \tparam T class or type +/// \param str the string to convert +/// \param order byte order +/// \returns a word representing the value of the string +template +T StringToWord(const std::string &str, ByteOrder order = BIG_ENDIAN_ORDER) +{ + T value = 0; + memcpy_s(&value, sizeof(value), str.data(), UnsignedMin(str.size(), sizeof(value))); + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +// ************** help remove warning on g++ *************** + +/// \brief Safely shift values when undefined behavior could occur +/// \tparam overflow boolean flag indicating if overflow is present +/// \details SafeShifter safely shifts values when undefined behavior could occur under C/C++ rules. +/// The class behaves much like a saturating arithmetic class, clamping values rather than allowing +/// the compiler to remove undefined behavior. +/// \sa SafeShifter, SafeShifter +template struct SafeShifter; + +/// \brief Shifts a value in the presence of overflow +/// \details the true template parameter indicates overflow would occur. +/// In this case, SafeShifter clamps the value and returns 0. +template<> struct SafeShifter +{ + /// \brief Right shifts a value that overflows + /// \tparam T class or type + /// \return 0 + /// \details Since overflow == true, the value 0 is always returned. + /// \sa SafeLeftShift + template + static inline T RightShift(T value, unsigned int bits) + { + CRYPTOPP_UNUSED(value); CRYPTOPP_UNUSED(bits); + return 0; + } + + /// \brief Left shifts a value that overflows + /// \tparam T class or type + /// \return 0 + /// \details Since overflow == true, the value 0 is always returned. + /// \sa SafeRightShift + template + static inline T LeftShift(T value, unsigned int bits) + { + CRYPTOPP_UNUSED(value); CRYPTOPP_UNUSED(bits); + return 0; + } +}; + +/// \brief Shifts a value in the absence of overflow +/// \details the false template parameter indicates overflow would not occur. +/// In this case, SafeShifter returns the shfted value. +template<> struct SafeShifter +{ + /// \brief Right shifts a value that does not overflow + /// \tparam T class or type + /// \return the shifted value + /// \details Since overflow == false, the shifted value is returned. + /// \sa SafeLeftShift + template + static inline T RightShift(T value, unsigned int bits) + { + return value >> bits; + } + + /// \brief Left shifts a value that does not overflow + /// \tparam T class or type + /// \return the shifted value + /// \details Since overflow == false, the shifted value is returned. + /// \sa SafeRightShift + template + static inline T LeftShift(T value, unsigned int bits) + { + return value << bits; + } +}; + +/// \brief Safely right shift values when undefined behavior could occur +/// \tparam bits the number of bit positions to shift the value +/// \tparam T class or type +/// \param value the value to right shift +/// \result the shifted value or 0 +/// \details SafeRightShift safely shifts the value to the right when undefined behavior +/// could occur under C/C++ rules. SafeRightShift will return the shifted value or 0 +/// if undefined behavior would occur. +template +inline T SafeRightShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); +} + +/// \brief Safely left shift values when undefined behavior could occur +/// \tparam bits the number of bit positions to shift the value +/// \tparam T class or type +/// \param value the value to left shift +/// \result the shifted value or 0 +/// \details SafeLeftShift safely shifts the value to the left when undefined behavior +/// could occur under C/C++ rules. SafeLeftShift will return the shifted value or 0 +/// if undefined behavior would occur. +template +inline T SafeLeftShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); +} + +/// \brief Finds first element not in a range +/// \tparam InputIt Input iterator type +/// \tparam T class or type +/// \param first iterator to first element +/// \param last iterator to last element +/// \param value the value used as a predicate +/// \returns iterator to the first element in the range that is not value +template +inline InputIt FindIfNot(InputIt first, InputIt last, const T &value) { +#ifdef CRYPTOPP_CXX11_LAMBDA + return std::find_if(first, last, [&value](const T &o) { + return value!=o; + }); +#else + return std::find_if(first, last, std::bind2nd(std::not_equal_to(), value)); +#endif +} + +// ************** use one buffer for multiple data members *************** + +#define CRYPTOPP_BLOCK_1(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+0);} size_t SS1() {return sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_2(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS1());} size_t SS2() {return SS1()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_3(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS2());} size_t SS3() {return SS2()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_4(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS3());} size_t SS4() {return SS3()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_5(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS4());} size_t SS5() {return SS4()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_6(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS5());} size_t SS6() {return SS5()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_7(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS6());} size_t SS7() {return SS6()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_8(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS7());} size_t SS8() {return SS7()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCKS_END(i) size_t SST() {return SS##i();} void AllocateBlocks() {m_aggregate.New(SST());} AlignedSecByteBlock m_aggregate; + +NAMESPACE_END + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/include/cryptlib/modarith.h b/include/cryptlib/modarith.h new file mode 100644 index 0000000..2c6b1c6 --- /dev/null +++ b/include/cryptlib/modarith.h @@ -0,0 +1,323 @@ +// modarith.h - originally written and placed in the public domain by Wei Dai + +/// \file modarith.h +/// \brief Class file for performing modular arithmetic. + +#ifndef CRYPTOPP_MODARITH_H +#define CRYPTOPP_MODARITH_H + +// implementations are in integer.cpp + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "secblock.h" +#include "misc.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain; + +/// \brief Ring of congruence classes modulo n +/// \details This implementation represents each congruence class as the smallest +/// non-negative integer in that class. +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+class CRYPTOPP_DLL ModularArithmetic : public AbstractRing +{ +public: + + typedef int RandomizationParameter; + typedef Integer Element; + + virtual ~ModularArithmetic() {} + + /// \brief Construct a ModularArithmetic + /// \param modulus congruence class modulus + ModularArithmetic(const Integer &modulus = Integer::One()) + : AbstractRing(), m_modulus(modulus), m_result((word)0, modulus.reg.size()) {} + + /// \brief Copy construct a ModularArithmetic + /// \param ma other ModularArithmetic + ModularArithmetic(const ModularArithmetic &ma) + : AbstractRing(), m_modulus(ma.m_modulus), m_result((word)0, ma.m_modulus.reg.size()) {} + + /// \brief Construct a ModularArithmetic + /// \param bt BER encoded ModularArithmetic + ModularArithmetic(BufferedTransformation &bt); // construct from BER encoded parameters + + /// \brief Clone a ModularArithmetic + /// \returns pointer to a new ModularArithmetic + /// \details Clone effectively copy constructs a new ModularArithmetic. The caller is + /// responsible for deleting the pointer returned from this method. + virtual ModularArithmetic * Clone() const {return new ModularArithmetic(*this);} + + /// \brief Encodes in DER format + /// \param bt BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Encodes element in DER format + /// \param out BufferedTransformation object + /// \param a Element to encode + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + + /// \brief Decodes element in DER format + /// \param in BufferedTransformation object + /// \param a Element to decode + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + /// \brief Retrieves the modulus + /// \returns the modulus + const Integer& GetModulus() const {return m_modulus;} + + /// \brief Sets the modulus + /// \param newModulus the new modulus + void SetModulus(const Integer &newModulus) + {m_modulus = newModulus; m_result.reg.resize(m_modulus.reg.size());} + + /// \brief Retrieves the representation + /// \returns true if the if the modulus is in Montgomery form for multiplication, false otherwise + virtual bool IsMontgomeryRepresentation() const {return false;} + + /// \brief Reduces an element in the congruence class + /// \param a element to convert + /// \returns the reduced element + /// \details ConvertIn is useful for derived classes, like MontgomeryRepresentation, which + /// must convert between representations. + virtual Integer ConvertIn(const Integer &a) const + {return a%m_modulus;} + + /// \brief Reduces an element in the congruence class + /// \param a element to convert + /// \returns the reduced element + /// \details ConvertOut is useful for derived classes, like MontgomeryRepresentation, which + /// must convert between representations. + virtual Integer ConvertOut(const Integer &a) const + {return a;} + + /// \brief Divides an element by 2 + /// \param a element to convert + const Integer& Half(const Integer &a) const; + + /// \brief Compare two elements for equality + /// \param a first element + /// \param b second element + /// \returns true if the elements are equal, false otherwise + /// \details Equal() tests the elements for equality using a==b + bool Equal(const Integer &a, const Integer &b) const + {return a==b;} + + /// \brief Provides the Identity element + /// \returns the Identity element + const Integer& Identity() const + {return Integer::Zero();} + + /// \brief Adds elements in the ring + /// \param a first element + /// \param b second element + /// \returns the sum of a and b + const Integer& Add(const Integer &a, const Integer &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \returns TODO + Integer& Accumulate(Integer &a, const Integer &b) const; + + /// \brief Inverts the element in the ring + /// \param a first element + /// \returns the inverse of the element + const Integer& Inverse(const Integer &a) const; + + /// \brief Subtracts elements in the ring + /// \param a first element + /// \param b second element + /// \returns the difference of a and b. The element a must provide a Subtract member function. + const Integer& Subtract(const Integer &a, const Integer &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \returns TODO + Integer& Reduce(Integer &a, const Integer &b) const; + + /// \brief Doubles an element in the ring + /// \param a the element + /// \returns the element doubled + /// \details Double returns Add(a, a). The element a must provide an Add member function. + const Integer& Double(const Integer &a) const + {return Add(a, a);} + + /// \brief Retrieves the multiplicative identity + /// \returns the multiplicative identity + /// \details the base class implementations returns 1. + const Integer& MultiplicativeIdentity() const + {return Integer::One();} + + /// \brief Multiplies elements in the ring + /// \param a the multiplicand + /// \param b the multiplier + /// \returns the product of a and b + /// \details Multiply returns a*b\%n. + const Integer& Multiply(const Integer &a, const Integer &b) const + {return m_result1 = a*b%m_modulus;} + + /// \brief Square an element in the ring + /// \param a the element + /// \returns the element squared + /// \details Square returns a*a\%n. The element a must provide a Square member function. + const Integer& Square(const Integer &a) const + {return m_result1 = a.Squared()%m_modulus;} + + /// \brief Determines whether an element is a unit in the ring + /// \param a the element + /// \returns true if the element is a unit after reduction, false otherwise. + bool IsUnit(const Integer &a) const + {return Integer::Gcd(a, m_modulus).IsUnit();} + + /// \brief Calculate the multiplicative inverse of an element in the ring + /// \param a the element + /// \details MultiplicativeInverse returns a-1\%n. The element a must + /// provide a InverseMod member function. + const Integer& MultiplicativeInverse(const Integer &a) const + {return m_result1 = a.InverseMod(m_modulus);} + + /// \brief Divides elements in the ring + /// \param a the dividend + /// \param b the divisor + /// \returns the quotient + /// \details Divide returns a*b-1\%n. + const Integer& Divide(const Integer &a, const Integer &b) const + {return Multiply(a, MultiplicativeInverse(b));} + + /// \brief TODO + /// \param x first element + /// \param e1 first exponent + /// \param y second element + /// \param e2 second exponent + /// \returns TODO + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const; + + /// \brief Exponentiates a base to multiple exponents in the ring + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Provides the maximum bit size of an element in the ring + /// \returns maximum bit size of an element + unsigned int MaxElementBitLength() const + {return (m_modulus-1).BitCount();} + + /// \brief Provides the maximum byte size of an element in the ring + /// \returns maximum byte size of an element + unsigned int MaxElementByteLength() const + {return (m_modulus-1).ByteCount();} + + /// \brief Provides a random element in the ring + /// \param rng RandomNumberGenerator used to generate material + /// \param ignore_for_now unused + /// \returns a random element that is uniformly distributed + /// \details RandomElement constructs a new element in the range [0,n-1], inclusive. + /// The element's class must provide a constructor with the signature Element(RandomNumberGenerator rng, + /// Element min, Element max). + Element RandomElement(RandomNumberGenerator &rng , const RandomizationParameter &ignore_for_now = 0) const + // left RandomizationParameter arg as ref in case RandomizationParameter becomes a more complicated struct + { + CRYPTOPP_UNUSED(ignore_for_now); + return Element(rng, Integer::Zero(), m_modulus - Integer::One()) ; + } + + /// \brief Compares two ModularArithmetic for equality + /// \param rhs other ModularArithmetic + /// \returns true if this is equal to the other, false otherwise + /// \details The operator tests for equality using this.m_modulus == rhs.m_modulus. + bool operator==(const ModularArithmetic &rhs) const + {return m_modulus == rhs.m_modulus;} + + static const RandomizationParameter DefaultRandomizationParameter ; + +protected: + Integer m_modulus; + mutable Integer m_result, m_result1; +}; + +// const ModularArithmetic::RandomizationParameter ModularArithmetic::DefaultRandomizationParameter = 0 ; + +/// \brief Performs modular arithmetic in Montgomery representation for increased speed +/// \details The Montgomery representation represents each congruence class [a] as +/// a*r\%n, where r is a convenient power of 2. +/// \details const Element& returned by member functions are references to +/// internal data members. Since each object may have only one such data member for holding +/// results, the following code will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+class CRYPTOPP_DLL MontgomeryRepresentation : public ModularArithmetic +{ +public: + virtual ~MontgomeryRepresentation() {} + + /// \brief Construct a MontgomeryRepresentation + /// \param modulus congruence class modulus + /// \note The modulus must be odd. + MontgomeryRepresentation(const Integer &modulus); + + /// \brief Clone a MontgomeryRepresentation + /// \returns pointer to a new MontgomeryRepresentation + /// \details Clone effectively copy constructs a new MontgomeryRepresentation. The caller is + /// responsible for deleting the pointer returned from this method. + virtual ModularArithmetic * Clone() const {return new MontgomeryRepresentation(*this);} + + bool IsMontgomeryRepresentation() const {return true;} + + Integer ConvertIn(const Integer &a) const + {return (a<<(WORD_BITS*m_modulus.reg.size()))%m_modulus;} + + Integer ConvertOut(const Integer &a) const; + + const Integer& MultiplicativeIdentity() const + {return m_result1 = Integer::Power2(WORD_BITS*m_modulus.reg.size())%m_modulus;} + + const Integer& Multiply(const Integer &a, const Integer &b) const; + + const Integer& Square(const Integer &a) const; + + const Integer& MultiplicativeInverse(const Integer &a) const; + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const + {return AbstractRing::CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {AbstractRing::SimultaneousExponentiate(results, base, exponents, exponentsCount);} + +private: + Integer m_u; + mutable IntegerSecBlock m_workspace; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/modes.h b/include/cryptlib/modes.h new file mode 100644 index 0000000..7003f1f --- /dev/null +++ b/include/cryptlib/modes.h @@ -0,0 +1,493 @@ +// modes.h - originally written and placed in the public domain by Wei Dai + +/// \file modes.h +/// \brief Classes for block cipher modes of operation + +#ifndef CRYPTOPP_MODES_H +#define CRYPTOPP_MODES_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "strciphr.h" +#include "argnames.h" +#include "algparam.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Block cipher mode of operation information +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the SymmetricCipher interface. +/// For each mode there are two classes, one of which is a template class, +/// and the other one has a name that ends in "_ExternalCipher". +/// The "external cipher" mode objects hold a reference to the underlying block cipher, +/// instead of holding an instance of it. The reference must be passed in to the constructor. +/// For the "cipher holder" classes, the CIPHER template parameter should be a class +/// derived from BlockCipherDocumentation, for example DES or AES. +/// \details See NIST SP 800-38A for definitions of these modes. See +/// AuthenticatedSymmetricCipherDocumentation for authenticated encryption modes. +struct CipherModeDocumentation : public SymmetricCipherDocumentation +{ +}; + +/// \brief Block cipher mode of operation information +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CipherModeBase : public SymmetricCipher +{ +public: + virtual ~CipherModeBase() {} + size_t MinKeyLength() const {return m_cipher->MinKeyLength();} + size_t MaxKeyLength() const {return m_cipher->MaxKeyLength();} + size_t DefaultKeyLength() const {return m_cipher->DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const {return m_cipher->GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const {return m_cipher->IsValidKeyLength(n);} + + unsigned int OptimalDataAlignment() const {return m_cipher->OptimalDataAlignment();} + + unsigned int IVSize() const {return BlockSize();} + virtual IV_Requirement IVRequirement() const =0; + + void SetCipher(BlockCipher &cipher) + { + this->ThrowIfResynchronizable(); + this->m_cipher = &cipher; + this->ResizeBuffers(); + } + + void SetCipherWithIV(BlockCipher &cipher, const byte *iv, int feedbackSize = 0) + { + this->ThrowIfInvalidIV(iv); + this->m_cipher = &cipher; + this->ResizeBuffers(); + this->SetFeedbackSize(feedbackSize); + if (this->IsResynchronizable()) + this->Resynchronize(iv); + } + +protected: + CipherModeBase() : m_cipher(NULLPTR) {} + inline unsigned int BlockSize() const {CRYPTOPP_ASSERT(m_register.size() > 0); return (unsigned int)m_register.size();} + virtual void SetFeedbackSize(unsigned int feedbackSize) + { + if (!(feedbackSize == 0 || feedbackSize == BlockSize())) + throw InvalidArgument("CipherModeBase: feedback size cannot be specified for this cipher mode"); + } + + virtual void ResizeBuffers(); + + BlockCipher *m_cipher; + AlignedSecByteBlock m_register; +}; + +/// \brief Block cipher mode of operation common operations +/// \tparam POLICY_INTERFACE common operations +template +class CRYPTOPP_NO_VTABLE ModePolicyCommonTemplate : public CipherModeBase, public POLICY_INTERFACE +{ + unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();} + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); +}; + +template +void ModePolicyCommonTemplate::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + m_cipher->SetKey(key, length, params); + ResizeBuffers(); + int feedbackSize = params.GetIntValueWithDefault(Name::FeedbackSize(), 0); + SetFeedbackSize(feedbackSize); +} + +/// \brief CFB block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CFB";} + + virtual ~CFB_ModePolicy() {} + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + unsigned int GetBytesPerIteration() const {return m_feedbackSize;} + byte * GetRegisterBegin() {return m_register + BlockSize() - m_feedbackSize;} + bool CanIterate() const {return m_feedbackSize == BlockSize();} + void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount); + void TransformRegister(); + void CipherResynchronize(const byte *iv, size_t length); + void SetFeedbackSize(unsigned int feedbackSize); + void ResizeBuffers(); + + SecByteBlock m_temp; + unsigned int m_feedbackSize; +}; + +inline void CopyOrZero(void *dest, size_t d, const void *src, size_t s) +{ + CRYPTOPP_ASSERT(dest); + CRYPTOPP_ASSERT(d >= s); + + if (src) + memcpy_s(dest, d, src, s); + else + memset(dest, 0, d); +} + +/// \brief OFB block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE OFB_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "OFB";} + + bool CipherIsRandomAccess() const {return false;} + IV_Requirement IVRequirement() const {return UNIQUE_IV;} + +private: + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *keystreamBuffer, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); +}; + +/// \brief CTR block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CTR_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CTR";} + + virtual ~CTR_ModePolicy() {} + bool CipherIsRandomAccess() const {return true;} + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + virtual void IncrementCounterBy256(); + unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();} + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *buffer, size_t iterationCount) + {OperateKeystream(WRITE_KEYSTREAM, buffer, NULLPTR, iterationCount);} + bool CanOperateKeystream() const {return true;} + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + void SeekToIteration(lword iterationCount); + + AlignedSecByteBlock m_counterArray; +}; + +/// \brief Block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockOrientedCipherModeBase : public CipherModeBase +{ +public: + virtual ~BlockOrientedCipherModeBase() {} + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + unsigned int MandatoryBlockSize() const {return BlockSize();} + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return false;} + bool IsForwardTransformation() const {return m_cipher->IsForwardTransformation();} + void Resynchronize(const byte *iv, int length=-1) {memcpy_s(m_register, m_register.size(), iv, ThrowIfInvalidIVLength(length));} + +protected: + bool RequireAlignedInput() const {return true;} + virtual void ResizeBuffers(); + + SecByteBlock m_buffer; +}; + +/// \brief ECB block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ECB_OneWay : public BlockOrientedCipherModeBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECB";} + + void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs) + {m_cipher->SetKey(key, length, params); BlockOrientedCipherModeBase::ResizeBuffers();} + IV_Requirement IVRequirement() const {return NOT_RESYNCHRONIZABLE;} + unsigned int OptimalBlockSize() const {return BlockSize() * m_cipher->OptimalNumberOfParallelBlocks();} + void ProcessData(byte *outString, const byte *inString, size_t length); +}; + +/// \brief CBC block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_ModeBase : public BlockOrientedCipherModeBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CBC";} + + IV_Requirement IVRequirement() const {return UNPREDICTABLE_RANDOM_IV;} + bool RequireAlignedInput() const {return false;} + unsigned int MinLastBlockSize() const {return 0;} +}; + +/// \brief CBC block cipher mode of operation encryption operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Encryption : public CBC_ModeBase +{ +public: + void ProcessData(byte *outString, const byte *inString, size_t length); +}; + +/// \brief CBC-CTS block cipher mode of operation encryption operation +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Encryption : public CBC_Encryption +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CBC/CTS";} + + void SetStolenIV(byte *iv) {m_stolenIV = iv;} + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CBC_Encryption::UncheckedSetKey(key, length, params); + m_stolenIV = params.GetValueWithDefault(Name::StolenIV(), (byte *)NULLPTR); + } + + byte *m_stolenIV; +}; + +/// \brief CBC block cipher mode of operation decryption operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Decryption : public CBC_ModeBase +{ +public: + virtual ~CBC_Decryption() {} + void ProcessData(byte *outString, const byte *inString, size_t length); + +protected: + virtual void ResizeBuffers(); + + AlignedSecByteBlock m_temp; +}; + +/// \brief CBC-CTS block cipher mode of operation decryption operation +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Decryption : public CBC_Decryption +{ +public: + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); +}; + +/// \brief Block cipher mode of operation aggregate +template +class CipherModeFinalTemplate_CipherHolder : protected ObjectHolder, public AlgorithmImpl > +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() + {return CIPHER::StaticAlgorithmName() + "/" + BASE::StaticAlgorithmName();} + + CipherModeFinalTemplate_CipherHolder() + { + this->m_cipher = &this->m_object; + this->ResizeBuffers(); + } + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length); + } + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))); + } + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv, int feedbackSize) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))(Name::FeedbackSize(), feedbackSize)); + } +}; + +/// \tparam BASE CipherModeFinalTemplate_CipherHolder base class +/// \details Base class for external mode cipher combinations +template +class CipherModeFinalTemplate_ExternalCipher : public BASE +{ +public: + CipherModeFinalTemplate_ExternalCipher() {} + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher) + {this->SetCipher(cipher);} + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher, const byte *iv, int feedbackSize = 0) + {this->SetCipherWithIV(cipher, iv, feedbackSize);} + + std::string AlgorithmName() const + {return (this->m_cipher ? this->m_cipher->AlgorithmName() + "/" : std::string("")) + BASE::StaticAlgorithmName();} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >; + +/// \brief CFB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > Decryption; +}; + +/// \brief CFB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > Decryption; +}; + +/// \brief CFB block cipher mode of operation providing FIPS validated cryptography. +/// \details Requires full block plaintext according to FIPS 800-38A +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CFB_FIPS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > > Decryption; +}; + +/// \brief CFB mode, external cipher, providing FIPS validated cryptography. +/// \details Requires full block plaintext according to FIPS 800-38A +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CFB_FIPS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > > Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; + +/// \brief OFB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct OFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief OFB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct OFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher > > >; + +/// \brief CTR block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CTR_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief CTR mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CTR_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief ECB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct ECB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief ECB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct ECB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef Encryption Decryption; +}; + +/// \brief CBC block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CBC_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief CBC mode, external cipher +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CBC_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +/// \brief CBC-CTS block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 3.0 +template +struct CBC_CTS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief CBC mode with ciphertext stealing, external cipher +/// \sa Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 3.0 +struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/include/cryptlib/modexppc.h b/include/cryptlib/modexppc.h new file mode 100644 index 0000000..cacb0aa --- /dev/null +++ b/include/cryptlib/modexppc.h @@ -0,0 +1,48 @@ +#ifndef CRYPTOPP_MODEXPPC_H +#define CRYPTOPP_MODEXPPC_H + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; + +class ModExpPrecomputation : public DL_GroupPrecomputation +{ +public: + virtual ~ModExpPrecomputation() {} + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &v) const {return m_mr->ConvertIn(v);} + virtual Element ConvertOut(const Element &v) const {return m_mr->ConvertOut(v);} + const AbstractGroup & GetGroup() const {return m_mr->MultiplicativeGroup();} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_mr.reset(new MontgomeryRepresentation(v));} + const Integer & GetModulus() const {return m_mr->GetModulus();} + +private: + value_ptr m_mr; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/mqueue.h b/include/cryptlib/mqueue.h new file mode 100644 index 0000000..0ef13f2 --- /dev/null +++ b/include/cryptlib/mqueue.h @@ -0,0 +1,105 @@ +#ifndef CRYPTOPP_MQUEUE_H +#define CRYPTOPP_MQUEUE_H + +#include "cryptlib.h" +#include "queue.h" +#include "filters.h" +#include "misc.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// Message Queue +class CRYPTOPP_DLL MessageQueue : public AutoSignaling +{ +public: + MessageQueue(unsigned int nodeSize=256); + + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_queue.IsolatedInitialize(parameters); m_lengths.assign(1, 0U); m_messageCounts.assign(1, 0U);} + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(blocking); + m_queue.Put(begin, length); + m_lengths.back() += length; + if (messageEnd) + { + m_lengths.push_back(0); + m_messageCounts.back()++; + } + return 0; + } + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking); return false;} + bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); m_messageCounts.push_back(0); return false;} + + lword MaxRetrievable() const + {return m_lengths.front();} + bool AnyRetrievable() const + {return m_lengths.front() > 0;} + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + lword TotalBytesRetrievable() const + {return m_queue.MaxRetrievable();} + unsigned int NumberOfMessages() const + {return (unsigned int)m_lengths.size()-1;} + bool GetNextMessage(); + + unsigned int NumberOfMessagesInThisSeries() const + {return m_messageCounts[0];} + unsigned int NumberOfMessageSeries() const + {return (unsigned int)m_messageCounts.size()-1;} + + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + + const byte * Spy(size_t &contiguousSize) const; + + void swap(MessageQueue &rhs); + +private: + ByteQueue m_queue; + std::deque m_lengths; + std::deque m_messageCounts; +}; + + +/// A filter that checks messages on two channels for equality +class CRYPTOPP_DLL EqualityComparisonFilter : public Unflushable > +{ +public: + struct MismatchDetected : public Exception {MismatchDetected() : Exception(DATA_INTEGRITY_CHECK_FAILED, "EqualityComparisonFilter: did not receive the same data on two channels") {}}; + + /*! if throwIfNotEqual is false, this filter will output a '\\0' byte when it detects a mismatch, '\\1' otherwise */ + EqualityComparisonFilter(BufferedTransformation *attachment=NULLPTR, bool throwIfNotEqual=true, const std::string &firstChannel="0", const std::string &secondChannel="1") + : m_throwIfNotEqual(throwIfNotEqual), m_mismatchDetected(false) + , m_firstChannel(firstChannel), m_secondChannel(secondChannel) + {Detach(attachment);} + + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + +private: + unsigned int MapChannel(const std::string &channel) const; + bool HandleMismatchDetected(bool blocking); + + bool m_throwIfNotEqual, m_mismatchDetected; + std::string m_firstChannel, m_secondChannel; + MessageQueue m_q[2]; +}; + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::MessageQueue &a, CryptoPP::MessageQueue &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/include/cryptlib/mqv.h b/include/cryptlib/mqv.h new file mode 100644 index 0000000..0427ac0 --- /dev/null +++ b/include/cryptlib/mqv.h @@ -0,0 +1,223 @@ +// mqv.h - originally written and placed in the public domain by Wei Dai + +/// \file mqv.h +/// \brief Classes for Menezes–Qu–Vanstone (MQV) key agreement +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MQV_H +#define CRYPTOPP_MQV_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief MQV domain for performing authenticated key agreement +/// \tparam GROUP_PARAMETERS doamin parameters +/// \tparam COFACTOR_OPTION cofactor option +/// \details GROUP_PARAMETERS parameters include the curve coefcients and the base point. +/// Binary curves use a polynomial to represent its characteristic, while prime curves +/// use a prime number. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 3.0 +template +class MQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef MQV_Domain Domain; + + /// \brief Construct a MQV domain + MQV_Domain() {} + + /// \brief Construct a MQV domain + /// \param params group parameters and options + MQV_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + /// \brief Construct a MQV domain + /// \param bt BufferedTransformation with group parameters and options + MQV_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2, T3 v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), which means the + /// element is encoded in a non-reversible format. A non-reversible format means its a raw byte array, + /// and it lacks presentation format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), which means the + /// element is encoded in a reversible format. A reversible format means it has a presentation format, + /// and its an ANS.1 encoded element or point. + unsigned int StaticPublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored in a revrsible format. + /// A reversible format means it has a presentation format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + unsigned int EphemeralPublicKeyLength() const {return StaticPublicKeyLength();} + + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Element WW = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV = params.DecodeElement(ephemeralOtherPublicKey, true); + + Integer s(staticPrivateKey, StaticPrivateKeyLength()); + Integer u(ephemeralPrivateKey, StaticPrivateKeyLength()); + Element V = params.DecodeElement(ephemeralPrivateKey+StaticPrivateKeyLength(), false); + + const Integer &r = params.GetSubgroupOrder(); + Integer h2 = Integer::Power2((r.BitCount()+1)/2); + Integer e = ((h2+params.ConvertElementToInteger(V)%h2)*s+u) % r; + Integer tt = h2 + params.ConvertElementToInteger(VV) % h2; + + if (COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION) + { + Element P = params.ExponentiateElement(WW, tt); + P = m_groupParameters.MultiplyElements(P, VV); + Element R[2]; + const Integer e2[2] = {r, e}; + params.SimultaneousExponentiate(R, P, e2, 2); + if (!params.IsIdentity(R[0]) || params.IsIdentity(R[1])) + return false; + params.EncodeElement(false, R[1], agreedValue); + } + else + { + const Integer &k = params.GetCofactor(); + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + e = ModularArithmetic(r).Divide(e, k); + Element P = m_groupParameters.CascadeExponentiate(VV, k*e, WW, k*(e*tt%r)); + if (params.IsIdentity(P)) + return false; + params.EncodeElement(false, P, agreedValue); + } + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + +private: + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +/// Menezes-Qu-Vanstone in GF(p) with key validation, AKA MQV +/// \sa MQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 3.0 +typedef MQV_Domain MQV; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/naclite.h b/include/cryptlib/naclite.h new file mode 100644 index 0000000..242a6e1 --- /dev/null +++ b/include/cryptlib/naclite.h @@ -0,0 +1,417 @@ +// naclite.h - written and placed in the public domain by Jeffrey Walton +// based on public domain NaCl source code written by +// Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, +// Tanja Lange, Peter Schwabe and Sjaak Smetsers. + +/// \file naclite.h +/// \brief Crypto++ interface to TweetNaCl library (20140917) +/// \details TweetNaCl is a compact reimplementation of the NaCl library by +/// Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, Tanja Lange, +/// Peter Schwabe and Sjaak Smetsers. The library is less than 20 KB in size +/// and provides 25 of the NaCl library functions. +/// \details The compact library uses curve25519, XSalsa20, Poly1305 and +/// SHA-512 as default primitives, and includes both x25519 key exchange and +/// ed25519 signatures. The complete list of functions can be found in +/// TweetNaCl: +/// A crypto library in 100 tweets (20140917), Table 1, page 5. +/// \details Crypto++ rejects small order elements using libsodium's blacklist. The +/// TweetNaCl library allowed them but the library predated the attack. If you wish +/// to allow small elements then use the "unchecked" versions of crypto_box_unchecked, +/// crypto_box_open_unchecked and crypto_box_beforenm_unchecked. +/// \details TweetNaCl is well written but not well optimzed. It runs 2x to 3x +/// slower than optimized routines from libsodium. However, the library is still +/// 2x to 4x faster than the algorithms NaCl was designed to replace. +/// \details The Crypto++ wrapper for TweetNaCl requires OS features. That is, +/// NO_OS_DEPENDENCE cannot be defined. It is due to TweetNaCl's +/// internal function randombytes. Crypto++ used +/// DefaultAutoSeededRNG within randombytes, so OS integration +/// must be enabled. You can use another generator like RDRAND to +/// avoid the restriction. +/// \sa The security impact +/// of a new cryptographic library, TweetNaCl: +/// A crypto library in 100 tweets (20140917), May the Fourth Be With You: A +/// Microarchitectural Side Channel Attack on Several Real-World Applications of +/// Curve25519, libsodium +/// commit afabd7e7386e1194 and RFC +/// 7748, Elliptic Curves for Security, Section 6. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_NACL_H +#define CRYPTOPP_NACL_H + +#include "config.h" +#include "stdcpp.h" + +#if defined(NO_OS_DEPENDENCE) +# define CRYPTOPP_DISABLE_NACL 1 +#endif + +#ifndef CRYPTOPP_DISABLE_NACL + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(NaCl) + +/// \brief Hash size in bytes +/// \sa NaCl crypto_hash documentation +CRYPTOPP_CONSTANT(crypto_hash_BYTES = 64) + +/// \brief Key size in bytes +/// \sa NaCl crypto_stream documentation +CRYPTOPP_CONSTANT(crypto_stream_KEYBYTES = 32) +/// \brief Nonce size in bytes +/// \sa NaCl crypto_stream documentation +CRYPTOPP_CONSTANT(crypto_stream_NONCEBYTES = 24) + +/// \brief Key size in bytes +/// \sa NaCl crypto_auth documentation +CRYPTOPP_CONSTANT(crypto_auth_KEYBYTES = 32) +/// \brief Tag size in bytes +/// \sa NaCl crypto_auth documentation +CRYPTOPP_CONSTANT(crypto_auth_BYTES = 16) + +/// \brief Key size in bytes +/// \sa NaCl crypto_onetimeauth documentation +CRYPTOPP_CONSTANT(crypto_onetimeauth_KEYBYTES = 32) +/// \brief Tag size in bytes +/// \sa NaCl crypto_onetimeauth documentation +CRYPTOPP_CONSTANT(crypto_onetimeauth_BYTES = 16) + +/// \brief Key size in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_KEYBYTES = 32) +/// \brief Nonce size in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_NONCEBYTES = 24) +/// \brief Zero-padded message prefix in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_ZEROBYTES = 32) +/// \brief Zero-padded message prefix in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_BOXZEROBYTES = 16) + +/// \brief Private key size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_SECRETKEYBYTES = 32) +/// \brief Public key size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_PUBLICKEYBYTES = 32) +/// \brief Nonce size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_NONCEBYTES = 24) +/// \brief Message 0-byte prefix in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_ZEROBYTES = 32) +/// \brief Open box 0-byte prefix in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_BOXZEROBYTES = 16) +/// \brief Precomputation 0-byte prefix in bytes in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_BEFORENMBYTES = 32) +/// \brief MAC size in bytes +/// \details crypto_box_MACBYTES was missing from tweetnacl.h. Its is defined as +/// crypto_box_curve25519xsalsa20poly1305_MACBYTES, which is defined as 16U. +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_MACBYTES = 16) + +/// \brief Private key size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_SECRETKEYBYTES = 64) +/// \brief Public key size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_PUBLICKEYBYTES = 32) +/// \brief Seed size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_SEEDBYTES = 32) +/// \brief Signature size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_BYTES = 64) + +/// \brief Group element size in bytes +/// \sa NaCl crypto_scalarmult documentation +CRYPTOPP_CONSTANT(crypto_scalarmult_BYTES = 32) +/// \brief Integer size in bytes +/// \sa NaCl crypto_scalarmult documentation +CRYPTOPP_CONSTANT(crypto_scalarmult_SCALARBYTES = 32) + +/// \brief Encrypt and authenticate a message +/// \param c output byte buffer +/// \param m input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box(byte *c,const byte *m,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_open(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Generate a keypair for encryption +/// \param y public key byte buffer +/// \param x private key byte buffer +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_keypair(byte *y,byte *x); + +/// \brief Encrypt and authenticate a message +/// \param k shared secret byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key. +/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_beforenm(byte *k,const byte *y,const byte *x); + +/// \brief Encrypt and authenticate a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param k shared secret byte buffer +/// \details crypto_box_afternm() performs message-dependent computation using the derived the key. +/// Once the key is derived using crypto_box_beforenm() multiple calls to crypto_box_afternm() +/// can be made to process the message. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_afternm(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param k shared secret byte buffer +/// \details crypto_box_afternm() performs message-dependent computation using the derived the key. +/// Once the key is derived using crypto_box_beforenm() multiple calls to crypto_box_open_afternm() +/// can be made to process the message. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_open_afternm(byte *m,const byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt and authenticate a message +/// \param c output byte buffer +/// \param m input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305. +/// \details This version of crypto_box() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \returns 0 on success, non-0 otherwise +/// \warning This version of crypto_box() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_unchecked(byte *c,const byte *m,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305. +/// \details This version of crypto_box_open() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \returns 0 on success, non-0 otherwise +/// \warning This version of crypto_box_open() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_open_unchecked(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Encrypt and authenticate a message +/// \param k shared secret byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key. +/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message. +/// \details This version of crypto_box_beforenm() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \returns 0 on success, non-0 otherwise +/// \warning This version of crypto_box_beforenm() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_beforenm_unchecked(byte *k,const byte *y,const byte *x); + +/// \brief TODO +int crypto_core_salsa20(byte *out,const byte *in,const byte *k,const byte *c); + +/// \brief TODO +/// \returns 0 on success, non-0 otherwise +/// \since Crypto++ 6.0 +int crypto_core_hsalsa20(byte *out,const byte *in,const byte *k,const byte *c); + +/// \brief Hash multiple blocks +/// \details crypto_hashblocks() uses crypto_hashblocks_sha512. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_hash documentation +/// \since Crypto++ 6.0 +int crypto_hashblocks(byte *x,const byte *m,word64 n); + +/// \brief Hash a message +/// \details crypto_hash() uses crypto_hash_sha512. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_hash documentation +/// \since Crypto++ 6.0 +int crypto_hash(byte *out,const byte *m,word64 n); + +/// \brief Create an authentication tag for a message +/// \details crypto_onetimeauth() uses crypto_onetimeauth_poly1305. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_onetimeauth documentation +/// \since Crypto++ 6.0 +int crypto_onetimeauth(byte *out,const byte *m,word64 n,const byte *k); + +/// \brief Verify an authentication tag on a message +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_onetimeauth documentation +/// \since Crypto++ 6.0 +int crypto_onetimeauth_verify(const byte *h,const byte *m,word64 n,const byte *k); + +/// \brief Scalar multiplication of a point +/// \details crypto_scalarmult() uses crypto_scalarmult_curve25519 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_scalarmult documentation +/// \since Crypto++ 6.0 +int crypto_scalarmult(byte *q,const byte *n,const byte *p); + +/// \brief Scalar multiplication of base point +/// \details crypto_scalarmult_base() uses crypto_scalarmult_curve25519 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_scalarmult documentation +/// \since Crypto++ 6.0 +int crypto_scalarmult_base(byte *q,const byte *n); + +/// \brief Encrypt and authenticate a message +/// \details crypto_secretbox() uses a symmetric key to encrypt and authenticate a message. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_secretbox documentation +/// \since Crypto++ 6.0 +int crypto_secretbox(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Verify and decrypt a message +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_secretbox documentation +/// \since Crypto++ 6.0 +int crypto_secretbox_open(byte *m,const byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Sign a message +/// \param sm output byte buffer +/// \param smlen size of the output byte buffer +/// \param m input byte buffer +/// \param n size of the input byte buffer +/// \param sk private key +/// \details crypto_sign() uses crypto_sign_ed25519. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign(byte *sm,word64 *smlen,const byte *m,word64 n,const byte *sk); + +/// \brief Verify a message +/// \param m output byte buffer +/// \param mlen size of the output byte buffer +/// \param sm input byte buffer +/// \param n size of the input byte buffer +/// \param pk public key +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign_open(byte *m,word64 *mlen,const byte *sm,word64 n,const byte *pk); + +/// \brief Generate a keypair for signing +/// \param pk public key byte buffer +/// \param sk private key byte buffer +/// \details crypto_sign_keypair() creates an ed25519 keypair. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign_keypair(byte *pk, byte *sk); + +/// \brief Produce a keystream using XSalsa20 +/// \details crypto_stream() uses crypto_stream_xsalsa20 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream(byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt a message using XSalsa20 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_xor(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Produce a keystream using Salsa20 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_salsa20(byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt a message using Salsa20 +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_salsa20_xor(byte *c,const byte *m,word64 b,const byte *n,const byte *k); + +/// \brief Compare 16-byte buffers +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_verify documentation +/// \since Crypto++ 6.0 +int crypto_verify_16(const byte *x,const byte *y); + +/// \brief Compare 32-byte buffers +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_verify documentation +/// \since Crypto++ 6.0 +int crypto_verify_32(const byte *x,const byte *y); + +NAMESPACE_END // CryptoPP +NAMESPACE_END // NaCl + +#endif // CRYPTOPP_DISABLE_NACL +#endif // CRYPTOPP_NACL_H diff --git a/include/cryptlib/nbtheory.h b/include/cryptlib/nbtheory.h new file mode 100644 index 0000000..4e68a84 --- /dev/null +++ b/include/cryptlib/nbtheory.h @@ -0,0 +1,316 @@ +// nbtheory.h - originally written and placed in the public domain by Wei Dai + +/// \file nbtheory.h +/// \brief Classes and functions for number theoretic operations + +#ifndef CRYPTOPP_NBTHEORY_H +#define CRYPTOPP_NBTHEORY_H + +#include "cryptlib.h" +#include "integer.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief The Small Prime table +/// \details GetPrimeTable obtains pointer to small prime table and provides the size of the table. +CRYPTOPP_DLL const word16 * CRYPTOPP_API GetPrimeTable(unsigned int &size); + +// ************ primality testing **************** + +/// \brief Generates a provable prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param bits the number of bits in the prime number +/// \returns Integer() meeting Maurer's tests for primality +CRYPTOPP_DLL Integer CRYPTOPP_API MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +/// \brief Generates a provable prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param bits the number of bits in the prime number +/// \returns Integer() meeting Mihailescu's tests for primality +/// \details Mihailescu's methods performs a search using algorithmic progressions. +CRYPTOPP_DLL Integer CRYPTOPP_API MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +/// \brief Tests whether a number is a small prime +/// \param p a candidate prime to test +/// \returns true if p is a small prime, false otherwise +/// \details Internally, the library maintains a table of the first 32719 prime numbers +/// in sorted order. IsSmallPrime searches the table and returns true if p is +/// in the table. +CRYPTOPP_DLL bool CRYPTOPP_API IsSmallPrime(const Integer &p); + +/// \brief Tests whether a number is divisible by a small prime +/// \returns true if p is divisible by some prime less than bound. +/// \details TrialDivision() returns true if p is divisible by some prime less +/// than bound. bound should not be greater than the largest entry in the +/// prime table, which is 32719. +CRYPTOPP_DLL bool CRYPTOPP_API TrialDivision(const Integer &p, unsigned bound); + +/// \brief Tests whether a number is divisible by a small prime +/// \returns true if p is NOT divisible by small primes. +/// \details SmallDivisorsTest() returns true if p is NOT divisible by some +/// prime less than 32719. +CRYPTOPP_DLL bool CRYPTOPP_API SmallDivisorsTest(const Integer &p); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \param b the base to exponentiate +/// \returns true if the number n is probably prime, false otherwise. +/// \details IsFermatProbablePrime raises b to the n-1 power and checks if +/// the result is congruent to 1 modulo n. +/// \details These is no reason to use IsFermatProbablePrime, use IsStrongProbablePrime or +/// IsStrongLucasProbablePrime instead. +/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime +CRYPTOPP_DLL bool CRYPTOPP_API IsFermatProbablePrime(const Integer &n, const Integer &b); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \returns true if the number n is probably prime, false otherwise. +/// \details These is no reason to use IsLucasProbablePrime, use IsStrongProbablePrime or +/// IsStrongLucasProbablePrime instead. +/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime +CRYPTOPP_DLL bool CRYPTOPP_API IsLucasProbablePrime(const Integer &n); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \param b the base to exponentiate +/// \returns true if the number n is probably prime, false otherwise. +CRYPTOPP_DLL bool CRYPTOPP_API IsStrongProbablePrime(const Integer &n, const Integer &b); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \returns true if the number n is probably prime, false otherwise. +CRYPTOPP_DLL bool CRYPTOPP_API IsStrongLucasProbablePrime(const Integer &n); + +/// \brief Determine if a number is probably prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param n the number to test +/// \param rounds the number of tests to perform +/// \details This is the Rabin-Miller primality test, i.e. repeating the strong probable prime +/// test for several rounds with random bases +/// \sa Trial divisions before +/// Miller-Rabin checks? on Crypto Stack Exchange +CRYPTOPP_DLL bool CRYPTOPP_API RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds); + +/// \brief Verifies a number is probably prime +/// \param p a candidate prime to test +/// \returns true if p is a probable prime, false otherwise +/// \details IsPrime() is suitable for testing candidate primes when creating them. Internally, +/// IsPrime() utilizes SmallDivisorsTest(), IsStrongProbablePrime() and IsStrongLucasProbablePrime(). +CRYPTOPP_DLL bool CRYPTOPP_API IsPrime(const Integer &p); + +/// \brief Verifies a number is probably prime +/// \param rng a RandomNumberGenerator for randomized testing +/// \param p a candidate prime to test +/// \param level the level of thoroughness of testing +/// \returns true if p is a strong probable prime, false otherwise +/// \details VerifyPrime() is suitable for testing candidate primes created by others. Internally, +/// VerifyPrime() utilizes IsPrime() and one-round RabinMillerTest(). If the candiate passes and +/// level is greater than 1, then 10 round RabinMillerTest() primality testing is performed. +CRYPTOPP_DLL bool CRYPTOPP_API VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level = 1); + +/// \brief Application callback to signal suitability of a cabdidate prime +class CRYPTOPP_DLL PrimeSelector +{ +public: + const PrimeSelector *GetSelectorPointer() const {return this;} + virtual bool IsAcceptable(const Integer &candidate) const =0; +}; + +/// \brief Finds a random prime of special form +/// \param p an Integer reference to receive the prime +/// \param max the maximum value +/// \param equiv the equivalence class based on the parameter mod +/// \param mod the modulus used to reduce the equivalence class +/// \param pSelector pointer to a PrimeSelector function for the application to signal suitability +/// \returns true if and only if FirstPrime() finds a prime and returns the prime through p. If FirstPrime() +/// returns false, then no such prime exists and the value of p is undefined +/// \details FirstPrime() uses a fast sieve to find the first probable prime +/// in {x | p<=x<=max and x%mod==equiv} +CRYPTOPP_DLL bool CRYPTOPP_API FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector); + +CRYPTOPP_DLL unsigned int CRYPTOPP_API PrimeSearchInterval(const Integer &max); + +CRYPTOPP_DLL AlgorithmParameters CRYPTOPP_API MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength); + +// ********** other number theoretic functions ************ + +/// \brief Calculate the greatest common divisor +/// \param a the first term +/// \param b the second term +/// \returns the greatest common divisor if one exists, 0 otherwise. +inline Integer GCD(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b);} + +/// \brief Determine relative primality +/// \param a the first term +/// \param b the second term +/// \returns true if a and b are relatively prime, false otherwise. +inline bool RelativelyPrime(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b) == Integer::One();} + +/// \brief Calculate the least common multiple +/// \param a the first term +/// \param b the second term +/// \returns the least common multiple of a and b. +inline Integer LCM(const Integer &a, const Integer &b) + {return a/Integer::Gcd(a,b)*b;} + +/// \brief Calculate multiplicative inverse +/// \param a the number to test +/// \param b the modulus +/// \returns an Integer (a ^ -1) % n or 0 if none exists. +/// \details EuclideanMultiplicativeInverse returns the multiplicative inverse of the Integer +/// *a modulo the Integer b. If no Integer exists then Integer 0 is returned. +inline Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b) + {return a.InverseMod(b);} + + +/// \brief Chinese Remainder Theorem +/// \param xp the first number, mod p +/// \param p the first prime modulus +/// \param xq the second number, mod q +/// \param q the second prime modulus +/// \param u inverse of p mod q +/// \returns the CRT value of the parameters +/// \details CRT uses the Chinese Remainder Theorem to calculate x given +/// x mod p and x mod q, and u the inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u); + +/// \brief Calculate the Jacobi symbol +/// \param a the first term +/// \param b the second term +/// \returns the the Jacobi symbol. +/// \details Jacobi symbols are calculated using the following rules: +/// -# if b is prime, then Jacobi(a, b), then return 0 +/// -# if a%b==0 AND a is quadratic residue mod b, then return 1 +/// -# return -1 otherwise +/// \details Refer to a number theory book for what Jacobi symbol means when b is not prime. +CRYPTOPP_DLL int CRYPTOPP_API Jacobi(const Integer &a, const Integer &b); + +/// \brief Calculate the Lucas value +/// \returns the Lucas value +/// \details Lucas() calculates the Lucas function V_e(p, 1) mod n. +CRYPTOPP_DLL Integer CRYPTOPP_API Lucas(const Integer &e, const Integer &p, const Integer &n); + +/// \brief Calculate the inverse Lucas value +/// \returns the inverse Lucas value +/// \details InverseLucas() calculates x such that m==Lucas(e, x, p*q), +/// p q primes, u is inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u); + +/// \brief Modular multiplication +/// \param x the first term +/// \param y the second term +/// \param m the modulus +/// \returns an Integer (x * y) % m. +inline Integer ModularMultiplication(const Integer &x, const Integer &y, const Integer &m) + {return a_times_b_mod_c(x, y, m);} + +/// \brief Modular exponentiation +/// \param x the base +/// \param e the exponent +/// \param m the modulus +/// \returns an Integer (a ^ b) % m. +inline Integer ModularExponentiation(const Integer &x, const Integer &e, const Integer &m) + {return a_exp_b_mod_c(x, e, m);} + +/// \brief Extract a modular square root +/// \param a the number to extract square root +/// \param p the prime modulus +/// \returns the modular square root if it exists +/// \details ModularSquareRoot returns x such that x*x%p == a, p prime +CRYPTOPP_DLL Integer CRYPTOPP_API ModularSquareRoot(const Integer &a, const Integer &p); + +/// \brief Extract a modular root +/// \returns a modular root if it exists +/// \details ModularRoot returns x such that a==ModularExponentiation(x, e, p*q), +/// p q primes, and e relatively prime to (p-1)*(q-1), +/// dp=d%(p-1), dq=d%(q-1), (d is inverse of e mod (p-1)*(q-1)) +/// and u=inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u); + +/// \brief Solve a Modular Quadratic Equation +/// \param r1 the first residue +/// \param r2 the second residue +/// \param a the first coefficient +/// \param b the second coefficient +/// \param c the third constant +/// \param p the prime modulus +/// \returns true if solutions exist +/// \details SolveModularQuadraticEquation() finds r1 and r2 such that ax^2 + +/// bx + c == 0 (mod p) for x in {r1, r2}, p prime. +CRYPTOPP_DLL bool CRYPTOPP_API SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p); + +/// \brief Estimate work factor +/// \param bitlength the size of the number, in bits +/// \returns the estimated work factor, in operations +/// \details DiscreteLogWorkFactor returns log base 2 of estimated number of operations to +/// calculate discrete log or factor a number. +CRYPTOPP_DLL unsigned int CRYPTOPP_API DiscreteLogWorkFactor(unsigned int bitlength); + +/// \brief Estimate work factor +/// \param bitlength the size of the number, in bits +/// \returns the estimated work factor, in operations +/// \details FactoringWorkFactor returns log base 2 of estimated number of operations to +/// calculate discrete log or factor a number. +CRYPTOPP_DLL unsigned int CRYPTOPP_API FactoringWorkFactor(unsigned int bitlength); + +// ******************************************************** + +/// \brief Generator of prime numbers of special forms +class CRYPTOPP_DLL PrimeAndGenerator +{ +public: + /// \brief Construct a PrimeAndGenerator + PrimeAndGenerator() {} + + /// \brief Construct a PrimeAndGenerator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \details PrimeAndGenerator() generates a random prime p of the form 2*q+delta, where delta is 1 or -1 and q is + /// also prime. Internally the constructor calls Generate(delta, rng, pbits, pbits-1). + /// \pre pbits > 5 + /// \warning This PrimeAndGenerator() is slow because primes of this form are harder to find. + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits) + {Generate(delta, rng, pbits, pbits-1);} + + /// \brief Construct a PrimeAndGenerator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \param qbits the number of bits in the prime q + /// \details PrimeAndGenerator() generates a random prime p of the form 2*r*q+delta, where q is also prime. + /// Internally the constructor calls Generate(delta, rng, pbits, qbits). + /// \pre qbits > 4 && pbits > qbits + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits) + {Generate(delta, rng, pbits, qbits);} + + /// \brief Generate a Prime and Generator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \param qbits the number of bits in the prime q + /// \details Generate() generates a random prime p of the form 2*r*q+delta, where q is also prime. + void Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits); + + /// \brief Retrieve first prime + /// \returns Prime() returns the prime p. + const Integer& Prime() const {return p;} + + /// \brief Retrieve second prime + /// \returns SubPrime() returns the prime q. + const Integer& SubPrime() const {return q;} + + /// \brief Retrieve the generator + /// \returns Generator() returns the the generator g. + const Integer& Generator() const {return g;} + +private: + Integer p, q, g; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/network.h b/include/cryptlib/network.h new file mode 100644 index 0000000..96b03d2 --- /dev/null +++ b/include/cryptlib/network.h @@ -0,0 +1,234 @@ +#ifndef CRYPTOPP_NETWORK_H +#define CRYPTOPP_NETWORK_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(SOCKETS_AVAILABLE) + +#include "filters.h" +#include "hrtimer.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +class LimitedBandwidth +{ +public: + LimitedBandwidth(lword maxBytesPerSecond = 0) + : m_maxBytesPerSecond(maxBytesPerSecond), m_timer(Timer::MILLISECONDS) + , m_nextTransceiveTime(0) + { m_timer.StartTimer(); } + + lword GetMaxBytesPerSecond() const + { return m_maxBytesPerSecond; } + + void SetMaxBytesPerSecond(lword v) + { m_maxBytesPerSecond = v; } + + lword ComputeCurrentTransceiveLimit(); + + double TimeToNextTransceive(); + + void NoteTransceive(lword size); + +public: + /*! GetWaitObjects() must be called despite the 0 return from GetMaxWaitObjectCount(); + the 0 is because the ScheduleEvent() method is used instead of adding a wait object */ + unsigned int GetMaxWaitObjectCount() const { return 0; } + void GetWaitObjects(WaitObjectContainer &container, const CallStack &callStack); + +private: + lword m_maxBytesPerSecond; + + typedef std::deque > OpQueue; + OpQueue m_ops; + + Timer m_timer; + double m_nextTransceiveTime; + + void ComputeNextTransceiveTime(); + double GetCurTimeAndCleanUp(); +}; + +/// a Source class that can pump from a device for a specified amount of time. +class CRYPTOPP_NO_VTABLE NonblockingSource : public AutoSignaling, public LimitedBandwidth +{ +public: + NonblockingSource(BufferedTransformation *attachment) + : m_messageEndSent(false) , m_doPumpBlocked(false), m_blockedBySpeedLimit(false) {Detach(attachment);} + + /// \name NONBLOCKING SOURCE + //@{ + + /// pump up to maxSize bytes using at most maxTime milliseconds + /*! If checkDelimiter is true, pump up to delimiter, which itself is not extracted or pumped. */ + size_t GeneralPump2(lword &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n'); + + lword GeneralPump(lword maxSize=LWORD_MAX, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n') + { + GeneralPump2(maxSize, true, maxTime, checkDelimiter, delimiter); + return maxSize; + } + lword TimedPump(unsigned long maxTime) + {return GeneralPump(LWORD_MAX, maxTime);} + lword PumpLine(byte delimiter='\n', lword maxSize=1024) + {return GeneralPump(maxSize, INFINITE_TIME, true, delimiter);} + + size_t Pump2(lword &byteCount, bool blocking=true) + {return GeneralPump2(byteCount, blocking, blocking ? INFINITE_TIME : 0);} + size_t PumpMessages2(unsigned int &messageCount, bool blocking=true); + //@} + +protected: + virtual size_t DoPump(lword &byteCount, bool blockingOutput, + unsigned long maxTime, bool checkDelimiter, byte delimiter) =0; + + bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; } + +private: + bool m_messageEndSent, m_doPumpBlocked, m_blockedBySpeedLimit; +}; + +/// Network Receiver +class CRYPTOPP_NO_VTABLE NetworkReceiver : public Waitable +{ +public: + virtual bool MustWaitToReceive() {return false;} + virtual bool MustWaitForResult() {return false;} + /// receive data from network source, returns whether result is immediately available + virtual bool Receive(byte* buf, size_t bufLen) =0; + virtual unsigned int GetReceiveResult() =0; + virtual bool EofReceived() const =0; +}; + +class CRYPTOPP_NO_VTABLE NonblockingSinkInfo +{ +public: + virtual ~NonblockingSinkInfo() {} + virtual size_t GetMaxBufferSize() const =0; + virtual size_t GetCurrentBufferSize() const =0; + virtual bool EofPending() const =0; + /// compute the current speed of this sink in bytes per second + virtual float ComputeCurrentSpeed() =0; + /// get the maximum observed speed of this sink in bytes per second + virtual float GetMaxObservedSpeed() const =0; +}; + +/// a Sink class that queues input and can flush to a device for a specified amount of time. +class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink, public NonblockingSinkInfo, public LimitedBandwidth +{ +public: + NonblockingSink() : m_blockedBySpeedLimit(false) {} + + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// flush to device for no more than maxTime milliseconds + /*! This function will repeatedly attempt to flush data to some device, until + the queue is empty, or a total of maxTime milliseconds have elapsed. + If maxTime == 0, at least one attempt will be made to flush some data, but + it is likely that not all queued data will be flushed, even if the device + is ready to receive more data without waiting. If you want to flush as much data + as possible without waiting for the device, call this function in a loop. + For example: while (sink.TimedFlush(0) > 0) {} + \return number of bytes flushed + */ + lword TimedFlush(unsigned long maxTime, size_t targetSize = 0); + + virtual void SetMaxBufferSize(size_t maxBufferSize) =0; + /// set a bound which will cause sink to flush if exceeded by GetCurrentBufferSize() + virtual void SetAutoFlushBound(size_t bound) =0; + +protected: + virtual lword DoFlush(unsigned long maxTime, size_t targetSize) = 0; + + bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; } + +private: + bool m_blockedBySpeedLimit; +}; + +/// Network Sender +class CRYPTOPP_NO_VTABLE NetworkSender : public Waitable +{ +public: + virtual bool MustWaitToSend() {return false;} + virtual bool MustWaitForResult() {return false;} + virtual void Send(const byte* buf, size_t bufLen) =0; + virtual unsigned int GetSendResult() =0; + virtual bool MustWaitForEof() {return false;} + virtual void SendEof() =0; + virtual bool EofSent() {return false;} // implement if MustWaitForEof() == true +}; + +/// Network Source +class CRYPTOPP_NO_VTABLE NetworkSource : public NonblockingSource +{ +public: + NetworkSource(BufferedTransformation *attachment); + + unsigned int GetMaxWaitObjectCount() const; + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + + bool SourceExhausted() const {return m_dataBegin == m_dataEnd && GetReceiver().EofReceived();} + +protected: + size_t DoPump(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter); + + virtual NetworkReceiver & AccessReceiver() =0; + const NetworkReceiver & GetReceiver() const {return const_cast(this)->AccessReceiver();} + +private: + SecByteBlock m_buf; + size_t m_putSize, m_dataBegin, m_dataEnd; + bool m_waitingForResult, m_outputBlocked; +}; + +/// Network Sink +class CRYPTOPP_NO_VTABLE NetworkSink : public NonblockingSink +{ +public: + NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound); + + unsigned int GetMaxWaitObjectCount() const; + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + void SetMaxBufferSize(size_t maxBufferSize) {m_maxBufferSize = maxBufferSize; m_buffer.SetNodeSize(UnsignedMin(maxBufferSize, 16U*1024U+256U));} + void SetAutoFlushBound(size_t bound) {m_autoFlushBound = bound;} + + size_t GetMaxBufferSize() const {return m_maxBufferSize;} + size_t GetCurrentBufferSize() const {return (size_t)m_buffer.CurrentSize();} + + void ClearBuffer() { m_buffer.Clear(); } + + bool EofPending() const { return m_eofState > EOF_NONE && m_eofState < EOF_DONE; } + + /// compute the current speed of this sink in bytes per second + float ComputeCurrentSpeed(); + /// get the maximum observed speed of this sink in bytes per second + float GetMaxObservedSpeed() const; + +protected: + lword DoFlush(unsigned long maxTime, size_t targetSize); + + virtual NetworkSender & AccessSender() =0; + const NetworkSender & GetSender() const {return const_cast(this)->AccessSender();} + +private: + enum EofState { EOF_NONE, EOF_PENDING_SEND, EOF_PENDING_DELIVERY, EOF_DONE }; + + size_t m_maxBufferSize, m_autoFlushBound; + bool m_needSendResult, m_wasBlocked; + EofState m_eofState; + ByteQueue m_buffer; + size_t m_skipBytes; + Timer m_speedTimer; + float m_byteCountSinceLastTimerReset, m_currentSpeed, m_maxObservedSpeed; +}; + +NAMESPACE_END + +#endif // SOCKETS_AVAILABLE + +#endif // CRYPTOPP_NETWORK_H diff --git a/include/cryptlib/nr.h b/include/cryptlib/nr.h new file mode 100644 index 0000000..c398e35 --- /dev/null +++ b/include/cryptlib/nr.h @@ -0,0 +1,6 @@ +#ifndef CRYPTOPP_NR_H +#define CRYPTOPP_NR_H + +#include "gfpcrypt.h" + +#endif diff --git a/include/cryptlib/oaep.h b/include/cryptlib/oaep.h new file mode 100644 index 0000000..a709e2a --- /dev/null +++ b/include/cryptlib/oaep.h @@ -0,0 +1,54 @@ +// oaep.h - originally written and placed in the public domain by Wei Dai + +/// \file oaep.h +/// \brief Classes for optimal asymmetric encryption padding +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_OAEP_H +#define CRYPTOPP_OAEP_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief OAEP padding base class +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL OAEP_Base : public PK_EncryptionMessageEncodingMethod +{ +public: + bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;} + size_t MaxUnpaddedLength(size_t paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedLength, const NameValuePairs ¶meters) const; + DecodingResult Unpad(const byte *padded, size_t paddedLength, byte *raw, const NameValuePairs ¶meters) const; + +protected: + virtual unsigned int DigestSize() const =0; + virtual HashTransformation * NewHash() const =0; + virtual MaskGeneratingFunction * NewMGF() const =0; +}; + +/// \brief OAEP padding +/// \tparam H HashTransformation derived class +/// \tparam MGF MaskGeneratingFunction derived class +/// \sa EME-OAEP, for use with classes derived from TF_ES +/// \since Crypto++ 2.1 +template +class OAEP : public OAEP_Base, public EncryptionStandard +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("OAEP-") + MGF::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + typedef OAEP EncryptionMessageEncodingMethod; + +protected: + unsigned int DigestSize() const {return H::DIGESTSIZE;} + HashTransformation * NewHash() const {return new H;} + MaskGeneratingFunction * NewMGF() const {return new MGF;} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS OAEP; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/oids.h b/include/cryptlib/oids.h new file mode 100644 index 0000000..92da4bd --- /dev/null +++ b/include/cryptlib/oids.h @@ -0,0 +1,156 @@ +// oids.h - originally written and placed in the public domain by Wei Dai + +/// \file oids.h +/// \brief ASN.1 object identifiers for algorthms and schemes +/// \details Most OIDs can be found at http://www.oid-info.com/. The Chinese OIDs +/// are assigned in GM/T 0006-2012, Cryptographic Application Identifier Criterion +/// Specification. A reproduction can be found at http://gmssl.org/docs/oid.html. +/// There seems to be some confusion between the text of GmSSL's oid.html web page +/// and the actual OID used in the code. We used the same OIDs that were detailed in +/// http://github.com/guanzhi/GmSSL/blob/master/crypto/objects/objects.txt. + +#ifndef CRYPTOPP_OIDS_H +#define CRYPTOPP_OIDS_H + +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +NAMESPACE_BEGIN(ASN1) + +#define DEFINE_OID(value, name) inline OID name() {return value;} + +DEFINE_OID(1, iso) + DEFINE_OID(iso()+2, member_body) + DEFINE_OID(member_body()+156, iso_cn) + DEFINE_OID(iso_cn()+10197, oscca) + DEFINE_OID(oscca()+1, sm_scheme) + DEFINE_OID(sm_scheme()+104, sms4) + DEFINE_OID(sm_scheme()+301, sm2p256v1) + DEFINE_OID(sm2p256v1()+1, sm2sign) + DEFINE_OID(sm2p256v1()+2, sm2exchange) + DEFINE_OID(sm2p256v1()+3, sm2encrypt) + DEFINE_OID(sm2encrypt()+1, sm2encrypt_recommendedParameters) + DEFINE_OID(sm2encrypt()+2, sm2encrypt_specifiedParameters) + DEFINE_OID(member_body()+840, iso_us) + DEFINE_OID(iso_us()+10040, ansi_x9_57) + DEFINE_OID(ansi_x9_57()+4+1, id_dsa) + DEFINE_OID(iso_us()+10045, ansi_x9_62) + DEFINE_OID(ansi_x9_62()+1, id_fieldType) + DEFINE_OID(id_fieldType()+1, prime_field) + DEFINE_OID(id_fieldType()+2, characteristic_two_field) + DEFINE_OID(characteristic_two_field()+3, id_characteristic_two_basis) + DEFINE_OID(id_characteristic_two_basis()+1, gnBasis) + DEFINE_OID(id_characteristic_two_basis()+2, tpBasis) + DEFINE_OID(id_characteristic_two_basis()+3, ppBasis) + DEFINE_OID(ansi_x9_62()+2, id_publicKeyType) + DEFINE_OID(id_publicKeyType()+1, id_ecPublicKey) + DEFINE_OID(ansi_x9_62()+3, ansi_x9_62_curves) + DEFINE_OID(ansi_x9_62_curves()+1, ansi_x9_62_curves_prime) + DEFINE_OID(ansi_x9_62_curves_prime()+1, secp192r1) + DEFINE_OID(ansi_x9_62_curves_prime()+7, secp256r1) + DEFINE_OID(iso_us()+113549, rsadsi) + DEFINE_OID(rsadsi()+1, pkcs) + DEFINE_OID(pkcs()+1, pkcs_1) + DEFINE_OID(pkcs_1()+1, rsaEncryption) + DEFINE_OID(rsadsi()+2, rsadsi_digestAlgorithm) + DEFINE_OID(rsadsi_digestAlgorithm()+2, id_md2) + DEFINE_OID(rsadsi_digestAlgorithm()+5, id_md5) + DEFINE_OID(iso()+3, identified_organization) + // Arc from http://tools.ietf.org/html/draft-josefsson-pkix-newcurves + DEFINE_OID(identified_organization()+6, dod) + DEFINE_OID(dod()+1, internet) + DEFINE_OID(internet()+4, internet_private) + DEFINE_OID(internet_private()+1, enterprise) + DEFINE_OID(enterprise()+11591,gnu) + DEFINE_OID(gnu()+15,ellipticCurve) + DEFINE_OID(ellipticCurve()+1,curve25519) + DEFINE_OID(ellipticCurve()+2,curve448) + DEFINE_OID(ellipticCurve()+3,curve25519ph) + DEFINE_OID(ellipticCurve()+4,curve448ph) + DEFINE_OID(identified_organization()+14, oiw) + DEFINE_OID(oiw()+3, oiw_secsig) + DEFINE_OID(oiw_secsig()+2, oiw_secsig_algorithms) + DEFINE_OID(oiw_secsig_algorithms()+26, id_sha1) + DEFINE_OID(identified_organization()+36, teletrust) + DEFINE_OID(teletrust()+3, teletrust_algorithm) + DEFINE_OID(teletrust_algorithm()+2+1, id_ripemd160) + DEFINE_OID(teletrust_algorithm()+3+2+8+1, teletrust_ellipticCurve) + DEFINE_OID(teletrust_ellipticCurve()+1+1, brainpoolP160r1) + DEFINE_OID(teletrust_ellipticCurve()+1+3, brainpoolP192r1) + DEFINE_OID(teletrust_ellipticCurve()+1+5, brainpoolP224r1) + DEFINE_OID(teletrust_ellipticCurve()+1+7, brainpoolP256r1) + DEFINE_OID(teletrust_ellipticCurve()+1+9, brainpoolP320r1) + DEFINE_OID(teletrust_ellipticCurve()+1+11, brainpoolP384r1) + DEFINE_OID(teletrust_ellipticCurve()+1+13, brainpoolP512r1) + DEFINE_OID(identified_organization()+132, certicom) + DEFINE_OID(certicom()+0, certicom_ellipticCurve) + // these are sorted by curve type and then by OID + // first curves based on GF(p) + DEFINE_OID(certicom_ellipticCurve()+6, secp112r1) + DEFINE_OID(certicom_ellipticCurve()+7, secp112r2) + DEFINE_OID(certicom_ellipticCurve()+8, secp160r1) + DEFINE_OID(certicom_ellipticCurve()+9, secp160k1) + DEFINE_OID(certicom_ellipticCurve()+10, secp256k1) + DEFINE_OID(certicom_ellipticCurve()+28, secp128r1) + DEFINE_OID(certicom_ellipticCurve()+29, secp128r2) + DEFINE_OID(certicom_ellipticCurve()+30, secp160r2) + DEFINE_OID(certicom_ellipticCurve()+31, secp192k1) + DEFINE_OID(certicom_ellipticCurve()+32, secp224k1) + DEFINE_OID(certicom_ellipticCurve()+33, secp224r1) + DEFINE_OID(certicom_ellipticCurve()+34, secp384r1) + DEFINE_OID(certicom_ellipticCurve()+35, secp521r1) + // then curves based on GF(2^n) + DEFINE_OID(certicom_ellipticCurve()+1, sect163k1) + DEFINE_OID(certicom_ellipticCurve()+2, sect163r1) + DEFINE_OID(certicom_ellipticCurve()+3, sect239k1) + DEFINE_OID(certicom_ellipticCurve()+4, sect113r1) + DEFINE_OID(certicom_ellipticCurve()+5, sect113r2) + DEFINE_OID(certicom_ellipticCurve()+15, sect163r2) + DEFINE_OID(certicom_ellipticCurve()+16, sect283k1) + DEFINE_OID(certicom_ellipticCurve()+17, sect283r1) + DEFINE_OID(certicom_ellipticCurve()+22, sect131r1) + DEFINE_OID(certicom_ellipticCurve()+23, sect131r2) + DEFINE_OID(certicom_ellipticCurve()+24, sect193r1) + DEFINE_OID(certicom_ellipticCurve()+25, sect193r2) + DEFINE_OID(certicom_ellipticCurve()+26, sect233k1) + DEFINE_OID(certicom_ellipticCurve()+27, sect233r1) + DEFINE_OID(certicom_ellipticCurve()+36, sect409k1) + DEFINE_OID(certicom_ellipticCurve()+37, sect409r1) + DEFINE_OID(certicom_ellipticCurve()+38, sect571k1) + DEFINE_OID(certicom_ellipticCurve()+39, sect571r1) +DEFINE_OID(2, joint_iso_ccitt) + DEFINE_OID(joint_iso_ccitt()+16, country) + DEFINE_OID(country()+840, joint_iso_ccitt_us) + DEFINE_OID(joint_iso_ccitt_us()+1, us_organization) + DEFINE_OID(us_organization()+101, us_gov) + DEFINE_OID(us_gov()+3, csor) + DEFINE_OID(csor()+4, nistalgorithms) + DEFINE_OID(nistalgorithms()+1, aes) + DEFINE_OID(aes()+1, id_aes128_ECB) + DEFINE_OID(aes()+2, id_aes128_cbc) + DEFINE_OID(aes()+3, id_aes128_ofb) + DEFINE_OID(aes()+4, id_aes128_cfb) + DEFINE_OID(aes()+21, id_aes192_ECB) + DEFINE_OID(aes()+22, id_aes192_cbc) + DEFINE_OID(aes()+23, id_aes192_ofb) + DEFINE_OID(aes()+24, id_aes192_cfb) + DEFINE_OID(aes()+41, id_aes256_ECB) + DEFINE_OID(aes()+42, id_aes256_cbc) + DEFINE_OID(aes()+43, id_aes256_ofb) + DEFINE_OID(aes()+44, id_aes256_cfb) + DEFINE_OID(nistalgorithms()+2, nist_hashalgs) + DEFINE_OID(nist_hashalgs()+1, id_sha256) + DEFINE_OID(nist_hashalgs()+2, id_sha384) + DEFINE_OID(nist_hashalgs()+3, id_sha512) + DEFINE_OID(nist_hashalgs()+4, id_sha224) + DEFINE_OID(nist_hashalgs()+7, id_sha3_224) + DEFINE_OID(nist_hashalgs()+8, id_sha3_256) + DEFINE_OID(nist_hashalgs()+9, id_sha3_384) + DEFINE_OID(nist_hashalgs()+10, id_sha3_512) + +NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/osrng.h b/include/cryptlib/osrng.h new file mode 100644 index 0000000..290e76a --- /dev/null +++ b/include/cryptlib/osrng.h @@ -0,0 +1,277 @@ +// osrng.h - originally written and placed in the public domain by Wei Dai + +/// \file osrng.h +/// \brief Classes for access to the operating system's random number generators + +#ifndef CRYPTOPP_OSRNG_H +#define CRYPTOPP_OSRNG_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) + +#include "cryptlib.h" +#include "randpool.h" +#include "smartptr.h" +#include "fips140.h" +#include "rng.h" +#include "aes.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when an operating system error is encountered +class CRYPTOPP_DLL OS_RNG_Err : public Exception +{ +public: + /// \brief Constructs an OS_RNG_Err + /// \param operation the operation or API call when the error occurs + OS_RNG_Err(const std::string &operation); +}; + +#ifdef NONBLOCKING_RNG_AVAILABLE + +#ifdef CRYPTOPP_WIN32_AVAILABLE +/// \brief Wrapper for Microsoft crypto service provider +/// \sa \def USE_MS_CRYPTOAPI, \def USE_MS_CNGAPI +class CRYPTOPP_DLL MicrosoftCryptoProvider +{ +public: + /// \brief Construct a MicrosoftCryptoProvider + MicrosoftCryptoProvider(); + ~MicrosoftCryptoProvider(); + +// type HCRYPTPROV and BCRYPT_ALG_HANDLE, avoid #include +#if defined(USE_MS_CRYPTOAPI) +# if defined(__CYGWIN__) && defined(__x86_64__) + typedef unsigned long long ProviderHandle; +# elif defined(WIN64) || defined(_WIN64) + typedef unsigned __int64 ProviderHandle; +# else + typedef unsigned long ProviderHandle; +# endif +#elif defined(USE_MS_CNGAPI) + typedef void *PVOID; + typedef PVOID ProviderHandle; +#endif // USE_MS_CRYPTOAPI or USE_MS_CNGAPI + + /// \brief Retrieves the provider handle + /// \returns CryptoAPI provider handle + /// \details If USE_MS_CRYPTOAPI is in effect, then CryptAcquireContext() + /// acquires then handle and CryptReleaseContext() releases the handle + /// upon destruction. If USE_MS_CNGAPI is in effect, then + /// BCryptOpenAlgorithmProvider() acquires then handle and + /// BCryptCloseAlgorithmProvider() releases the handle upon destruction. + ProviderHandle GetProviderHandle() const {return m_hProvider;} + +private: + ProviderHandle m_hProvider; +}; + +#if defined(_MSC_VER) && defined(USE_MS_CRYPTOAPI) +# pragma comment(lib, "advapi32.lib") +#endif + +#if defined(_MSC_VER) && defined(USE_MS_CNGAPI) +# pragma comment(lib, "bcrypt.lib") +#endif + +#endif // CRYPTOPP_WIN32_AVAILABLE + +/// \brief Wrapper class for /dev/random and /dev/srandom +/// \details Encapsulates CryptoAPI's CryptGenRandom() or CryptoNG's BCryptGenRandom() +/// on Windows, or /dev/urandom on Unix and compatibles. +class CRYPTOPP_DLL NonblockingRng : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "NonblockingRng"; } + + ~NonblockingRng(); + + /// \brief Construct a NonblockingRng + NonblockingRng(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock(). + void GenerateBlock(byte *output, size_t size); + +protected: +#ifdef CRYPTOPP_WIN32_AVAILABLE + MicrosoftCryptoProvider m_Provider; +#else + int m_fd; +#endif +}; + +#endif + +#if defined(BLOCKING_RNG_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Wrapper class for /dev/random and /dev/srandom +/// \details Encapsulates /dev/random on Linux, OS X and Unix; and /dev/srandom on the BSDs. +/// \note On Linux the /dev/random interface is effectively deprecated. According to the +/// Kernel Crypto developers, /dev/urandom or getrandom(2) should be used instead. Also +/// see [RFC PATCH v12 3/4] Linux Random +/// Number Generator on the kernel-crypto mailing list. +class CRYPTOPP_DLL BlockingRng : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "BlockingRng"; } + + ~BlockingRng(); + + /// \brief Construct a BlockingRng + BlockingRng(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock(). + void GenerateBlock(byte *output, size_t size); + +protected: + int m_fd; +}; + +#endif + +/// OS_GenerateRandomBlock +/// \brief Generate random array of bytes +/// \param blocking specifies whther a bobcking or non-blocking generator should be used +/// \param output the byte buffer +/// \param size the length of the buffer, in bytes +/// \details OS_GenerateRandomBlock() uses the underlying operating system's +/// random number generator. On Windows, CryptGenRandom() is called using NonblockingRng. +/// \details On Unix and compatibles, /dev/urandom is called if blocking is false using +/// NonblockingRng. If blocking is true, then either /dev/randomd or /dev/srandom is used +/// by way of BlockingRng, if available. +CRYPTOPP_DLL void CRYPTOPP_API OS_GenerateRandomBlock(bool blocking, byte *output, size_t size); + +/// \brief Automatically Seeded Randomness Pool +/// \details This class seeds itself using an operating system provided RNG. +/// AutoSeededRandomPool was suggested by Leonard Janke. +class CRYPTOPP_DLL AutoSeededRandomPool : public RandomPool +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "AutoSeededRandomPool"; } + + ~AutoSeededRandomPool() {} + + /// \brief Construct an AutoSeededRandomPool + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param seedSize the size of the seed, in bytes + /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng. + /// The parameter is ignored if only one of these is available. + explicit AutoSeededRandomPool(bool blocking = false, unsigned int seedSize = 32) + {Reseed(blocking, seedSize);} + + /// \brief Reseed an AutoSeededRandomPool + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param seedSize the size of the seed, in bytes + void Reseed(bool blocking = false, unsigned int seedSize = 32); +}; + +/// \tparam BLOCK_CIPHER a block cipher +/// \brief Automatically Seeded X9.17 RNG +/// \details AutoSeededX917RNG is from ANSI X9.17 Appendix C, seeded using an OS provided RNG. +/// If 3-key TripleDES (DES_EDE3) is used, then its a X9.17 conforming generator. If AES is +/// used, then its a X9.31 conforming generator. +/// \details Though ANSI X9 prescribes 3-key TripleDES, the template parameter BLOCK_CIPHER can be any +/// BlockTransformation derived class. +/// \sa X917RNG, DefaultAutoSeededRNG +template +class AutoSeededX917RNG : public RandomNumberGenerator, public NotCopyable +{ +public: + static std::string StaticAlgorithmName() { return std::string("AutoSeededX917RNG(") + BLOCK_CIPHER::StaticAlgorithmName() + std::string(")"); } + + ~AutoSeededX917RNG() {} + + /// \brief Construct an AutoSeededX917RNG + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param autoSeed controls auto seeding of the generator + /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng. + /// The parameter is ignored if only one of these is available. + /// \sa X917RNG + explicit AutoSeededX917RNG(bool blocking = false, bool autoSeed = true) + {if (autoSeed) Reseed(blocking);} + + /// \brief Reseed an AutoSeededX917RNG + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param additionalEntropy additional entropy to add to the generator + /// \param length the size of the additional entropy, in bytes + /// \details Internally, the generator uses SHA256 to extract the entropy from + /// from the seed and then stretch the material for the block cipher's key + /// and initialization vector. + void Reseed(bool blocking = false, const byte *additionalEntropy = NULLPTR, size_t length = 0); + + /// \brief Deterministically reseed an AutoSeededX917RNG for testing + /// \param key the key to use for the deterministic reseeding + /// \param keylength the size of the key, in bytes + /// \param seed the seed to use for the deterministic reseeding + /// \param timeVector a time vector to use for deterministic reseeding + /// \details This is a testing interface for testing purposes, and should \a NOT + /// be used in production. + void Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector); + + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length) {Reseed(false, input, length);} + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length) + {m_rng->GenerateIntoBufferedTransformation(target, channel, length);} + +private: + member_ptr m_rng; +}; + +template +void AutoSeededX917RNG::Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector) +{ + m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector)); +} + +template +void AutoSeededX917RNG::Reseed(bool blocking, const byte *input, size_t length) +{ + SecByteBlock seed(BLOCK_CIPHER::BLOCKSIZE + BLOCK_CIPHER::DEFAULT_KEYLENGTH); + const byte *key; + do + { + OS_GenerateRandomBlock(blocking, seed, seed.size()); + if (length > 0) + { + SHA256 hash; + hash.Update(seed, seed.size()); + hash.Update(input, length); + hash.TruncatedFinal(seed, UnsignedMin(hash.DigestSize(), seed.size())); + } + key = seed + BLOCK_CIPHER::BLOCKSIZE; + } // check that seed and key don't have same value + while (memcmp(key, seed, STDMIN((unsigned int)BLOCK_CIPHER::BLOCKSIZE, (unsigned int)BLOCK_CIPHER::DEFAULT_KEYLENGTH)) == 0); + + Reseed(key, BLOCK_CIPHER::DEFAULT_KEYLENGTH, seed, NULLPTR); +} + +CRYPTOPP_DLL_TEMPLATE_CLASS AutoSeededX917RNG; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief A typedef providing a default generator +/// \details DefaultAutoSeededRNG is a typedef of either AutoSeededX917RNG or AutoSeededRandomPool. +/// If CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined, then DefaultAutoSeededRNG is +/// AutoSeededX917RNG. Otherwise, DefaultAutoSeededRNG is AutoSeededRandomPool. +class DefaultAutoSeededRNG {} +#else +// AutoSeededX917RNG in FIPS mode, otherwise it's AutoSeededRandomPool +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +typedef AutoSeededX917RNG DefaultAutoSeededRNG; +#else +typedef AutoSeededRandomPool DefaultAutoSeededRNG; +#endif +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +#endif + +#endif diff --git a/include/cryptlib/ossig.h b/include/cryptlib/ossig.h new file mode 100644 index 0000000..c6511ef --- /dev/null +++ b/include/cryptlib/ossig.h @@ -0,0 +1,128 @@ +// ossig.h - written and placed in the public domain by Jeffrey Walton +// +/// \file ossig.h +/// \brief Utility class for trapping OS signals. +/// \since Crypto++ 5.6.5 + +#ifndef CRYPTOPP_OS_SIGNAL_H +#define CRYPTOPP_OS_SIGNAL_H + +#include "config.h" + +#if defined(UNIX_SIGNALS_AVAILABLE) +# include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** Unix and Linux compatibles *************** + +#if defined(UNIX_SIGNALS_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Signal handler function pointer +/// \details SignalHandlerFn is provided as a stand alone function pointer with external "C" linkage +/// \sa SignalHandler, NullSignalHandler +extern "C" { + typedef void (*SignalHandlerFn) (int); +} + +/// \brief Null signal handler function +/// \param unused the signal number +/// \details NullSignalHandler is provided as a stand alone function with external "C" linkage +/// and not a static member function due to the the member function's implicit +/// external "C++" linkage. +/// \sa SignalHandler, SignalHandlerFn +extern "C" { + inline void NullSignalHandler(int unused) {CRYPTOPP_UNUSED(unused);} +} + +/// Signal handler for Linux and Unix compatibles +/// \tparam S Signal number +/// \tparam O Flag indicating exsting handler should be overwriiten +/// \details SignalHandler() can be used to install a signal handler with the signature +/// void handler_fn(int). If SignalHandlerFn is not NULL, then +/// the sigaction is set to the function and the sigaction flags is set to the flags. +/// If SignalHandlerFn is NULL, then a default handler is installed +/// using sigaction flags set to 0. The default handler only returns from the call. +/// \details Upon destruction the previous signal handler is restored if the former signal handler +/// was replaced. +/// \details On Cygwin systems using Newlib, you should define _XOPEN_SOURCE=700 or +/// _GNU_SOURCE; or use -std=gnu++03, -std=gnu++11, or similar. If +/// you compile with -std=c++03, -std=c++11 or similar, then define +/// _XOPEN_SOURCE=700. +/// \warning Do not use SignalHandler in a code block that uses setjmp or longjmp +/// because the destructor may not run. +/// \since Crypto++ 5.6.5 +/// \sa NullSignalHandler, SignalHandlerFn, \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", DebugTrapHandler +template +struct SignalHandler +{ + /// \brief Construct a signal handler + /// \param pfn Pointer to a signal handler function + /// \param flags Flags to use with the signal handler + /// \details SignalHandler() installs a signal handler with the signature + /// void handler_fn(int). If SignalHandlerFn is not NULL, then + /// the sigaction is set to the function and the sigaction flags is set to the flags. + /// If SignalHandlerFn is NULL, then a default handler is installed + /// using sigaction flags set to 0. The default handler only returns from the call. + /// \details Upon destruction the previous signal handler is restored if the former signal handler + /// was overwritten. + /// \details On Cygwin systems using Newlib, you should define _XOPEN_SOURCE=700 or + /// _GNU_SOURCE; or use -std=gnu++03, -std=gnu++11, or similar. If + /// you compile with -std=c++03, -std=c++11 or similar, then define + /// _XOPEN_SOURCE=700. + /// \warning Do not use SignalHandler in a code block that uses setjmp or longjmp + /// because the destructor may not run. setjmp is why cpu.cpp does not use SignalHandler + /// during CPU feature testing. + /// \since Crypto++ 5.6.5 + SignalHandler(SignalHandlerFn pfn = NULLPTR, int flags = 0) : m_installed(false) + { + // http://pubs.opengroup.org/onlinepubs/007908799/xsh/sigaction.html + struct sigaction new_handler; + + do + { + int ret = 0; + + ret = sigaction (S, 0, &m_old); + if (ret != 0) break; // Failed + + // Don't step on another's handler if Overwrite=false + if (m_old.sa_handler != 0 && !O) break; + + // Cygwin/Newlib requires -D_XOPEN_SOURCE=700 + ret = sigemptyset (&new_handler.sa_mask); + if (ret != 0) break; // Failed + + new_handler.sa_handler = (pfn ? pfn : &NullSignalHandler); + new_handler.sa_flags = (pfn ? flags : 0); + + // Install it + ret = sigaction (S, &new_handler, 0); + if (ret != 0) break; // Failed + + m_installed = true; + + } while(0); + } + + ~SignalHandler() + { + if (m_installed) + sigaction (S, &m_old, 0); + } + +private: + struct sigaction m_old; + bool m_installed; + +private: + // Not copyable + SignalHandler(const SignalHandler &); + void operator=(const SignalHandler &); +}; +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_OS_SIGNAL_H diff --git a/include/cryptlib/padlkrng.h b/include/cryptlib/padlkrng.h new file mode 100644 index 0000000..dc27cbd --- /dev/null +++ b/include/cryptlib/padlkrng.h @@ -0,0 +1,136 @@ +// via-rng.h - written and placed in public domain by Jeffrey Walton + +/// \file padlkrng.h +/// \brief Classes for VIA Padlock RNG +/// \since Crypto++ 6.0 +/// \sa VIA +/// Padlock on the Crypto++ wiki + +#ifndef CRYPTOPP_PADLOCK_RNG_H +#define CRYPTOPP_PADLOCK_RNG_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a PadlockRNG generator encounters +/// a generator related error. +/// \since Crypto++ 6.0 +class PadlockRNG_Err : public Exception +{ +public: + PadlockRNG_Err(const std::string &operation) + : Exception(OTHER_ERROR, "PadlockRNG: " + operation + " operation failed") {} + PadlockRNG_Err(const std::string &component, const std::string &message) + : Exception(OTHER_ERROR, component + ": " + message) {} +}; + +/// \brief Hardware generated random numbers using VIA XSTORE +/// \details Some VIA processors provide a Security Engine called Padlock. The Padlock +/// Security Engine provides AES, SHA and a RNG. The PadlockRNG class provides access +/// to the RNG. +/// \details The VIA generator uses an 8 byte FIFO buffer for random numbers. The +/// generator can be configured to discard bits from the buffer to resist analysis. +/// The divisor controls the number of bytes discarded. The formula for +/// the discard amount is 2**divisor - 1. When divisor=0 no bits +/// are discarded and the entire 8 byte buffer is read. If divisor=3 then +/// 7 bytes are discarded and 1 byte is read. TheVIA SDK samples use divisor=1. +/// \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine +/// in 2003. CRI provided recommendations to operate the generator for secure and +/// non-secure applications. Additionally, the Programmers Guide and SDK provided a +/// different configuration in the sample code. +/// \details You can operate the generator according to CRI recommendations by setting +/// divisor, reading one word (or partial word) at a time from the FIFO, and +/// then inspecting the MSR after each read. +/// \details The audit report with recommendations is available on the Crypto++ wiki +/// at VIA Padlock. +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 6.0 +class PadlockRNG : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "PadlockRNG"; } + + virtual ~PadlockRNG() {} + + /// \brief Construct a PadlockRNG generator + /// \param divisor the XSTORE divisor + /// \details Some VIA processors provide a Security Engine called Padlock. The Padlock + /// Security Engine provides AES, SHA and a RNG. The PadlockRNG class provides access + /// to the RNG. + /// \details The VIA generator uses an 8 byte FIFO buffer for random numbers. The + /// generator can be configured to discard bits from the buffer to resist analysis. + /// The divisor controls the number of bytes discarded. The formula for + /// the discard amount is 2**divisor - 1. When divisor=0 no bits + /// are discarded and the entire 8 byte buffer is read. If divisor=3 then + /// 7 bytes are discarded and 1 byte is read. VIA SDK samples use divisor=1. + /// \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine + /// in 2003. CRI provided recommendations to operate the generator for secure and + /// non-secure applications. Additionally, the Programmers SDK provided a different + /// configuration in the sample code. + /// \details The audit report with recommendations is available on the Crypto++ wiki + /// at VIA Padlock. + /// \sa SetDivisor, GetDivisor + PadlockRNG(word32 divisor=1); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the Padlock generator discards words, not bytes. If n is + /// not a multiple of a 32-bit word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + /// \brief Set the XSTORE divisor + /// \param divisor the XSTORE divisor + /// \returns the old XSTORE divisor + word32 SetDivisor(word32 divisor) + { + word32 old = m_divisor; + m_divisor = DivisorHelper(divisor); + return old; + } + + /// \brief Get the XSTORE divisor + /// \returns the current XSTORE divisor + word32 GetDivisor() const + { + return m_divisor; + } + + /// \brief Get the MSR for the last operation + /// \returns the MSR for the last read operation + word32 GetMSR() const + { + return m_msr; + } + +protected: + inline word32 DivisorHelper(word32 divisor) + { + return divisor > 3 ? 3 : divisor; + } + +private: + FixedSizeAlignedSecBlock m_buffer; + word32 m_divisor, m_msr; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_PADLOCK_RNG_H diff --git a/include/cryptlib/panama.h b/include/cryptlib/panama.h new file mode 100644 index 0000000..268b8cf --- /dev/null +++ b/include/cryptlib/panama.h @@ -0,0 +1,157 @@ +// panama.h - originally written and placed in the public domain by Wei Dai + +/// \file panama.h +/// \brief Classes for Panama hash and stream cipher + +#ifndef CRYPTOPP_PANAMA_H +#define CRYPTOPP_PANAMA_H + +#include "strciphr.h" +#include "iterhash.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler error with .intel_syntax +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_INTEL_ASM) +# define CRYPTOPP_DISABLE_PANAMA_ASM +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// Base class, do not use directly +template +class CRYPTOPP_NO_VTABLE Panama +{ +public: + void Reset(); + void Iterate(size_t count, const word32 *p=NULLPTR, byte *output=NULLPTR, const byte *input=NULLPTR, KeystreamOperation operation=WRITE_KEYSTREAM); + +protected: + typedef word32 Stage[8]; + CRYPTOPP_CONSTANT(STAGES = 32) + + FixedSizeAlignedSecBlock m_state; +}; + +namespace Weak { +/// \brief Panama hash +/// \sa Panama Hash +template +class PanamaHash : protected Panama, public AlgorithmImpl, PanamaHash > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 32) + PanamaHash() {Panama::Reset();} + unsigned int DigestSize() const {return DIGESTSIZE;} + void TruncatedFinal(byte *hash, size_t size); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} + +protected: + void Init() {Panama::Reset();} + void HashEndianCorrectedBlock(const word32 *data) {this->Iterate(1, data);} // push + size_t HashMultipleBlocks(const word32 *input, size_t length); + word32* StateBuf() {return NULLPTR;} +}; +} + +/// \brief MAC construction using a hermetic hash function +template +class HermeticHashFunctionMAC : public AlgorithmImpl > >, T_Info> +{ +public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(params); + + m_key.Assign(key, length); + Restart(); + } + + void Restart() + { + m_hash.Restart(); + m_keyed = false; + } + + void Update(const byte *input, size_t length) + { + if (!m_keyed) + KeyHash(); + m_hash.Update(input, length); + } + + void TruncatedFinal(byte *digest, size_t digestSize) + { + if (!m_keyed) + KeyHash(); + m_hash.TruncatedFinal(digest, digestSize); + m_keyed = false; + } + + unsigned int DigestSize() const + {return m_hash.DigestSize();} + unsigned int BlockSize() const + {return m_hash.BlockSize();} + unsigned int OptimalBlockSize() const + {return m_hash.OptimalBlockSize();} + unsigned int OptimalDataAlignment() const + {return m_hash.OptimalDataAlignment();} + +protected: + void KeyHash() + { + m_hash.Update(m_key, m_key.size()); + m_keyed = true; + } + + T_Hash m_hash; + bool m_keyed; + SecByteBlock m_key; +}; + +namespace Weak { +/// \brief Panama message authentication code +template +class PanamaMAC : public HermeticHashFunctionMAC > +{ +public: + PanamaMAC() {} + PanamaMAC(const byte *key, unsigned int length) + {this->SetKey(key, length);} +}; +} + +/// \brief Panama stream cipher information +template +struct PanamaCipherInfo : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} +}; + +/// \brief Panama stream cipher operation +template +class PanamaCipherPolicy : public AdditiveCipherConcretePolicy, + public PanamaCipherInfo, + protected Panama +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CipherIsRandomAccess() const {return false;} + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + unsigned int GetAlignment() const; + + FixedSizeSecBlock m_key; +}; + +/// \brief Panama stream cipher +/// \sa Panama Stream Cipher +template +struct PanamaCipher : public PanamaCipherInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, PanamaCipherInfo > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/pch.h b/include/cryptlib/pch.h new file mode 100644 index 0000000..2cd163e --- /dev/null +++ b/include/cryptlib/pch.h @@ -0,0 +1,31 @@ +// pch.h - originally written and placed in the public domain by Wei Dai + +/// \file pch.h +/// \brief Precompiled header file +/// \details The precompiled header files are used Windows. + +#ifndef CRYPTOPP_PCH_H +#define CRYPTOPP_PCH_H + +# ifdef CRYPTOPP_GENERATE_X64_MASM + #include "cpu.h" + +# else + #include "config.h" + + #ifdef USE_PRECOMPILED_HEADERS + #include "simple.h" + #include "secblock.h" + #include "misc.h" + #include "smartptr.h" + #include "stdcpp.h" + #endif +# endif + +// Enable file and line numbers, if available. +// #if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_PRECOMPILED_HEADERS) +// # define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +// # define new DEBUG_NEW +// #endif + +#endif // CRYPTOPP_PCH_H diff --git a/include/cryptlib/pkcspad.h b/include/cryptlib/pkcspad.h new file mode 100644 index 0000000..f112c52 --- /dev/null +++ b/include/cryptlib/pkcspad.h @@ -0,0 +1,123 @@ +// pkcspad.h - originally written and placed in the public domain by Wei Dai + +/// \file pkcspad.h +/// \brief Classes for PKCS padding schemes +/// \details PKCS #1 v1.5, v2.0 and P1363a allow MD2, MD5, SHA1, SHA224, SHA256, SHA384, +/// SHA512, Tiger and RipeMd-160 to be instantiated. + +#ifndef CRYPTOPP_PKCSPAD_H +#define CRYPTOPP_PKCSPAD_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "hashfwd.h" + +#ifdef CRYPTOPP_IS_DLL +#include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief PKCS #1 v1.5 Encryption Padding Scheme +/// \sa EME-PKCS1-v1_5 +class PKCS_EncryptionPaddingScheme : public PK_EncryptionMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EME-PKCS1-v1_5";} + + size_t MaxUnpaddedLength(size_t paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedLength, const NameValuePairs ¶meters) const; + DecodingResult Unpad(const byte *padded, size_t paddedLength, byte *raw, const NameValuePairs ¶meters) const; +}; + +/// \brief PKCS #1 decoration data structure +template class PKCS_DigestDecoration +{ +public: + static const byte decoration[]; + static const unsigned int length; +}; + +// PKCS_DigestDecoration can be instantiated with the following +// classes as specified in PKCS #1 v2.0 and P1363a +// SHA1, SHA224, SHA256, SHA384, SHA512, Tiger, RIPEMD160, MD2, MD5 + +#if defined(CRYPTOPP_IS_DLL) +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +// http://github.com/weidai11/cryptopp/issues/517 +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +#endif + +// https://github.com/weidai11/cryptopp/issues/300 and +// https://github.com/weidai11/cryptopp/issues/533 +#if defined(__clang__) +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; + +// http://github.com/weidai11/cryptopp/issues/517 +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; + +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +#endif + +/// \brief PKCS #1 v1.5 Signature Encoding Scheme +/// \sa EMSA-PKCS1-v1_5 +class CRYPTOPP_DLL PKCS1v15_SignatureMessageEncodingMethod : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA-PKCS1-v1_5";} + + size_t MinRepresentativeBitLength(size_t hashIdentifierSize, size_t digestSize) const + {return 8 * (digestSize + hashIdentifierSize + 10);} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; + + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(PKCS_DigestDecoration::decoration, PKCS_DigestDecoration::length); + } + }; + }; +}; + +/// \brief PKCS #1 version 1.5, for use with RSAES and RSASS +/// \dontinclude pkcspad.h + +struct PKCS1v15 : public SignatureStandard, public EncryptionStandard +{ + typedef PKCS_EncryptionPaddingScheme EncryptionMessageEncodingMethod; + typedef PKCS1v15_SignatureMessageEncodingMethod SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/poly1305.h b/include/cryptlib/poly1305.h new file mode 100644 index 0000000..3a2b799 --- /dev/null +++ b/include/cryptlib/poly1305.h @@ -0,0 +1,167 @@ +// poly1305.h - written and placed in the public domain by Jeffrey Walton and Jean-Pierre Munch +// Based on Andy Polyakov's Base-2^26 scalar multiplication implementation for OpenSSL. + +/// \file poly1305.h +/// \brief Classes for Poly1305 message authentication code +/// \details Poly1305-AES is a state-of-the-art message-authentication code suitable for a wide +/// variety of applications. Poly1305-AES computes a 16-byte authenticator of a variable-length +/// message, using a 16-byte AES key, a 16-byte additional key, and a 16-byte nonce. +/// \details Each message must use a unique security context, which means either the key or nonce +/// must be changed after each message. It can be accomplished in one of two ways. First, you +/// can create a new Poly1305 object with a key and nonce each time its needed. +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   Poly1305 poly1305(key, key.size(), nonce, nonce.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+/// +/// \details Second, you can create a Poly1305 object, reuse the key, and set a fresh nonce +/// for each message. The second and subsequent nonces can be generated directly using a +/// RandomNumberGenerator() derived class; or it can be generated using GetNextIV(). +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   // First message
+///   Poly1305 poly1305(key, key.size());
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///
+///   // Second message
+///   poly1305.GetNextIV(prng, nonce);
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///   ...
+/// \sa Daniel J. Bernstein The Poly1305-AES +/// Message-Authentication Code (20050329) and Andy Polyakov Poly1305 Revised +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_POLY1305_H +#define CRYPTOPP_POLY1305_H + +#include "cryptlib.h" +#include "seckey.h" +#include "secblock.h" +#include "argnames.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Poly1305 message authentication code base class +/// \tparam T class derived from BlockCipherDocumentation with 16-byte key and 16-byte blocksize +/// \since Crypto++ 6.0 +template +class CRYPTOPP_NO_VTABLE Poly1305_Base : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 16>, public MessageAuthenticationCode +{ + CRYPTOPP_COMPILE_ASSERT(T::DEFAULT_KEYLENGTH == 16); + CRYPTOPP_COMPILE_ASSERT(T::BLOCKSIZE == 16); + +public: + static std::string StaticAlgorithmName() {return std::string("Poly1305(") + T::StaticAlgorithmName() + ")";} + + CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE) + CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE) + + Poly1305_Base() : m_idx(0), m_used(true) {} + + void Resynchronize (const byte *iv, int ivLength=-1); + void GetNextIV (RandomNumberGenerator &rng, byte *iv); + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + void Restart(); + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return DIGESTSIZE;} + +protected: + void HashBlocks(const byte *input, size_t length, word32 padbit); + void HashFinal(byte *mac, size_t length); + + typename T::Encryption m_cipher; + + // Accumulated hash, clamped r-key, and encrypted nonce + FixedSizeAlignedSecBlock m_h; + FixedSizeAlignedSecBlock m_r; + FixedSizeAlignedSecBlock m_n; + + // Accumulated message bytes and index + FixedSizeAlignedSecBlock m_acc, m_nk; + size_t m_idx; + + // Track nonce reuse; assert in debug but continue + bool m_used; +}; + +/// \brief Poly1305 message authentication code +/// \tparam T class derived from BlockCipherDocumentation with 16-byte key and 16-byte blocksize +/// \details Poly1305-AES is a state-of-the-art message-authentication code suitable for a wide +/// variety of applications. Poly1305-AES computes a 16-byte authenticator of a variable-length +/// message, using a 16-byte AES key, a 16-byte additional key, and a 16-byte nonce. +/// \details Each message must use a unique security context, which means either the key or nonce +/// must be changed after each message. It can be accomplished in one of two ways. First, you +/// can create a new Poly1305 object with a key and nonce each time its needed. +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   Poly1305 poly1305(key, key.size(), nonce, nonce.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+/// +/// \details Second, you can create a Poly1305 object, reuse the key, and set a fresh nonce +/// for each message. The second and subsequent nonces can be generated directly using a +/// RandomNumberGenerator() derived class; or it can be generated using GetNextIV(). +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   // First message
+///   Poly1305 poly1305(key, key.size());
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///
+///   // Second message
+///   poly1305.GetNextIV(prng, nonce);
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///   ...
+/// \warning The Poly1305 class does not enforce a fresh nonce for each message. The source code +/// will assert in debug builds to alert of nonce reuse. No action is taken in release builds. +/// \sa Daniel J. Bernstein The Poly1305-AES +/// Message-Authentication Code (20050329) and Andy Polyakov Poly1305 Revised +/// \since Crypto++ 6.0 +template +class Poly1305 : public MessageAuthenticationCodeFinal > +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=Poly1305_Base::DEFAULT_KEYLENGTH) + + /// \brief Construct a Poly1305 + Poly1305() {} + + /// \brief Construct a Poly1305 + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array, in bytes + /// \param nonce a byte array used to key the cipher + /// \param nonceLength the size of the byte array, in bytes + /// \details key is the 32-byte key composed of the 16-byte AES key and the 16 additional key + /// bytes used for r. + /// \details Each message requires a unique security context. You can use GetNextIV() and + /// Resynchronize() to set a new nonce under a key for a message. + Poly1305(const byte *key, size_t keyLength=DEFAULT_KEYLENGTH, const byte *nonce=NULLPTR, size_t nonceLength=0) + {this->SetKey(key, keyLength, MakeParameters(Name::IV(), ConstByteArrayParameter(nonce, nonceLength)));} +}; + +NAMESPACE_END + +#endif // CRYPTOPP_POLY1305_H diff --git a/include/cryptlib/polynomi.h b/include/cryptlib/polynomi.h new file mode 100644 index 0000000..9a754ef --- /dev/null +++ b/include/cryptlib/polynomi.h @@ -0,0 +1,463 @@ +// polynomi.h - originally written and placed in the public domain by Wei Dai + +/// \file polynomi.h +/// \brief Classes for polynomial basis and operations + +#ifndef CRYPTOPP_POLYNOMI_H +#define CRYPTOPP_POLYNOMI_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algebra.h" +#include "misc.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// represents single-variable polynomials over arbitrary rings +/*! \nosubgrouping */ +template class PolynomialOver +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// division by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialOver: division by zero") {} + }; + + /// specify the distribution for randomization functions + class RandomizationParameter + { + public: + RandomizationParameter(unsigned int coefficientCount, const typename T::RandomizationParameter &coefficientParameter ) + : m_coefficientCount(coefficientCount), m_coefficientParameter(coefficientParameter) {} + + private: + unsigned int m_coefficientCount; + typename T::RandomizationParameter m_coefficientParameter; + friend class PolynomialOver; + }; + + typedef T Ring; + typedef typename T::Element CoefficientType; + //@} + + /// \name CREATORS + //@{ + /// creates the zero polynomial + PolynomialOver() {} + + /// + PolynomialOver(const Ring &ring, unsigned int count) + : m_coefficients((size_t)count, ring.Identity()) {} + + /// copy constructor + PolynomialOver(const PolynomialOver &t) + : m_coefficients(t.m_coefficients.size()) {*this = t;} + + /// construct constant polynomial + PolynomialOver(const CoefficientType &element) + : m_coefficients(1, element) {} + + /// construct polynomial with specified coefficients, starting from coefficient of x^0 + template PolynomialOver(Iterator begin, Iterator end) + : m_coefficients(begin, end) {} + + /// convert from string + PolynomialOver(const char *str, const Ring &ring) {FromStr(str, ring);} + + /// convert from big-endian byte array + PolynomialOver(const byte *encodedPolynomialOver, unsigned int byteCount); + + /// convert from Basic Encoding Rules encoded byte array + explicit PolynomialOver(const byte *BEREncodedPolynomialOver); + + /// convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOver(BufferedTransformation &bt); + + /// create a random PolynomialOver + PolynomialOver(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) + {Randomize(rng, parameter, ring);} + //@} + + /// \name ACCESSORS + //@{ + /// the zero polynomial will return a degree of -1 + int Degree(const Ring &ring) const {return int(CoefficientCount(ring))-1;} + /// + unsigned int CoefficientCount(const Ring &ring) const; + /// return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i, const Ring &ring) const; + //@} + + /// \name MANIPULATORS + //@{ + /// + PolynomialOver& operator=(const PolynomialOver& t); + + /// + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring); + + /// set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring); + + /// + void Negate(const Ring &ring); + + /// + void swap(PolynomialOver &t); + //@} + + + /// \name BASIC ARITHMETIC ON POLYNOMIALS + //@{ + bool Equals(const PolynomialOver &t, const Ring &ring) const; + bool IsZero(const Ring &ring) const {return CoefficientCount(ring)==0;} + + PolynomialOver Plus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Minus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Inverse(const Ring &ring) const; + + PolynomialOver Times(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver DividedBy(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Modulo(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver MultiplicativeInverse(const Ring &ring) const; + bool IsUnit(const Ring &ring) const; + + PolynomialOver& Accumulate(const PolynomialOver& t, const Ring &ring); + PolynomialOver& Reduce(const PolynomialOver& t, const Ring &ring); + + /// + PolynomialOver Doubled(const Ring &ring) const {return Plus(*this, ring);} + /// + PolynomialOver Squared(const Ring &ring) const {return Times(*this, ring);} + + CoefficientType EvaluateAt(const CoefficientType &x, const Ring &ring) const; + + PolynomialOver& ShiftLeft(unsigned int n, const Ring &ring); + PolynomialOver& ShiftRight(unsigned int n, const Ring &ring); + + /// calculate r and q such that (a == d*q + r) && (0 <= degree of r < degree of d) + static void Divide(PolynomialOver &r, PolynomialOver &q, const PolynomialOver &a, const PolynomialOver &d, const Ring &ring); + //@} + + /// \name INPUT/OUTPUT + //@{ + std::istream& Input(std::istream &in, const Ring &ring); + std::ostream& Output(std::ostream &out, const Ring &ring) const; + //@} + +private: + void FromStr(const char *str, const Ring &ring); + + std::vector m_coefficients; +}; + +/// Polynomials over a fixed ring +/*! Having a fixed ring allows overloaded operators */ +template class PolynomialOverFixedRing : private PolynomialOver +{ + typedef PolynomialOver B; + typedef PolynomialOverFixedRing ThisType; + +public: + typedef T Ring; + typedef typename T::Element CoefficientType; + typedef typename B::DivideByZero DivideByZero; + typedef typename B::RandomizationParameter RandomizationParameter; + + /// \name CREATORS + //@{ + /// creates the zero polynomial + PolynomialOverFixedRing(unsigned int count = 0) : B(ms_fixedRing, count) {} + + /// copy constructor + PolynomialOverFixedRing(const ThisType &t) : B(t) {} + + explicit PolynomialOverFixedRing(const B &t) : B(t) {} + + /// construct constant polynomial + PolynomialOverFixedRing(const CoefficientType &element) : B(element) {} + + /// construct polynomial with specified coefficients, starting from coefficient of x^0 + template PolynomialOverFixedRing(Iterator first, Iterator last) + : B(first, last) {} + + /// convert from string + explicit PolynomialOverFixedRing(const char *str) : B(str, ms_fixedRing) {} + + /// convert from big-endian byte array + PolynomialOverFixedRing(const byte *encodedPoly, unsigned int byteCount) : B(encodedPoly, byteCount) {} + + /// convert from Basic Encoding Rules encoded byte array + explicit PolynomialOverFixedRing(const byte *BEREncodedPoly) : B(BEREncodedPoly) {} + + /// convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOverFixedRing(BufferedTransformation &bt) : B(bt) {} + + /// create a random PolynomialOverFixedRing + PolynomialOverFixedRing(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) : B(rng, parameter, ms_fixedRing) {} + + static const ThisType &Zero(); + static const ThisType &One(); + //@} + + /// \name ACCESSORS + //@{ + /// the zero polynomial will return a degree of -1 + int Degree() const {return B::Degree(ms_fixedRing);} + /// degree + 1 + unsigned int CoefficientCount() const {return B::CoefficientCount(ms_fixedRing);} + /// return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i) const {return B::GetCoefficient(i, ms_fixedRing);} + /// return coefficient for x^i + CoefficientType operator[](unsigned int i) const {return B::GetCoefficient(i, ms_fixedRing);} + //@} + + /// \name MANIPULATORS + //@{ + /// + ThisType& operator=(const ThisType& t) {B::operator=(t); return *this;} + /// + ThisType& operator+=(const ThisType& t) {Accumulate(t, ms_fixedRing); return *this;} + /// + ThisType& operator-=(const ThisType& t) {Reduce(t, ms_fixedRing); return *this;} + /// + ThisType& operator*=(const ThisType& t) {return *this = *this*t;} + /// + ThisType& operator/=(const ThisType& t) {return *this = *this/t;} + /// + ThisType& operator%=(const ThisType& t) {return *this = *this%t;} + + /// + ThisType& operator<<=(unsigned int n) {ShiftLeft(n, ms_fixedRing); return *this;} + /// + ThisType& operator>>=(unsigned int n) {ShiftRight(n, ms_fixedRing); return *this;} + + /// set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value) {B::SetCoefficient(i, value, ms_fixedRing);} + + /// + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) {B::Randomize(rng, parameter, ms_fixedRing);} + + /// + void Negate() {B::Negate(ms_fixedRing);} + + void swap(ThisType &t) {B::swap(t);} + //@} + + /// \name UNARY OPERATORS + //@{ + /// + bool operator!() const {return CoefficientCount()==0;} + /// + ThisType operator+() const {return *this;} + /// + ThisType operator-() const {return ThisType(Inverse(ms_fixedRing));} + //@} + + /// \name BINARY OPERATORS + //@{ + /// + friend ThisType operator>>(ThisType a, unsigned int n) {return ThisType(a>>=n);} + /// + friend ThisType operator<<(ThisType a, unsigned int n) {return ThisType(a<<=n);} + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// + ThisType MultiplicativeInverse() const {return ThisType(B::MultiplicativeInverse(ms_fixedRing));} + /// + bool IsUnit() const {return B::IsUnit(ms_fixedRing);} + + /// + ThisType Doubled() const {return ThisType(B::Doubled(ms_fixedRing));} + /// + ThisType Squared() const {return ThisType(B::Squared(ms_fixedRing));} + + CoefficientType EvaluateAt(const CoefficientType &x) const {return B::EvaluateAt(x, ms_fixedRing);} + + /// calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) + static void Divide(ThisType &r, ThisType &q, const ThisType &a, const ThisType &d) + {B::Divide(r, q, a, d, ms_fixedRing);} + //@} + + /// \name INPUT/OUTPUT + //@{ + /// + friend std::istream& operator>>(std::istream& in, ThisType &a) + {return a.Input(in, ms_fixedRing);} + /// + friend std::ostream& operator<<(std::ostream& out, const ThisType &a) + {return a.Output(out, ms_fixedRing);} + //@} + +private: + struct NewOnePolynomial + { + ThisType * operator()() const + { + return new ThisType(ms_fixedRing.MultiplicativeIdentity()); + } + }; + + static const Ring ms_fixedRing; +}; + +/// Ring of polynomials over another ring +template class RingOfPolynomialsOver : public AbstractEuclideanDomain > +{ +public: + typedef T CoefficientRing; + typedef PolynomialOver Element; + typedef typename Element::CoefficientType CoefficientType; + typedef typename Element::RandomizationParameter RandomizationParameter; + + RingOfPolynomialsOver(const CoefficientRing &ring) : m_ring(ring) {} + + Element RandomElement(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) + {return Element(rng, parameter, m_ring);} + + bool Equal(const Element &a, const Element &b) const + {return a.Equals(b, m_ring);} + + const Element& Identity() const + {return this->result = m_ring.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return this->result = a.Plus(b, m_ring);} + + Element& Accumulate(Element &a, const Element &b) const + {a.Accumulate(b, m_ring); return a;} + + const Element& Inverse(const Element &a) const + {return this->result = a.Inverse(m_ring);} + + const Element& Subtract(const Element &a, const Element &b) const + {return this->result = a.Minus(b, m_ring);} + + Element& Reduce(Element &a, const Element &b) const + {return a.Reduce(b, m_ring);} + + const Element& Double(const Element &a) const + {return this->result = a.Doubled(m_ring);} + + const Element& MultiplicativeIdentity() const + {return this->result = m_ring.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return this->result = a.Times(b, m_ring);} + + const Element& Square(const Element &a) const + {return this->result = a.Squared(m_ring);} + + bool IsUnit(const Element &a) const + {return a.IsUnit(m_ring);} + + const Element& MultiplicativeInverse(const Element &a) const + {return this->result = a.MultiplicativeInverse(m_ring);} + + const Element& Divide(const Element &a, const Element &b) const + {return this->result = a.DividedBy(b, m_ring);} + + const Element& Mod(const Element &a, const Element &b) const + {return this->result = a.Modulo(b, m_ring);} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d, m_ring);} + + class InterpolationFailed : public Exception + { + public: + InterpolationFailed() : Exception(OTHER_ERROR, "RingOfPolynomialsOver: interpolation failed") {} + }; + + Element Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + // a faster version of Interpolate(x, y, n).EvaluateAt(position) + CoefficientType InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; +/* + void PrepareBulkInterpolation(CoefficientType *w, const CoefficientType x[], unsigned int n) const; + void PrepareBulkInterpolationAt(CoefficientType *v, const CoefficientType &position, const CoefficientType x[], const CoefficientType w[], unsigned int n) const; + CoefficientType BulkInterpolateAt(const CoefficientType y[], const CoefficientType v[], unsigned int n) const; +*/ +protected: + void CalculateAlpha(std::vector &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + CoefficientRing m_ring; +}; + +template +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n); +template +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n); +template +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n); + +/// +template +inline bool operator==(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Equals(b, a.ms_fixedRing);} +/// +template +inline bool operator!=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return !(a==b);} + +/// +template +inline bool operator> (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() > b.Degree();} +/// +template +inline bool operator>=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() >= b.Degree();} +/// +template +inline bool operator< (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() < b.Degree();} +/// +template +inline bool operator<=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() <= b.Degree();} + +/// +template +inline CryptoPP::PolynomialOverFixedRing operator+(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Plus(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator-(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Minus(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator*(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Times(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator/(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.DividedBy(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator%(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Modulo(b, a.ms_fixedRing));} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template inline void swap(CryptoPP::PolynomialOver &a, CryptoPP::PolynomialOver &b) +{ + a.swap(b); +} +template inline void swap(CryptoPP::PolynomialOverFixedRing &a, CryptoPP::PolynomialOverFixedRing &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/include/cryptlib/ppc-simd.h b/include/cryptlib/ppc-simd.h new file mode 100644 index 0000000..04fdac5 --- /dev/null +++ b/include/cryptlib/ppc-simd.h @@ -0,0 +1,553 @@ +// ppc-simd.h - written and placed in public domain by Jeffrey Walton + +/// \file ppc-simd.h +/// \brief Support functions for PowerPC and vector operations +/// \details This header provides an agnostic interface into GCC and +/// IBM XL C/C++ compilers modulo their different built-in functions +/// for accessing vector intructions. +/// \details The abstractions are necesssary to support back to GCC 4.8. +/// GCC 4.8 and 4.9 are still popular, and they are the default +/// compiler for GCC112, GCC118 and others on the compile farm. Older +/// IBM XL C/C++ compilers also experience it due to lack of +/// vec_xl_be support on some platforms. Modern compilers +/// provide best support and don't need many of the little hacks below. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_PPC_CRYPTO_H +#define CRYPTOPP_PPC_CRYPTO_H + +#include "config.h" +#include "misc.h" + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +# include +# undef vector +# undef pixel +# undef bool +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +typedef __vector unsigned char uint8x16_p; +typedef __vector unsigned short uint16x8_p; +typedef __vector unsigned int uint32x4_p; + +#if defined(CRYPTOPP_POWER8_AVAILABLE) +typedef __vector unsigned long long uint64x2_p; +#endif + +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) && !defined(CRYPTOPP_POWER7_AVAILABLE) + +inline uint32x4_p VectorLoad(const byte src[16]) +{ + uint8x16_p data; + if (IsAlignedOn(src, 16)) + { + data = vec_ld(0, src); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + const uint8x16_p perm = vec_lvsl(0, src); + const uint8x16_p low = vec_ld(0, src); + const uint8x16_p high = vec_ld(15, src); + data = vec_perm(low, high, perm); + } + +#if defined(CRYPTOPP_BIG_ENDIAN) + return (uint32x4_p)data; +#else + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (uint32x4_p)vec_perm(data, data, mask); +#endif +} + +inline void VectorStore(const uint32x4_p data, byte dest[16]) +{ +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + const uint8x16_p t1 = (uint8x16_p)vec_perm(data, data, mask); +#else + const uint8x16_p t1 = (uint8x16_p)data; +#endif + + if (IsAlignedOn(dest, 16)) + { + vec_st(t1, 0, dest); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + const uint8x16_p t2 = vec_perm(t1, t1, vec_lvsr(0, dest)); + vec_ste((uint8x16_p) t2, 0, (unsigned char*) dest); + vec_ste((uint16x8_p) t2, 1, (unsigned short*)dest); + vec_ste((uint32x4_p) t2, 3, (unsigned int*) dest); + vec_ste((uint32x4_p) t2, 4, (unsigned int*) dest); + vec_ste((uint32x4_p) t2, 8, (unsigned int*) dest); + vec_ste((uint32x4_p) t2, 12, (unsigned int*) dest); + vec_ste((uint16x8_p) t2, 14, (unsigned short*)dest); + vec_ste((uint8x16_p) t2, 15, (unsigned char*) dest); + } +} + +inline uint32x4_p VectorXor(const uint32x4_p vec1, const uint32x4_p vec2) +{ + return vec_xor(vec1, vec2); +} + +inline uint32x4_p VectorAdd(const uint32x4_p vec1, const uint32x4_p vec2) +{ + return vec_add(vec1, vec2); +} + +#endif + +#if defined(CRYPTOPP_POWER7_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Reverse a 16-byte array +/// \param src the byte array +/// \details ReverseByteArrayLE reverses a 16-byte array on a little endian +/// system. It does nothing on a big endian system. +/// \since Crypto++ 6.0 +inline void ReverseByteArrayLE(byte src[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) && defined(CRYPTOPP_LITTLE_ENDIAN) + vec_st(vec_reve(vec_ld(0, src)), 0, src); +#elif defined(CRYPTOPP_LITTLE_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + const uint8x16_p zero = {0}; + vec_vsx_st(vec_perm(vec_vsx_ld(0, src), zero, mask), 0, src); +#endif +} + +/// \brief Reverse a vector +/// \tparam T vector type +/// \param src the vector +/// \details Reverse() endian swaps the bytes in a vector +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +template +inline T Reverse(const T& src) +{ + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return vec_perm(src, src, mask); +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details Loads a vector in big endian format from a byte array. +/// VectorLoadBE will swap endianess on little endian systems. +/// \note VectorLoadBE() does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoadBE(const uint8_t src[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (uint32x4_p)vec_xl_be(0, src); +#else +# if defined(CRYPTOPP_LITTLE_ENDIAN) + return (uint32x4_p)Reverse(vec_vsx_ld(0, src)); +# else + return (uint32x4_p)vec_vsx_ld(0, src); +# endif +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details Loads a vector in big endian format from a byte array. +/// VectorLoadBE will swap endianess on little endian systems. +/// \note VectorLoadBE does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoadBE(int off, const uint8_t src[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (uint32x4_p)vec_xl_be(off, src); +#else +# if defined(CRYPTOPP_LITTLE_ENDIAN) + return (uint32x4_p)Reverse(vec_vsx_ld(off, src)); +# else + return (uint32x4_p)vec_vsx_ld(off, src); +# endif +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details Loads a vector in big endian format from a byte array. +/// VectorLoad will swap endianess on little endian systems. +/// \note VectorLoad does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoad(const byte src[16]) +{ + return (uint32x4_p)VectorLoadBE(src); +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details Loads a vector in big endian format from a byte array. +/// VectorLoad will swap endianess on little endian systems. +/// \note VectorLoad does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoad(int off, const byte src[16]) +{ + return (uint32x4_p)VectorLoadBE(off, src); +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details Loads a vector from a byte array. +/// VectorLoadKey does not swap endianess on little endian systems. +/// \note VectorLoadKey does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoadKey(const byte src[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (uint32x4_p)vec_xl(0, src); +#else + return (uint32x4_p)vec_vsx_ld(0, src); +#endif +} + +/// \brief Loads a vector from a 32-bit word array +/// \param src the 32-bit word array +/// \details Loads a vector from a 32-bit word array. +/// VectorLoadKey does not swap endianess on little endian systems. +/// \note VectorLoadKey does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoadKey(const word32 src[4]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (uint32x4_p)vec_xl(0, src); +#else + return (uint32x4_p)vec_vsx_ld(0, src); +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details Loads a vector from a byte array. +/// VectorLoadKey does not swap endianess on little endian systems. +/// \note VectorLoadKey does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +inline uint32x4_p VectorLoadKey(int off, const byte src[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (uint32x4_p)vec_xl(off, src); +#else + return (uint32x4_p)vec_vsx_ld(off, src); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param src the vector +/// \param dest the byte array +/// \details Stores a vector in big endian format to a byte array. +/// VectorStoreBE will swap endianess on little endian systems. +/// \note VectorStoreBE does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +template +inline void VectorStoreBE(const T& src, uint8_t dest[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + vec_xst_be((uint8x16_p)src, 0, dest); +#else +# if defined(CRYPTOPP_LITTLE_ENDIAN) + vec_vsx_st(Reverse((uint8x16_p)src), 0, dest); +# else + vec_vsx_st((uint8x16_p)src, 0, dest); +# endif +#endif +} +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param src the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details Stores a vector in big endian format to a byte array. +/// VectorStoreBE will swap endianess on little endian systems. +/// \note VectorStoreBE does not require an aligned array. +/// \sa Reverse(), VectorLoadBE(), VectorLoad(), VectorLoadKey() +/// \since Crypto++ 6.0 +template +inline void VectorStoreBE(const T& src, int off, uint8_t dest[16]) +{ +#if defined(CRYPTOPP_XLC_VERSION) + vec_xst_be((uint8x16_p)src, off, dest); +#else +# if defined(CRYPTOPP_LITTLE_ENDIAN) + vec_vsx_st(Reverse((uint8x16_p)src), off, dest); +# else + vec_vsx_st((uint8x16_p)src, off, dest); +# endif +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param src the vector +/// \param dest the byte array +/// \details Stores a vector in big endian format to a byte array. +/// VectorStore will swap endianess on little endian systems. +/// \note VectorStore does not require an aligned array. +/// \since Crypto++ 6.0 +template +inline void VectorStore(const T& src, byte dest[16]) +{ + // Do not call VectorStoreBE. It slows us down by about 0.5 cpb on LE. +#if defined(CRYPTOPP_XLC_VERSION) + vec_xst_be((uint8x16_p)src, 0, dest); +#else +# if defined(CRYPTOPP_LITTLE_ENDIAN) + vec_vsx_st(Reverse((uint8x16_p)src), 0, dest); +# else + vec_vsx_st((uint8x16_p)src, 0, dest); +# endif +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param src the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details Stores a vector in big endian format to a byte array. +/// VectorStore will swap endianess on little endian systems. +/// \note VectorStore does not require an aligned array. +/// \since Crypto++ 6.0 +template +inline void VectorStore(const T& src, int off, byte dest[16]) +{ + // Do not call VectorStoreBE. It slows us down by about 0.5 cpb on LE. +#if defined(CRYPTOPP_XLC_VERSION) + vec_xst_be((uint8x16_p)src, off, dest); +#else +# if defined(CRYPTOPP_LITTLE_ENDIAN) + vec_vsx_st(Reverse((uint8x16_p)src), off, dest); +# else + vec_vsx_st((uint8x16_p)src, off, dest); +# endif +#endif +} + +/// \brief Permutes two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \param mask vector mask +/// \details VectorPermute returns a new vector from vec1 and vec2 +/// based on mask. mask is an uint8x16_p type vector. The return +/// vector is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorPermute(const T1& vec1, const T1& vec2, const T2& mask) +{ + return (T1)vec_perm(vec1, vec2, (uint8x16_p)mask); +} + +/// \brief XOR two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VectorXor returns a new vector from vec1 and vec2. The return +/// vector is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorXor(const T1& vec1, const T2& vec2) +{ + return (T1)vec_xor(vec1, (T1)vec2); +} + +/// \brief Add two vector +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VectorAdd returns a new vector from vec1 and vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorAdd(const T1& vec1, const T2& vec2) +{ + return (T1)vec_add(vec1, (T1)vec2); +} + +/// \brief Shift two vectors left +/// \tparam C shift byte count +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VectorShiftLeft() concatenates vec1 and vec2 and returns a +/// new vector after shifting the concatenation by the specified number +/// of bytes. Both vec1 and vec2 are cast to uint8x16_p. The return +/// vector is the same type as vec1. +/// \details On big endian machines VectorShiftLeft() is vec_sld(a, b, +/// c). On little endian machines VectorShiftLeft() is translated to +/// vec_sld(b, a, 16-c). You should always call the function as +/// if on a big endian machine as shown below. +///
+///    uint8x16_p r0 = {0};
+///    uint8x16_p r1 = VectorLoad(ptr);
+///    uint8x16_p r5 = VectorShiftLeft<12>(r0, r1);
+/// 
+/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T1 VectorShiftLeft(const T1& vec1, const T2& vec2) +{ +#if defined(CRYPTOPP_LITTLE_ENDIAN) + return (T1)vec_sld((uint8x16_p)vec2, (uint8x16_p)vec1, 16-C); +#else + return (T1)vec_sld((uint8x16_p)vec1, (uint8x16_p)vec2, C); +#endif +} + +#endif // CRYPTOPP_POWER7_AVAILABLE + +#if defined(CRYPTOPP_POWER8_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief One round of AES encryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VectorEncrypt performs one round of AES encryption of state +/// using subkey key. The return vector is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorEncrypt(const T1& state, const T2& key) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (T1)__vcipher((uint8x16_p)state, (uint8x16_p)key); +#elif defined(CRYPTOPP_GCC_VERSION) + return (T1)__builtin_crypto_vcipher((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief Final round of AES encryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VectorEncryptLast performs the final round of AES encryption +/// of state using subkey key. The return vector is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorEncryptLast(const T1& state, const T2& key) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (T1)__vcipherlast((uint8x16_p)state, (uint8x16_p)key); +#elif defined(CRYPTOPP_GCC_VERSION) + return (T1)__builtin_crypto_vcipherlast((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief One round of AES decryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VectorDecrypt performs one round of AES decryption of state +/// using subkey key. The return vector is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorDecrypt(const T1& state, const T2& key) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (T1)__vncipher((uint8x16_p)state, (uint8x16_p)key); +#elif defined(CRYPTOPP_GCC_VERSION) + return (T1)__builtin_crypto_vncipher((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief Final round of AES decryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VectorDecryptLast performs the final round of AES decryption +/// of state using subkey key. The return vector is the same type as vec1. +/// \since Crypto++ 6.0 +template +inline T1 VectorDecryptLast(const T1& state, const T2& key) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (T1)__vncipherlast((uint8x16_p)state, (uint8x16_p)key); +#elif defined(CRYPTOPP_GCC_VERSION) + return (T1)__builtin_crypto_vncipherlast((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief SHA256 Sigma functions +/// \tparam func function +/// \tparam subfunc sub-function +/// \tparam T vector type +/// \param vec the block to transform +/// \details VectorSHA256 selects sigma0, sigma1, Sigma0, Sigma1 based on +/// func and subfunc. The return vector is the same type as vec. +/// \since Crypto++ 6.0 +template +inline T VectorSHA256(const T& vec) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (T)__vshasigmaw((uint32x4_p)vec, func, subfunc); +#elif defined(CRYPTOPP_GCC_VERSION) + return (T)__builtin_crypto_vshasigmaw((uint32x4_p)vec, func, subfunc); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief SHA512 Sigma functions +/// \tparam func function +/// \tparam subfunc sub-function +/// \tparam T vector type +/// \param vec the block to transform +/// \details VectorSHA512 selects sigma0, sigma1, Sigma0, Sigma1 based on +/// func and subfunc. The return vector is the same type as vec. +/// \since Crypto++ 6.0 +template +inline T VectorSHA512(const T& vec) +{ +#if defined(CRYPTOPP_XLC_VERSION) + return (T)__vshasigmad((uint64x2_p)vec, func, subfunc); +#elif defined(CRYPTOPP_GCC_VERSION) + return (T)__builtin_crypto_vshasigmad((uint64x2_p)vec, func, subfunc); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +#endif // CRYPTOPP_POWER8_AVAILABLE + +NAMESPACE_END + +#endif // CRYPTOPP_PPC_CRYPTO_H diff --git a/include/cryptlib/pssr.h b/include/cryptlib/pssr.h new file mode 100644 index 0000000..f1d4f81 --- /dev/null +++ b/include/cryptlib/pssr.h @@ -0,0 +1,105 @@ +// pssr.h - originally written and placed in the public domain by Wei Dai + +/// \file pssr.h +/// \brief Classes for probablistic signature schemes +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_PSSR_H +#define CRYPTOPP_PSSR_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "emsa2.h" + +#ifdef CRYPTOPP_IS_DLL +#include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief PSSR Message Encoding Method interface +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL PSSR_MEM_Base : public PK_RecoverableSignatureMessageEncodingMethod +{ +public: + virtual ~PSSR_MEM_Base() {} + +protected: + virtual bool AllowRecovery() const =0; + virtual size_t SaltLen(size_t hashLen) const =0; + virtual size_t MinPadLen(size_t hashLen) const =0; + virtual const MaskGeneratingFunction & GetMGF() const =0; + +private: + size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const; + size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const; + bool IsProbabilistic() const; + bool AllowNonrecoverablePart() const; + bool RecoverablePartFirst() const; + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; + DecodingResult RecoverMessageFromRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoverableMessage) const; +}; + +/// \brief PSSR Message Encoding Method with Hash Identifier +/// \tparam USE_HASH_ID flag indicating whether the HashId is used +/// \since Crypto++ 2.1 +template class PSSR_MEM_BaseWithHashId; + +/// \brief PSSR Message Encoding Method with Hash Identifier +/// \details If USE_HASH_ID is true, then EMSA2HashIdLookup is used for the base class +template<> class PSSR_MEM_BaseWithHashId : public EMSA2HashIdLookup {}; + +/// \brief PSSR Message Encoding Method without Hash Identifier +/// \details If USE_HASH_ID is false, then PSSR_MEM_Base is used for the base class +/// \since Crypto++ 2.1 +template<> class PSSR_MEM_BaseWithHashId : public PSSR_MEM_Base {}; + +/// \brief PSSR Message Encoding Method +/// \tparam ALLOW_RECOVERY flag indicating whether the scheme provides message recovery +/// \tparam MGF mask generation function +/// \tparam SALT_LEN length of the salt +/// \tparam MIN_PAD_LEN minimum length of the pad +/// \tparam USE_HASH_ID flag indicating whether the HashId is used +/// \details If ALLOW_RECOVERY is true, the the signature scheme provides message recovery. If +/// ALLOW_RECOVERY is false, the the signature scheme is appendix, and the message must be +/// provided during verification. +/// \since Crypto++ 2.1 +template +class PSSR_MEM : public PSSR_MEM_BaseWithHashId +{ + virtual bool AllowRecovery() const {return ALLOW_RECOVERY;} + virtual size_t SaltLen(size_t hashLen) const {return SALT_LEN < 0 ? hashLen : SALT_LEN;} + virtual size_t MinPadLen(size_t hashLen) const {return MIN_PAD_LEN < 0 ? hashLen : MIN_PAD_LEN;} + virtual const MaskGeneratingFunction & GetMGF() const {static MGF mgf; return mgf;} + +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(ALLOW_RECOVERY ? "PSSR-" : "PSS-") + MGF::StaticAlgorithmName();} +}; + +/// \brief Probabilistic Signature Scheme with Recovery +/// \details Signature Schemes with Recovery encode the message with the signature. +/// \sa PSSR-MGF1 +/// \since Crypto++ 2.1 +struct PSSR : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +/// \brief Probabilistic Signature Scheme with Appendix +/// \details Signature Schemes with Appendix require the message to be provided during verification. +/// \sa PSS-MGF1 +/// \since Crypto++ 2.1 +struct PSS : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/pubkey.h b/include/cryptlib/pubkey.h new file mode 100644 index 0000000..2877536 --- /dev/null +++ b/include/cryptlib/pubkey.h @@ -0,0 +1,2315 @@ +// pubkey.h - originally written and placed in the public domain by Wei Dai + +/// \file pubkey.h +/// \brief This file contains helper classes/functions for implementing public key algorithms. +/// \details The class hierachies in this header file tend to look like this: +/// +///
+///                   x1
+///                  +--+
+///                  |  |
+///                 y1  z1
+///                  |  |
+///             x2  x2
+///                  |  |
+///                 y2  z2
+///                  |  |
+///             x3  x3
+///                  |  |
+///                 y3  z3
+/// 
+/// +///
    +///
  • x1, y1, z1 are abstract interface classes defined in cryptlib.h +///
  • x2, y2, z2 are implementations of the interfaces using "abstract policies", which +/// are pure virtual functions that should return interfaces to interchangeable algorithms. +/// These classes have Base suffixes. +///
  • x3, y3, z3 hold actual algorithms and implement those virtual functions. +/// These classes have Impl suffixes. +///
+/// +/// \details The TF_ prefix means an implementation using trapdoor functions on integers. +/// \details The DL_ prefix means an implementation using group operations in groups where discrete log is hard. + +#ifndef CRYPTOPP_PUBKEY_H +#define CRYPTOPP_PUBKEY_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "filters.h" +#include "eprecomp.h" +#include "fips140.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" + +#if defined(__SUNPRO_CC) +# define MAYBE_RETURN(x) return x +#else +# define MAYBE_RETURN(x) CRYPTOPP_UNUSED(x) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Provides range for plaintext and ciphertext lengths +/// \details A trapdoor function is a function that is easy to compute in one direction, +/// but difficult to compute in the opposite direction without special knowledge. +/// The special knowledge is usually the private key. +/// \details Trapdoor functions only handle messages of a limited length or size. +/// MaxPreimage is the plaintext's maximum length, and MaxImage is the +/// ciphertext's maximum length. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunctionBounds +{ +public: + virtual ~TrapdoorFunctionBounds() {} + + /// \brief Returns the maximum size of a message before the trapdoor function is applied + /// \returns the maximum size of a message before the trapdoor function is applied + /// \details Derived classes must implement PreimageBound(). + virtual Integer PreimageBound() const =0; + /// \brief Returns the maximum size of a message after the trapdoor function is applied + /// \returns the maximum size of a message after the trapdoor function is applied + /// \details Derived classes must implement ImageBound(). + virtual Integer ImageBound() const =0; + /// \brief Returns the maximum size of a message before the trapdoor function is applied bound to a public key + /// \returns the maximum size of a message before the trapdoor function is applied bound to a public key + /// \details The default implementation returns PreimageBound() - 1. + virtual Integer MaxPreimage() const {return --PreimageBound();} + /// \brief Returns the maximum size of a message after the trapdoor function is applied bound to a public key + /// \returns the the maximum size of a message after the trapdoor function is applied bound to a public key + /// \details The default implementation returns ImageBound() - 1. + virtual Integer MaxImage() const {return --ImageBound();} +}; + +/// \brief Applies the trapdoor function, using random data if required +/// \details ApplyFunction() is the foundation for encrypting a message under a public key. +/// Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomizedTrapdoorFunction : public TrapdoorFunctionBounds +{ +public: + virtual ~RandomizedTrapdoorFunction() {} + + /// \brief Applies the trapdoor function, using random data if required + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the encryption function is applied + /// \returns the message x encrypted under the public key + /// \details ApplyRandomizedFunction is a generalization of encryption under a public key + /// cryptosystem. The RandomNumberGenerator may (or may not) be required. + /// Derived classes must implement it. + virtual Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const =0; + + /// \brief Determines if the encryption algorithm is randomized + /// \returns true if the encryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + virtual bool IsRandomized() const {return true;} +}; + +/// \brief Applies the trapdoor function +/// \details ApplyFunction() is the foundation for encrypting a message under a public key. +/// Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunction : public RandomizedTrapdoorFunction +{ +public: + virtual ~TrapdoorFunction() {} + + /// \brief Applies the trapdoor function + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the encryption function is applied + /// \details ApplyRandomizedFunction is a generalization of encryption under a public key + /// cryptosystem. The RandomNumberGenerator may (or may not) be required. + /// \details Internally, ApplyRandomizedFunction() calls ApplyFunction() \a + /// without the RandomNumberGenerator. + Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const + {CRYPTOPP_UNUSED(rng); return ApplyFunction(x);} + bool IsRandomized() const {return false;} + + /// \brief Applies the trapdoor + /// \param x the message on which the encryption function is applied + /// \returns the message x encrypted under the public key + /// \details ApplyFunction is a generalization of encryption under a public key + /// cryptosystem. Derived classes must implement it. + virtual Integer ApplyFunction(const Integer &x) const =0; +}; + +/// \brief Applies the inverse of the trapdoor function, using random data if required +/// \details CalculateInverse() is the foundation for decrypting a message under a private key +/// in a public key cryptosystem. Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~RandomizedTrapdoorFunctionInverse() {} + + /// \brief Applies the inverse of the trapdoor function, using random data if required + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the decryption function is applied + /// \returns the message x decrypted under the private key + /// \details CalculateRandomizedInverse is a generalization of decryption using the private key + /// The RandomNumberGenerator may (or may not) be required. Derived classes must implement it. + virtual Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const =0; + + /// \brief Determines if the decryption algorithm is randomized + /// \returns true if the decryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + virtual bool IsRandomized() const {return true;} +}; + +/// \brief Applies the inverse of the trapdoor function +/// \details CalculateInverse() is the foundation for decrypting a message under a private key +/// in a public key cryptosystem. Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunctionInverse : public RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~TrapdoorFunctionInverse() {} + + /// \brief Applies the inverse of the trapdoor function + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the decryption function is applied + /// \returns the message x decrypted under the private key + /// \details CalculateRandomizedInverse is a generalization of decryption using the private key + /// \details Internally, CalculateRandomizedInverse() calls CalculateInverse() \a + /// without the RandomNumberGenerator. + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const + {return CalculateInverse(rng, x);} + + /// \brief Determines if the decryption algorithm is randomized + /// \returns true if the decryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + bool IsRandomized() const {return false;} + + /// \brief Calculates the inverse of an element + /// \param rng a RandomNumberGenerator derived class + /// \param x the element + /// \returns the inverse of the element in the group + virtual Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const =0; +}; + +// ******************************************************** + +/// \brief Message encoding method for public key encryption +class CRYPTOPP_NO_VTABLE PK_EncryptionMessageEncodingMethod +{ +public: + virtual ~PK_EncryptionMessageEncodingMethod() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + + /// max size of unpadded message in bytes, given max size of padded message in bits (1 less than size of modulus) + virtual size_t MaxUnpaddedLength(size_t paddedLength) const =0; + + virtual void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedBitLength, const NameValuePairs ¶meters) const =0; + + virtual DecodingResult Unpad(const byte *padded, size_t paddedBitLength, byte *raw, const NameValuePairs ¶meters) const =0; +}; + +// ******************************************************** + +/// \brief The base for trapdoor based cryptosystems +/// \tparam TFI trapdoor function interface derived class +/// \tparam MEI message encoding interface derived class +template +class CRYPTOPP_NO_VTABLE TF_Base +{ +protected: + virtual ~TF_Base() {} + + virtual const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const =0; + + typedef TFI TrapdoorFunctionInterface; + virtual const TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const =0; + + typedef MEI MessageEncodingInterface; + virtual const MessageEncodingInterface & GetMessageEncodingInterface() const =0; +}; + +// ******************************************************** + +/// \brief Public key trapdoor function default implementation +/// \tparam BASE public key cryptosystem with a fixed length +template +class CRYPTOPP_NO_VTABLE PK_FixedLengthCryptoSystemImpl : public BASE +{ +public: + virtual ~PK_FixedLengthCryptoSystemImpl() {} + + size_t MaxPlaintextLength(size_t ciphertextLength) const + {return ciphertextLength == FixedCiphertextLength() ? FixedMaxPlaintextLength() : 0;} + size_t CiphertextLength(size_t plaintextLength) const + {return plaintextLength <= FixedMaxPlaintextLength() ? FixedCiphertextLength() : 0;} + + virtual size_t FixedMaxPlaintextLength() const =0; + virtual size_t FixedCiphertextLength() const =0; +}; + +/// \brief Trapdoor function cryptosystem base class +/// \tparam INTFACE public key cryptosystem base interface +/// \tparam BASE public key cryptosystem implementation base +template +class CRYPTOPP_NO_VTABLE TF_CryptoSystemBase : public PK_FixedLengthCryptoSystemImpl, protected BASE +{ +public: + virtual ~TF_CryptoSystemBase() {} + + bool ParameterSupported(const char *name) const {return this->GetMessageEncodingInterface().ParameterSupported(name);} + size_t FixedMaxPlaintextLength() const {return this->GetMessageEncodingInterface().MaxUnpaddedLength(PaddedBlockBitLength());} + size_t FixedCiphertextLength() const {return this->GetTrapdoorFunctionBounds().MaxImage().ByteCount();} + +protected: + size_t PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} + // Coverity finding on potential overflow/underflow. + size_t PaddedBlockBitLength() const {return SaturatingSubtract(this->GetTrapdoorFunctionBounds().PreimageBound().BitCount(),1U);} +}; + +/// \brief Trapdoor function cryptosystems decryption base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_DecryptorBase : public TF_CryptoSystemBase > +{ +public: + virtual ~TF_DecryptorBase() {} + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +/// \brief Trapdoor function cryptosystems encryption base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_EncryptorBase : public TF_CryptoSystemBase > +{ +public: + virtual ~TF_EncryptorBase() {} + + void Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +// ******************************************************** + +// Typedef change due to Clang, http://github.com/weidai11/cryptopp/issues/300 +typedef std::pair HashIdentifier; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_SignatureMessageEncodingMethod provides interfaces for message +/// encoding method for public key signature schemes. The methods support both +/// trapdoor functions (TF_*) and discrete logarithm (DL_*) +/// based schemes. +class CRYPTOPP_NO_VTABLE PK_SignatureMessageEncodingMethod +{ +public: + virtual ~PK_SignatureMessageEncodingMethod() {} + + virtual size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + virtual size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + + /// \brief Determines whether an encoding method requires a random number generator + /// \return true if the encoding method requires a RandomNumberGenerator() + /// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + /// RandomNumberGenerator(). + /// \sa Bellare and RogawayPSS: + /// Provably Secure Encoding Method for Digital Signatures + bool IsProbabilistic() const + {return true;} + bool AllowNonrecoverablePart() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + virtual bool RecoverablePartFirst() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // for verification, DL + virtual void ProcessSemisignature(HashTransformation &hash, const byte *semisignature, size_t semisignatureLength) const + {CRYPTOPP_UNUSED(hash); CRYPTOPP_UNUSED(semisignature); CRYPTOPP_UNUSED(semisignatureLength);} + + // for signature + virtual void ProcessRecoverableMessage(HashTransformation &hash, + const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *presignature, size_t presignatureLength, + SecByteBlock &semisignature) const + { + CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(recoverableMessage); CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(presignature); CRYPTOPP_UNUSED(presignatureLength); CRYPTOPP_UNUSED(semisignature); + if (RecoverablePartFirst()) + CRYPTOPP_ASSERT(!"ProcessRecoverableMessage() not implemented"); + } + + virtual void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const =0; + + virtual bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const =0; + + virtual DecodingResult RecoverMessageFromRepresentative( // for TF + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoveredMessage) const + {CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(messageEmpty); + CRYPTOPP_UNUSED(representative); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(recoveredMessage); + throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + virtual DecodingResult RecoverMessageFromSemisignature( // for DL + HashTransformation &hash, HashIdentifier hashIdentifier, + const byte *presignature, size_t presignatureLength, + const byte *semisignature, size_t semisignatureLength, + byte *recoveredMessage) const + {CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(presignature); CRYPTOPP_UNUSED(presignatureLength); + CRYPTOPP_UNUSED(semisignature); CRYPTOPP_UNUSED(semisignatureLength); CRYPTOPP_UNUSED(recoveredMessage); + throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // VC60 workaround + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier CRYPTOPP_API Lookup() + { + return HashIdentifier((const byte *)NULLPTR, 0); + } + }; + }; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_DeterministicSignatureMessageEncodingMethod provides interfaces +/// for message encoding method for public key signature schemes. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_DeterministicSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_RecoverableSignatureMessageEncodingMethod provides interfaces +/// for message encoding method for public key signature schemes. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_RecoverableSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_DSA provides interfaces +/// for message encoding method for DSA. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_DSA : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_NR provides interfaces +/// for message encoding method for Nyberg-Rueppel. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_NR : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +#if 0 +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_SM2 provides interfaces +/// for message encoding method for SM2. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_SM2 : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; +#endif + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_MessageAccumulatorBase provides interfaces +/// for message encoding method. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulatorBase : public PK_MessageAccumulator +{ +public: + PK_MessageAccumulatorBase() : m_empty(true) {} + + virtual HashTransformation & AccessHash() =0; + + void Update(const byte *input, size_t length) + { + AccessHash().Update(input, length); + m_empty = m_empty && length == 0; + } + + SecByteBlock m_recoverableMessage, m_representative, m_presignature, m_semisignature; + Integer m_k, m_s; + bool m_empty; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_MessageAccumulatorBase provides interfaces +/// for message encoding method. +template +class PK_MessageAccumulatorImpl : public PK_MessageAccumulatorBase, protected ObjectHolder +{ +public: + HashTransformation & AccessHash() {return this->m_object;} +}; + +/// \brief Trapdoor Function (TF) Signature Scheme base class +/// \tparam INTFACE interface +/// \tparam BASE base class +template +class CRYPTOPP_NO_VTABLE TF_SignatureSchemeBase : public INTFACE, protected BASE +{ +public: + virtual ~TF_SignatureSchemeBase() {} + + size_t SignatureLength() const + {return this->GetTrapdoorFunctionBounds().MaxPreimage().ByteCount();} + size_t MaxRecoverableLength() const + {return this->GetMessageEncodingInterface().MaxRecoverableLength(MessageRepresentativeBitLength(), GetHashIdentifier().second, GetDigestSize());} + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const + {CRYPTOPP_UNUSED(signatureLength); return this->MaxRecoverableLength();} + + bool IsProbabilistic() const + {return this->GetTrapdoorFunctionInterface().IsRandomized() || this->GetMessageEncodingInterface().IsProbabilistic();} + bool AllowNonrecoverablePart() const + {return this->GetMessageEncodingInterface().AllowNonrecoverablePart();} + bool RecoverablePartFirst() const + {return this->GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + // Coverity finding on potential overflow/underflow. + size_t MessageRepresentativeBitLength() const {return SaturatingSubtract(this->GetTrapdoorFunctionBounds().ImageBound().BitCount(),1U);} + virtual HashIdentifier GetHashIdentifier() const =0; + virtual size_t GetDigestSize() const =0; +}; + +/// \brief Trapdoor Function (TF) Signer base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_SignerBase : public TF_SignatureSchemeBase > +{ +public: + virtual ~TF_SignerBase() {} + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const; + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const; +}; + +/// \brief Trapdoor Function (TF) Verifier base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_VerifierBase : public TF_SignatureSchemeBase > +{ +public: + virtual ~TF_VerifierBase() {} + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const; + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const; + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &recoveryAccumulator) const; +}; + +// ******************************************************** + +/// \brief Trapdoor Function (TF) scheme options +/// \tparam T1 algorithm info class +/// \tparam T2 keys class with public and private key +/// \tparam T3 message encoding class +template +struct TF_CryptoSchemeOptions +{ + typedef T1 AlgorithmInfo; + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; + typedef T3 MessageEncodingMethod; +}; + +/// \brief Trapdoor Function (TF) signature scheme options +/// \tparam T1 algorithm info class +/// \tparam T2 keys class with public and private key +/// \tparam T3 message encoding class +/// \tparam T4 HashTransformation class +template +struct TF_SignatureSchemeOptions : public TF_CryptoSchemeOptions +{ + typedef T4 HashFunction; +}; + +/// \brief Trapdoor Function (TF) base implementation +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY_CLASS key class +template +class CRYPTOPP_NO_VTABLE TF_ObjectImplBase : public AlgorithmImpl +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef KEY_CLASS KeyClass; + + virtual ~TF_ObjectImplBase() {} + + PublicKey & AccessPublicKey() {return AccessKey();} + const PublicKey & GetPublicKey() const {return GetKey();} + + PrivateKey & AccessPrivateKey() {return AccessKey();} + const PrivateKey & GetPrivateKey() const {return GetKey();} + + virtual const KeyClass & GetKey() const =0; + virtual KeyClass & AccessKey() =0; + + const KeyClass & GetTrapdoorFunction() const {return GetKey();} + + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const + { + CRYPTOPP_UNUSED(rng); + return new PK_MessageAccumulatorImpl; + } + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } + +protected: + const typename BASE::MessageEncodingInterface & GetMessageEncodingInterface() const + {return Singleton().Ref();} + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const + {return GetKey();} + const typename BASE::TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const + {return GetKey();} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef typename SchemeOptions::MessageEncodingMethod::HashIdentifierLookup::template HashIdentifierLookup2 L; + return L::Lookup(); + } + size_t GetDigestSize() const + { + typedef typename SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } +}; + +/// \brief Trapdoor Function (TF) signature with external reference +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY key class +/// \details TF_ObjectImplExtRef() holds a pointer to an external key structure +template +class TF_ObjectImplExtRef : public TF_ObjectImplBase +{ +public: + virtual ~TF_ObjectImplExtRef() {} + + TF_ObjectImplExtRef(const KEY *pKey = NULLPTR) : m_pKey(pKey) {} + void SetKeyPtr(const KEY *pKey) {m_pKey = pKey;} + + const KEY & GetKey() const {return *m_pKey;} + KEY & AccessKey() {throw NotImplemented("TF_ObjectImplExtRef: cannot modify refererenced key");} + +private: + const KEY * m_pKey; +}; + +/// \brief Trapdoor Function (TF) signature scheme options +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY_CLASS key class +/// \details TF_ObjectImpl() holds a reference to a trapdoor function +template +class CRYPTOPP_NO_VTABLE TF_ObjectImpl : public TF_ObjectImplBase +{ +public: + typedef KEY_CLASS KeyClass; + + virtual ~TF_ObjectImpl() {} + + const KeyClass & GetKey() const {return m_trapdoorFunction;} + KeyClass & AccessKey() {return m_trapdoorFunction;} + +private: + KeyClass m_trapdoorFunction; +}; + +/// \brief Trapdoor Function (TF) decryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_DecryptorImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_EncryptorImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_SignerImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_VerifierImpl : public TF_ObjectImpl +{ +}; + +// ******************************************************** + +/// \brief Mask generation function interface +class CRYPTOPP_NO_VTABLE MaskGeneratingFunction +{ +public: + virtual ~MaskGeneratingFunction() {} + + /// \brief Generate and apply mask + /// \param hash HashTransformation derived class + /// \param output the destination byte array + /// \param outputLength the size fo the the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param mask flag indicating whether to apply the mask + virtual void GenerateAndMask(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, bool mask = true) const =0; +}; + +/// \fn P1363_MGF1KDF2_Common +/// \brief P1363 mask generation function +/// \param hash HashTransformation derived class +/// \param output the destination byte array +/// \param outputLength the size fo the the destination byte array +/// \param input the message to hash +/// \param inputLength the size of the message +/// \param derivationParams additional derivation parameters +/// \param derivationParamsLength the size of the additional derivation parameters +/// \param mask flag indicating whether to apply the mask +/// \param counterStart starting counter value used in generation function +CRYPTOPP_DLL void CRYPTOPP_API P1363_MGF1KDF2_Common(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength, bool mask, unsigned int counterStart); + +/// \brief P1363 mask generation function +class P1363_MGF1 : public MaskGeneratingFunction +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "MGF1";} + void GenerateAndMask(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, bool mask = true) const + { + P1363_MGF1KDF2_Common(hash, output, outputLength, input, inputLength, NULLPTR, 0, mask, 0); + } +}; + +// ******************************************************** + +/// \brief P1363 key derivation function +/// \tparam H hash function used in the derivation +template +class P1363_KDF2 +{ +public: + static void CRYPTOPP_API DeriveKey(byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength) + { + H h; + P1363_MGF1KDF2_Common(h, output, outputLength, input, inputLength, derivationParams, derivationParamsLength, false, 1); + } +}; + +// ******************************************************** + +/// \brief Exception thrown when an invalid group element is encountered +/// \details Thrown by DecodeElement and AgreeWithStaticPrivateKey +class DL_BadElement : public InvalidDataFormat +{ +public: + DL_BadElement() : InvalidDataFormat("CryptoPP: invalid group element") {} +}; + +/// \brief Interface for Discrete Log (DL) group parameters +/// \tparam T element in the group +/// \details The element is usually an Integer, \ref ECP "ECP::Point" or \ref EC2N "EC2N::Point" +template +class CRYPTOPP_NO_VTABLE DL_GroupParameters : public CryptoParameters +{ + typedef DL_GroupParameters ThisClass; + +public: + typedef T Element; + + virtual ~DL_GroupParameters() {} + + DL_GroupParameters() : m_validationLevel(0) {} + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + if (!GetBasePrecomputation().IsInitialized()) + return false; + + if (m_validationLevel > level) + return true; + + bool pass = ValidateGroup(rng, level); + pass = pass && ValidateElement(level, GetSubgroupGenerator(), &GetBasePrecomputation()); + + m_validationLevel = pass ? level+1 : 0; + + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupGenerator) + ; + } + + /// \brief Determines whether the object supports precomputation + /// \return true if the object supports precomputation, false otherwise + /// \sa Precompute() + bool SupportsPrecomputation() const {return true;} + + /// \brief Perform precomputation + /// \param precomputationStorage the suggested number of objects for the precompute table + /// \throws NotImplemented + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + void Precompute(unsigned int precomputationStorage=16) + { + AccessBasePrecomputation().Precompute(GetGroupPrecomputation(), GetSubgroupOrder().BitCount(), precomputationStorage); + } + + /// \brief Retrieve previously saved precomputation + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throws NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessBasePrecomputation().Load(GetGroupPrecomputation(), storedPrecomputation); + m_validationLevel = 0; + } + + /// \brief Save precomputation for later use + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throws NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetBasePrecomputation().Save(GetGroupPrecomputation(), storedPrecomputation); + } + + /// \brief Retrieves the subgroup generator + /// \return the subgroup generator + /// \details The subgroup generator is retrieved from the base precomputation + virtual const Element & GetSubgroupGenerator() const {return GetBasePrecomputation().GetBase(GetGroupPrecomputation());} + + /// \brief Sets the subgroup generator + /// \param base the new subgroup generator + /// \details The subgroup generator is set in the base precomputation + virtual void SetSubgroupGenerator(const Element &base) {AccessBasePrecomputation().SetBase(GetGroupPrecomputation(), base);} + + /// \brief Exponentiates the base + /// \return the element after exponentiation + /// \details ExponentiateBase() calls GetBasePrecomputation() and then exponentiates. + virtual Element ExponentiateBase(const Integer &exponent) const + { + return GetBasePrecomputation().Exponentiate(GetGroupPrecomputation(), exponent); + } + + /// \brief Exponentiates an element + /// \param base the base elemenet + /// \param exponent the exponent to raise the base + /// \return the result of the exponentiation + /// \details Internally, ExponentiateElement() calls SimultaneousExponentiate(). + virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const + { + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; + } + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation + virtual const DL_GroupPrecomputation & GetGroupPrecomputation() const =0; + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation using a fixed base + virtual const DL_FixedBasePrecomputation & GetBasePrecomputation() const =0; + + /// \brief Retrieves the group precomputation + /// \return a non-const reference to the group precomputation using a fixed base + virtual DL_FixedBasePrecomputation & AccessBasePrecomputation() =0; + + /// \brief Retrieves the subgroup order + /// \return the order of subgroup generated by the base element + virtual const Integer & GetSubgroupOrder() const =0; + + /// \brief Retrieves the maximum exponent for the group + /// \return the maximum exponent for the group + virtual Integer GetMaxExponent() const =0; + + /// \brief Retrieves the order of the group + /// \return the order of the group + /// \details Either GetGroupOrder() or GetCofactor() must be overridden in a derived class. + virtual Integer GetGroupOrder() const {return GetSubgroupOrder()*GetCofactor();} + + /// \brief Retrieves the cofactor + /// \return the cofactor + /// \details Either GetGroupOrder() or GetCofactor() must be overridden in a derived class. + virtual Integer GetCofactor() const {return GetGroupOrder()/GetSubgroupOrder();} + + /// \brief Retrieves the encoded element's size + /// \param reversible flag indicating the encoding format + /// \return encoded element's size, in bytes + /// \details The format of the encoded element varies by the underlyinhg type of the element and the + /// reversible flag. GetEncodedElementSize() must be implemented in a derived class. + /// \sa GetEncodedElementSize(), EncodeElement(), DecodeElement() + virtual unsigned int GetEncodedElementSize(bool reversible) const =0; + + /// \brief Encodes the element + /// \param reversible flag indicating the encoding format + /// \param element reference to the element to encode + /// \param encoded destination byte array for the encoded element + /// \details EncodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0; + + /// \brief Decodes the element + /// \param encoded byte array with the encoded element + /// \param checkForGroupMembership flag indicating if the element should be validated + /// \return Element after decoding + /// \details DecodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0; + + /// \brief Converts an element to an Integer + /// \param element the element to convert to an Integer + /// \return Element after converting to an Integer + /// \details ConvertElementToInteger() must be implemented in a derived class. + virtual Integer ConvertElementToInteger(const Element &element) const =0; + + /// \brief Check the group for errors + /// \param rng RandomNumberGenerator for objects which use randomized testing + /// \param level level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + /// \details ValidateGroup() must be implemented in a derived class. + virtual bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const =0; + + /// \brief Check the element for errors + /// \param level level of thoroughness + /// \param element element to check + /// \param precomp optional pointer to DL_FixedBasePrecomputation + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 performs group membership checks. Level 1 may not check for weak keys and such. + /// Levels 2 and 3 are recommended. + /// \details ValidateElement() must be implemented in a derived class. + virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation *precomp) const =0; + + virtual bool FastSubgroupCheckAvailable() const =0; + + /// \brief Determines if an element is an identity + /// \param element element to check + /// \return true if the element is an identity, false otherwise + /// \details The identity element or or neutral element is a special element in a group that leaves + /// other elements unchanged when combined with it. + /// \details IsIdentity() must be implemented in a derived class. + virtual bool IsIdentity(const Element &element) const =0; + + /// \brief Exponentiates a base to multiple exponents + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const =0; + +protected: + void ParametersChanged() {m_validationLevel = 0;} + +private: + mutable unsigned int m_validationLevel; +}; + +/// \brief Base implementation of Discrete Log (DL) group parameters +/// \tparam GROUP_PRECOMP group precomputation class +/// \tparam BASE_PRECOMP fixed base precomputation class +/// \tparam BASE class or type of an element +template , class BASE = DL_GroupParameters > +class DL_GroupParametersImpl : public BASE +{ +public: + typedef GROUP_PRECOMP GroupPrecomputation; + typedef typename GROUP_PRECOMP::Element Element; + typedef BASE_PRECOMP BasePrecomputation; + + virtual ~DL_GroupParametersImpl() {} + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation + const DL_GroupPrecomputation & GetGroupPrecomputation() const {return m_groupPrecomputation;} + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation using a fixed base + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return m_gpc;} + + /// \brief Retrieves the group precomputation + /// \return a non-const reference to the group precomputation using a fixed base + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return m_gpc;} + +protected: + GROUP_PRECOMP m_groupPrecomputation; + BASE_PRECOMP m_gpc; +}; + +/// \brief Base class for a Discrete Log (DL) key +/// \tparam T class or type of an element +/// \details The element is usually an Integer, \ref ECP "ECP::Point" or \ref EC2N "EC2N::Point" +template +class CRYPTOPP_NO_VTABLE DL_Key +{ +public: + virtual ~DL_Key() {} + + /// \brief Retrieves abstract group parameters + /// \return a const reference to the group parameters + virtual const DL_GroupParameters & GetAbstractGroupParameters() const =0; + /// \brief Retrieves abstract group parameters + /// \return a non-const reference to the group parameters + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; +}; + +/// \brief Interface for Discrete Log (DL) public keys +template +class CRYPTOPP_NO_VTABLE DL_PublicKey : public DL_Key +{ + typedef DL_PublicKey ThisClass; + +public: + typedef T Element; + + virtual ~DL_PublicKey(); + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \returns true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &this->GetAbstractGroupParameters()) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicElement); + } + + /// \brief Initialize or reinitialize this this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source); + + /// \brief Retrieves the public element + /// \returns the public element + virtual const Element & GetPublicElement() const {return GetPublicPrecomputation().GetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation());} + + /// \brief Sets the public element + /// \param y the public element + virtual void SetPublicElement(const Element &y) {AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + + /// \brief Exponentiates this element + /// \param exponent the exponent to raise the base + /// \returns the public element raised to the exponent + virtual Element ExponentiatePublicElement(const Integer &exponent) const + { + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + return GetPublicPrecomputation().Exponentiate(params.GetGroupPrecomputation(), exponent); + } + + /// \brief Exponentiates an element + /// \param baseExp the first exponent + /// \param publicExp the second exponent + /// \returns the public element raised to the exponent + /// \details CascadeExponentiateBaseAndPublicElement raises the public element to + /// the base element and precomputation. + virtual Element CascadeExponentiateBaseAndPublicElement(const Integer &baseExp, const Integer &publicExp) const + { + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + return params.GetBasePrecomputation().CascadeExponentiate(params.GetGroupPrecomputation(), baseExp, GetPublicPrecomputation(), publicExp); + } + + /// \brief Accesses the public precomputation + /// \details GetPublicPrecomputation returns a const reference, while + /// AccessPublicPrecomputation returns a non-const reference. Must be + /// overridden in derived classes. + virtual const DL_FixedBasePrecomputation & GetPublicPrecomputation() const =0; + + /// \brief Accesses the public precomputation + /// \details GetPublicPrecomputation returns a const reference, while + /// AccessPublicPrecomputation returns a non-const reference. Must be + /// overridden in derived classes. + virtual DL_FixedBasePrecomputation & AccessPublicPrecomputation() =0; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PublicKey::~DL_PublicKey() {} + +/// \brief Interface for Discrete Log (DL) private keys +template +class CRYPTOPP_NO_VTABLE DL_PrivateKey : public DL_Key +{ + typedef DL_PrivateKey ThisClass; + +public: + typedef T Element; + + virtual ~DL_PrivateKey(); + + /// \brief Initializes a public key from this key + /// \param pub reference to a public key + void MakePublicKey(DL_PublicKey &pub) const + { + pub.AccessAbstractGroupParameters().AssignFrom(this->GetAbstractGroupParameters()); + pub.SetPublicElement(this->GetAbstractGroupParameters().ExponentiateBase(GetPrivateExponent())); + } + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \returns true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &this->GetAbstractGroupParameters()) + CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent); + } + + /// \brief Initialize or reinitialize this this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source) + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent); + } + + /// \brief Retrieves the private exponent + /// \returns the private exponent + /// \details Must be overridden in derived classes. + virtual const Integer & GetPrivateExponent() const =0; + /// \brief Sets the private exponent + /// \param x the private exponent + /// \details Must be overridden in derived classes. + virtual void SetPrivateExponent(const Integer &x) =0; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey::~DL_PrivateKey() {} + +template +void DL_PublicKey::AssignFrom(const NameValuePairs &source) +{ + DL_PrivateKey *pPrivateKey = NULLPTR; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } +} + +class OID; + +/// \brief Discrete Log (DL) key base implementation +/// \tparam PK Key class +/// \tparam GP GroupParameters class +/// \tparam O OID class +template +class DL_KeyImpl : public PK +{ +public: + typedef GP GroupParameters; + + virtual ~DL_KeyImpl() {} + + O GetAlgorithmID() const {return GetGroupParameters().GetAlgorithmID();} + bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {AccessGroupParameters().BERDecode(bt); return true;} + bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {GetGroupParameters().DEREncode(bt); return true;} + + const GP & GetGroupParameters() const {return m_groupParameters;} + GP & AccessGroupParameters() {return m_groupParameters;} + +private: + GP m_groupParameters; +}; + +class X509PublicKey; +class PKCS8PrivateKey; + +/// \brief Discrete Log (DL) private key base implementation +/// \tparam GP GroupParameters class +template +class DL_PrivateKeyImpl : public DL_PrivateKey, public DL_KeyImpl +{ +public: + typedef typename GP::Element Element; + + virtual ~DL_PrivateKeyImpl() {} + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + bool pass = GetAbstractGroupParameters().Validate(rng, level); + + const Integer &q = GetAbstractGroupParameters().GetSubgroupOrder(); + const Integer &x = GetPrivateExponent(); + + pass = pass && x.IsPositive() && x < q; + if (level >= 1) + pass = pass && Integer::Gcd(x, q) == Integer::One(); + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + if (!params.GetThisObject(this->AccessGroupParameters())) + this->AccessGroupParameters().GenerateRandom(rng, params); + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + SetPrivateExponent(x); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + {AccessAbstractGroupParameters().Precompute(precomputationStorage);} + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation);} + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation);} + + // DL_Key + const DL_GroupParameters & GetAbstractGroupParameters() const {return this->GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return this->AccessGroupParameters();} + + // DL_PrivateKey + const Integer & GetPrivateExponent() const {return m_x;} + void SetPrivateExponent(const Integer &x) {m_x = x;} + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool, size_t) + {m_x.BERDecode(bt);} + void DEREncodePrivateKey(BufferedTransformation &bt) const + {m_x.DEREncode(bt);} + +private: + Integer m_x; +}; + +template +class DL_PrivateKey_WithSignaturePairwiseConsistencyTest : public BASE +{ +public: + virtual ~DL_PrivateKey_WithSignaturePairwiseConsistencyTest() {} + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + BASE::GenerateRandom(rng, params); + + if (FIPS_140_2_ComplianceEnabled()) + { + typename SIGNATURE_SCHEME::Signer signer(*this); + typename SIGNATURE_SCHEME::Verifier verifier(signer); + SignaturePairwiseConsistencyTest_FIPS_140_Only(signer, verifier); + } + } +}; + +/// \brief Discrete Log (DL) public key base implementation +/// \tparam GP GroupParameters class +template +class DL_PublicKeyImpl : public DL_PublicKey, public DL_KeyImpl +{ +public: + typedef typename GP::Element Element; + + virtual ~DL_PublicKeyImpl(); + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + bool pass = GetAbstractGroupParameters().Validate(rng, level); + pass = pass && GetAbstractGroupParameters().ValidateElement(level, this->GetPublicElement(), &GetPublicPrecomputation()); + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + { + AccessAbstractGroupParameters().Precompute(precomputationStorage); + AccessPublicPrecomputation().Precompute(GetAbstractGroupParameters().GetGroupPrecomputation(), GetAbstractGroupParameters().GetSubgroupOrder().BitCount(), precomputationStorage); + } + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation); + AccessPublicPrecomputation().Load(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation); + GetPublicPrecomputation().Save(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + // DL_Key + const DL_GroupParameters & GetAbstractGroupParameters() const {return this->GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return this->AccessGroupParameters();} + + // DL_PublicKey + const DL_FixedBasePrecomputation & GetPublicPrecomputation() const {return m_ypc;} + DL_FixedBasePrecomputation & AccessPublicPrecomputation() {return m_ypc;} + + // non-inherited + bool operator==(const DL_PublicKeyImpl &rhs) const + {return this->GetGroupParameters() == rhs.GetGroupParameters() && this->GetPublicElement() == rhs.GetPublicElement();} + +private: + typename GP::BasePrecomputation m_ypc; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PublicKeyImpl::~DL_PublicKeyImpl() {} + +/// \brief Interface for Elgamal-like signature algorithms +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_ElgamalLikeSignatureAlgorithm +{ +public: + virtual ~DL_ElgamalLikeSignatureAlgorithm() {} + + /// \brief Sign a message using a private key + /// \param params GroupParameters + /// \param privateKey private key + /// \param k signing exponent + /// \param e encoded message + /// \param r r part of signature + /// \param s s part of signature + virtual void Sign(const DL_GroupParameters ¶ms, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0; + + /// \brief Verify a message using a public key + /// \param params GroupParameters + /// \param publicKey public key + /// \param e encoded message + /// \param r r part of signature + /// \param s s part of signature + virtual bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const =0; + + /// \brief Recover a Presignature + /// \param params GroupParameters + /// \param publicKey public key + /// \param r r part of signature + /// \param s s part of signature + virtual Integer RecoverPresignature(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &r, const Integer &s) const + { + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(publicKey); CRYPTOPP_UNUSED(r); CRYPTOPP_UNUSED(s); + throw NotImplemented("DL_ElgamalLikeSignatureAlgorithm: this signature scheme does not support message recovery"); + MAYBE_RETURN(Integer::Zero()); + } + + /// \brief Retrieve R length + /// \param params GroupParameters + virtual size_t RLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + + /// \brief Retrieve S length + /// \param params GroupParameters + virtual size_t SLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + + /// \brief Signature scheme flag + /// \returns true if the signature scheme is deterministic, false otherwise + /// \details IsDeterministic() is provided for DL signers. It is used by RFC 6979 signature schemes. + virtual bool IsDeterministic() const + {return false;} +}; + +/// \brief Interface for deterministic signers +/// \details RFC 6979 signers which generate k based on the encoded message and private key +class CRYPTOPP_NO_VTABLE DeterministicSignatureAlgorithm +{ +public: + virtual ~DeterministicSignatureAlgorithm() {} + + /// \brief Generate k + /// \param x private key + /// \param q subgroup generator + /// \param e encoded message + virtual Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const =0; +}; + +/// \brief Interface for DL key agreement algorithms +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_KeyAgreementAlgorithm +{ +public: + typedef T Element; + + virtual ~DL_KeyAgreementAlgorithm() {} + + virtual Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const =0; + virtual Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const =0; +}; + +/// \brief Interface for key derivation algorithms used in DL cryptosystems +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_KeyDerivationAlgorithm +{ +public: + virtual ~DL_KeyDerivationAlgorithm() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + virtual void Derive(const DL_GroupParameters &groupParams, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs &derivationParams) const =0; +}; + +/// \brief Interface for symmetric encryption algorithms used in DL cryptosystems +class CRYPTOPP_NO_VTABLE DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~DL_SymmetricEncryptionAlgorithm() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + virtual size_t GetSymmetricKeyLength(size_t plaintextLength) const =0; + virtual size_t GetSymmetricCiphertextLength(size_t plaintextLength) const =0; + virtual size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const =0; + virtual void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const =0; + virtual DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const =0; +}; + +/// \brief Discrete Log (DL) base interface +/// \tparam KI public or private key interface +template +class CRYPTOPP_NO_VTABLE DL_Base +{ +protected: + typedef KI KeyInterface; + typedef typename KI::Element Element; + + virtual ~DL_Base() {} + + const DL_GroupParameters & GetAbstractGroupParameters() const {return GetKeyInterface().GetAbstractGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return AccessKeyInterface().AccessAbstractGroupParameters();} + + virtual KeyInterface & AccessKeyInterface() =0; + virtual const KeyInterface & GetKeyInterface() const =0; +}; + +/// \brief Discrete Log (DL) signature scheme base implementation +/// \tparam INTFACE PK_Signer or PK_Verifier derived class +/// \tparam KEY_INTFACE DL_Base key base used in the scheme +/// \details DL_SignatureSchemeBase provides common functions for signers and verifiers. +/// DL_Base is used for signers, and DL_Base is used for verifiers. +template +class CRYPTOPP_NO_VTABLE DL_SignatureSchemeBase : public INTFACE, public DL_Base +{ +public: + virtual ~DL_SignatureSchemeBase() {} + + /// \brief Provides the signature length + /// \returns signature length, in bytes + /// \details SignatureLength returns the size required for r+s. + size_t SignatureLength() const + { + return GetSignatureAlgorithm().RLen(this->GetAbstractGroupParameters()) + + GetSignatureAlgorithm().SLen(this->GetAbstractGroupParameters()); + } + + /// \brief Provides the maximum recoverable length + /// \returns maximum recoverable length, in bytes + size_t MaxRecoverableLength() const + {return GetMessageEncodingInterface().MaxRecoverableLength(0, GetHashIdentifier().second, GetDigestSize());} + + /// \brief Provides the maximum recoverable length + /// \param signatureLength the size fo the signature + /// \returns maximum recoverable length based on signature length, in bytes + /// \details this function is not implemented and always returns 0. + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const + {CRYPTOPP_UNUSED(signatureLength); CRYPTOPP_ASSERT(false); return 0;} // TODO + + /// \brief Determines if the scheme is probabilistic + /// \returns true if the scheme is probabilistic, false otherwise + bool IsProbabilistic() const + {return true;} + + /// \brief Determines if the scheme has non-recoverable part + /// \returns true if the message encoding has a non-recoverable part, false otherwise. + bool AllowNonrecoverablePart() const + {return GetMessageEncodingInterface().AllowNonrecoverablePart();} + + /// \brief Determines if the scheme allows recoverable part first + /// \returns true if the message encoding allows the recoverable part, false otherwise. + bool RecoverablePartFirst() const + {return GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + size_t MessageRepresentativeBitLength() const {return this->GetAbstractGroupParameters().GetSubgroupOrder().BitCount();} + + // true if the scheme conforms to RFC 6979 + virtual bool IsDeterministic() const {return false;} + + virtual const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const =0; + virtual const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const =0; + virtual HashIdentifier GetHashIdentifier() const =0; + virtual size_t GetDigestSize() const =0; +}; + +/// \brief Discrete Log (DL) signature scheme signer base implementation +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_SignerBase : public DL_SignatureSchemeBase > +{ +public: + virtual ~DL_SignerBase() {} + + /// \brief Testing interface + /// \param k Integer + /// \param e Integer + /// \param r Integer + /// \param s Integer + void RawSign(const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + r = params.ConvertElementToInteger(params.ExponentiateBase(k)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + } + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + ma.m_recoverableMessage.Assign(recoverableMessage, recoverableMessageLength); + this->GetMessageEncodingInterface().ProcessRecoverableMessage(ma.AccessHash(), + recoverableMessage, recoverableMessageLength, + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature); + } + + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative( + rng, + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + // hash message digest into random number k to prevent reusing the same k on + // different messages after virtual machine rollback + if (rng.CanIncorporateEntropy()) + rng.IncorporateEntropy(representative, representative.size()); + + Integer k; + if (alg.IsDeterministic()) + { + const Integer& q = params.GetSubgroupOrder(); + const Integer& x = key.GetPrivateExponent(); + const DeterministicSignatureAlgorithm& det = dynamic_cast(alg); + k = det.GenerateRandom(x, q, e); + } + else + { + k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + } + + Integer r, s; + r = params.ConvertElementToInteger(params.ExponentiateBase(k)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + + /* + Integer r, s; + if (this->MaxRecoverableLength() > 0) + r.Decode(ma.m_semisignature, ma.m_semisignature.size()); + else + r.Decode(ma.m_presignature, ma.m_presignature.size()); + alg.Sign(params, key.GetPrivateExponent(), ma.m_k, e, r, s); + */ + + size_t rLen = alg.RLen(params); + r.Encode(signature, rLen); + s.Encode(signature+rLen, alg.SLen(params)); + + if (restart) + RestartMessageAccumulator(rng, ma); + + return this->SignatureLength(); + } + +protected: + void RestartMessageAccumulator(RandomNumberGenerator &rng, PK_MessageAccumulatorBase &ma) const + { + // k needs to be generated before hashing for signature schemes with recovery + // but to defend against VM rollbacks we need to generate k after hashing. + // so this code is commented out, since no DL-based signature scheme with recovery + // has been implemented in Crypto++ anyway + /* + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + ma.m_k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + ma.m_presignature.New(params.GetEncodedElementSize(false)); + params.ConvertElementToInteger(params.ExponentiateBase(ma.m_k)).Encode(ma.m_presignature, ma.m_presignature.size()); + */ + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(ma); + } +}; + +/// \brief Discret Log (DL) Verifier base class +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_VerifierBase : public DL_SignatureSchemeBase > +{ +public: + virtual ~DL_VerifierBase() {} + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const + { + CRYPTOPP_UNUSED(signature); CRYPTOPP_UNUSED(signatureLength); + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + + size_t rLen = alg.RLen(params); + ma.m_semisignature.Assign(signature, rLen); + ma.m_s.Decode(signature+rLen, alg.SLen(params)); + + this->GetMessageEncodingInterface().ProcessSemisignature(ma.AccessHash(), ma.m_semisignature, ma.m_semisignature.size()); + } + + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative(NullRNG(), ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + return alg.Verify(params, key, e, r, ma.m_s); + } + + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative( + NullRNG(), + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + ma.m_presignature.New(params.GetEncodedElementSize(false)); + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + alg.RecoverPresignature(params, key, r, ma.m_s).Encode(ma.m_presignature, ma.m_presignature.size()); + + return this->GetMessageEncodingInterface().RecoverMessageFromSemisignature( + ma.AccessHash(), this->GetHashIdentifier(), + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature, ma.m_semisignature.size(), + recoveredMessage); + } +}; + +/// \brief Discrete Log (DL) cryptosystem base implementation +/// \tparam PK field element type +/// \tparam KI public or private key interface +template +class CRYPTOPP_NO_VTABLE DL_CryptoSystemBase : public PK, public DL_Base +{ +public: + typedef typename DL_Base::Element Element; + + virtual ~DL_CryptoSystemBase() {} + + size_t MaxPlaintextLength(size_t ciphertextLength) const + { + unsigned int minLen = this->GetAbstractGroupParameters().GetEncodedElementSize(true); + return ciphertextLength < minLen ? 0 : GetSymmetricEncryptionAlgorithm().GetMaxSymmetricPlaintextLength(ciphertextLength - minLen); + } + + size_t CiphertextLength(size_t plaintextLength) const + { + size_t len = GetSymmetricEncryptionAlgorithm().GetSymmetricCiphertextLength(plaintextLength); + return len == 0 ? 0 : this->GetAbstractGroupParameters().GetEncodedElementSize(true) + len; + } + + bool ParameterSupported(const char *name) const + {return GetKeyDerivationAlgorithm().ParameterSupported(name) || GetSymmetricEncryptionAlgorithm().ParameterSupported(name);} + +protected: + virtual const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const =0; + virtual const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const =0; + virtual const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const =0; +}; + +/// \brief Discrete Log (DL) decryptor base implementation +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_DecryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + virtual ~DL_DecryptorBase() {} + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + { + try + { + CRYPTOPP_UNUSED(rng); + const DL_KeyAgreementAlgorithm &agreeAlg = this->GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = this->GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = this->GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + Element q = params.DecodeElement(ciphertext, true); + size_t elementSize = params.GetEncodedElementSize(true); + ciphertext += elementSize; + ciphertextLength -= elementSize; + + Element z = agreeAlg.AgreeWithStaticPrivateKey(params, q, true, key.GetPrivateExponent()); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(encAlg.GetMaxSymmetricPlaintextLength(ciphertextLength))); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q, parameters); + + return encAlg.SymmetricDecrypt(derivedKey, ciphertext, ciphertextLength, plaintext, parameters); + } + catch (DL_BadElement &) + { + return DecodingResult(); + } + } +}; + +/// \brief Discrete Log (DL) encryptor base implementation +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_EncryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + virtual ~DL_EncryptorBase() {} + + void Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + { + const DL_KeyAgreementAlgorithm &agreeAlg = this->GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = this->GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = this->GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + Integer x(rng, Integer::One(), params.GetMaxExponent()); + Element q = params.ExponentiateBase(x); + params.EncodeElement(true, q, ciphertext); + unsigned int elementSize = params.GetEncodedElementSize(true); + ciphertext += elementSize; + + Element z = agreeAlg.AgreeWithEphemeralPrivateKey(params, key.GetPublicPrecomputation(), x); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(plaintextLength)); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q, parameters); + + encAlg.SymmetricEncrypt(rng, derivedKey, plaintext, plaintextLength, ciphertext, parameters); + } +}; + +/// \brief Discrete Log (DL) scheme options +/// \tparam T1 algorithm information +/// \tparam T2 group parameters for the scheme +template +struct DL_SchemeOptionsBase +{ + typedef T1 AlgorithmInfo; + typedef T2 GroupParameters; + typedef typename GroupParameters::Element Element; +}; + +/// \brief Discrete Log (DL) key options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +template +struct DL_KeyedSchemeOptions : public DL_SchemeOptionsBase +{ + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; +}; + +/// \brief Discrete Log (DL) signature scheme options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +/// \tparam T3 signature algorithm +/// \tparam T4 message encoding method +/// \tparam T5 hash function +template +struct DL_SignatureSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 SignatureAlgorithm; + typedef T4 MessageEncodingMethod; + typedef T5 HashFunction; +}; + +/// \brief Discrete Log (DL) crypto scheme options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +/// \tparam T3 key agreement algorithm +/// \tparam T4 key derivation algorithm +/// \tparam T5 symmetric encryption algorithm +template +struct DL_CryptoSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 KeyAgreementAlgorithm; + typedef T4 KeyDerivationAlgorithm; + typedef T5 SymmetricEncryptionAlgorithm; +}; + +/// \brief Discrete Log (DL) base object implementation +/// \tparam BASE TODO +/// \tparam SCHEME_OPTIONS options for the scheme +/// \tparam KEY key used in the scheme +template +class CRYPTOPP_NO_VTABLE DL_ObjectImplBase : public AlgorithmImpl +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef typename KEY::Element Element; + + virtual ~DL_ObjectImplBase() {} + + PrivateKey & AccessPrivateKey() {return m_key;} + PublicKey & AccessPublicKey() {return m_key;} + + // KeyAccessor + const KEY & GetKey() const {return m_key;} + KEY & AccessKey() {return m_key;} + +protected: + typename BASE::KeyInterface & AccessKeyInterface() {return m_key;} + const typename BASE::KeyInterface & GetKeyInterface() const {return m_key;} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef typename SchemeOptions::MessageEncodingMethod::HashIdentifierLookup HashLookup; + return HashLookup::template HashIdentifierLookup2::Lookup(); + } + size_t GetDigestSize() const + { + typedef typename SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } + +private: + KEY m_key; +}; + +/// \brief Discrete Log (DL) object implementation +/// \tparam BASE TODO +/// \tparam SCHEME_OPTIONS options for the scheme +/// \tparam KEY key used in the scheme +template +class CRYPTOPP_NO_VTABLE DL_ObjectImpl : public DL_ObjectImplBase +{ +public: + typedef typename KEY::Element Element; + + virtual ~DL_ObjectImpl() {} + +protected: + const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const + {return Singleton().Ref();} + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {return Singleton().Ref();} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const + {return Singleton().Ref();} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const + {return Singleton().Ref();} + HashIdentifier GetHashIdentifier() const + {return HashIdentifier();} + const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const + {return Singleton().Ref();} +}; + +/// \brief Discrete Log (DL) signer implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_SignerImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey> +{ +public: + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const + { + member_ptr p(new PK_MessageAccumulatorImpl); + this->RestartMessageAccumulator(rng, *p); + return p.release(); + } +}; + +/// \brief Discrete Log (DL) verifier implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_VerifierImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey> +{ +public: + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } +}; + +/// \brief Discrete Log (DL) encryptor implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_EncryptorImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey> +{ +}; + +/// \brief Discrete Log (DL) decryptor implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_DecryptorImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey> +{ +}; + +// ******************************************************** + +/// \brief Discrete Log (DL) simple key agreement base implementation +/// \tparam T class or type +template +class CRYPTOPP_NO_VTABLE DL_SimpleKeyAgreementDomainBase : public SimpleKeyAgreementDomain +{ +public: + typedef T Element; + + virtual ~DL_SimpleKeyAgreementDomainBase() {} + + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + unsigned int PrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + unsigned int PublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, PrivateKeyLength()); + } + + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const + { + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element w = params.DecodeElement(otherPublicKey, validateOtherPublicKey); + + Element z = GetKeyAgreementAlgorithm().AgreeWithStaticPrivateKey( + GetAbstractGroupParameters(), w, validateOtherPublicKey, x); + params.EncodeElement(false, z, agreedValue); + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + + /// \brief Retrieves a reference to the group generator + /// \returns const reference to the group generator + const Element &GetGenerator() const {return GetAbstractGroupParameters().GetSubgroupGenerator();} + +protected: + virtual const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const =0; + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; + const DL_GroupParameters & GetAbstractGroupParameters() const {return const_cast *>(this)->AccessAbstractGroupParameters();} +}; + +/// \brief Methods for avoiding "Small-Subgroup" attacks on Diffie-Hellman Key Agreement +/// \details Additional methods exist and include public key validation and choice of prime p. +/// \sa Methods for Avoiding the "Small-Subgroup" Attacks on the +/// Diffie-Hellman Key Agreement Method for S/MIME +enum CofactorMultiplicationOption { + /// \brief No cofactor multiplication applied + NO_COFACTOR_MULTIPLICTION, + /// \brief Cofactor multiplication compatible with ordinary Diffie-Hellman + /// \details Modifies the computation of ZZ by including j (the cofactor) in the computations and is + /// compatible with ordinary Diffie-Hellman. + COMPATIBLE_COFACTOR_MULTIPLICTION, + /// \brief Cofactor multiplication incompatible with ordinary Diffie-Hellman + /// \details Modifies the computation of ZZ by including j (the cofactor) in the computations but is + /// not compatible with ordinary Diffie-Hellman. + INCOMPATIBLE_COFACTOR_MULTIPLICTION}; + +typedef EnumToType NoCofactorMultiplication; +typedef EnumToType CompatibleCofactorMultiplication; +typedef EnumToType IncompatibleCofactorMultiplication; + +/// \brief Diffie-Hellman key agreement algorithm +template +class DL_KeyAgreementAlgorithm_DH : public DL_KeyAgreementAlgorithm +{ +public: + typedef ELEMENT Element; + + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() + {return COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? "DHC" : "DH";} + + virtual ~DL_KeyAgreementAlgorithm_DH() {} + + Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const + { + return publicPrecomputation.Exponentiate(params.GetGroupPrecomputation(), + COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? privateExponent*params.GetCofactor() : privateExponent); + } + + Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const + { + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + { + const Integer &k = params.GetCofactor(); + return params.ExponentiateElement(publicElement, + ModularArithmetic(params.GetSubgroupOrder()).Divide(privateExponent, k)*k); + } + else if (COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION) + return params.ExponentiateElement(publicElement, privateExponent*params.GetCofactor()); + else + { + CRYPTOPP_ASSERT(COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION); + + if (!validateOtherPublicKey) + return params.ExponentiateElement(publicElement, privateExponent); + + if (params.FastSubgroupCheckAvailable()) + { + if (!params.ValidateElement(2, publicElement, NULLPTR)) + throw DL_BadElement(); + return params.ExponentiateElement(publicElement, privateExponent); + } + else + { + const Integer e[2] = {params.GetSubgroupOrder(), privateExponent}; + Element r[2]; + params.SimultaneousExponentiate(r, publicElement, e, 2); + if (!params.IsIdentity(r[0])) + throw DL_BadElement(); + return r[1]; + } + } + } +}; + +// ******************************************************** + +/// \brief Template implementing constructors for public key algorithm classes +template +class CRYPTOPP_NO_VTABLE PK_FinalTemplate : public BASE +{ +public: + PK_FinalTemplate() {} + + PK_FinalTemplate(const CryptoMaterial &key) + {this->AccessKey().AssignFrom(key);} + + PK_FinalTemplate(BufferedTransformation &bt) + {this->AccessKey().BERDecode(bt);} + + PK_FinalTemplate(const AsymmetricAlgorithm &algorithm) + {this->AccessKey().AssignFrom(algorithm.GetMaterial());} + + PK_FinalTemplate(const Integer &v1) + {this->AccessKey().Initialize(v1);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2) + {this->AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3) + {this->AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {this->AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2) + {this->AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3) + {this->AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {this->AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} +}; + +/// \brief Base class for public key encryption standard classes. +/// \details These classes are used to select from variants of algorithms. +/// Not all standards apply to all algorithms. +struct EncryptionStandard {}; + +/// \brief Base class for public key signature standard classes. +/// \details These classes are used to select from variants of algorithms. +/// Not all standards apply to all algorithms. +struct SignatureStandard {}; + +/// \brief Trapdoor Function (TF) encryption scheme +/// \tparam STANDARD standard +/// \tparam KEYS keys used in the encryption scheme +/// \tparam ALG_INFO algorithm information +template +class TF_ES; + +template > +class TF_ES : public KEYS +{ + typedef typename STANDARD::EncryptionMessageEncodingMethod MessageEncodingMethod; + +public: + /// see EncryptionStandard for a list of standards + typedef STANDARD Standard; + typedef TF_CryptoSchemeOptions SchemeOptions; + + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(KEYS::StaticAlgorithmName()) + "/" + MessageEncodingMethod::StaticAlgorithmName();} + + /// implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +/// \brief Trapdoor Function (TF) Signature Scheme +/// \tparam STANDARD standard +/// \tparam H hash function +/// \tparam KEYS keys used in the signature scheme +/// \tparam ALG_INFO algorithm information +template +class TF_SS; + +template > +class TF_SS : public KEYS +{ +public: + /// see SignatureStandard for a list of standards + typedef STANDARD Standard; + typedef typename Standard::SignatureMessageEncodingMethod MessageEncodingMethod; + typedef TF_SignatureSchemeOptions SchemeOptions; + + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(KEYS::StaticAlgorithmName()) + "/" + MessageEncodingMethod::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + + /// implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + /// implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +/// \brief Discrete Log (DL) signature scheme +/// \tparam KEYS keys used in the signature scheme +/// \tparam SA signature algorithm +/// \tparam MEM message encoding method +/// \tparam H hash function +/// \tparam ALG_INFO algorithm information +template +class DL_SS; + +template > +class DL_SS : public KEYS +{ + typedef DL_SignatureSchemeOptions SchemeOptions; + +public: + static std::string StaticAlgorithmName() {return SA::StaticAlgorithmName() + std::string("/EMSA1(") + H::StaticAlgorithmName() + ")";} + + /// implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + /// implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +/// \brief Discrete Log (DL) encryption scheme +/// \tparam KEYS keys used in the encryption scheme +/// \tparam AA key agreement algorithm +/// \tparam DA key derivation algorithm +/// \tparam EA encryption algorithm +/// \tparam ALG_INFO algorithm information +template +class DL_ES : public KEYS +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + +public: + /// implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/pwdbased.h b/include/cryptlib/pwdbased.h new file mode 100644 index 0000000..160e770 --- /dev/null +++ b/include/cryptlib/pwdbased.h @@ -0,0 +1,461 @@ +// pwdbased.h - originally written and placed in the public domain by Wei Dai +// Cutover to KeyDerivationFunction interface by Uri Blumenthal +// Marcel Raad and Jeffrey Walton in March 2018. + +/// \file pwdbased.h +/// \brief Password based key derivation functions + +#ifndef CRYPTOPP_PWDBASED_H +#define CRYPTOPP_PWDBASED_H + +#include "cryptlib.h" +#include "hrtimer.h" +#include "integer.h" +#include "argnames.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +// ******************** PBKDF1 ******************** + +/// \brief PBKDF1 from PKCS #5 +/// \tparam T a HashTransformation class +template +class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS5_PBKDF1() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF1(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(T::DIGESTSIZE); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \returns the number of iterations performed + /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + /// \details PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation + /// allows salts of any length. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS5_PBKDF1::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedLength()) + return MaxDerivedLength(); + return keylength; +} + +template +size_t PKCS5_PBKDF1::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS5_PBKDF1::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + CRYPTOPP_UNUSED(purpose); + + ThrowIfInvalidDerivedLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + T hash; + hash.Update(secret, secretLen); + hash.Update(salt, saltLen); + + SecByteBlock buffer(hash.DigestSize()); + hash.Final(buffer); + + unsigned int i; + ThreadUserTimer timer; + + if (timeInSeconds) + timer.StartTimer(); + + for (i=1; i +class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS5_PBKDF2_HMAC() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF2_HMAC(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + // should multiply by T::DIGESTSIZE, but gets overflow that way + size_t MaxDerivedKeyLength() const { + return 0xffffffffU; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \returns the number of iterations performed + /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS5_PBKDF2_HMAC::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedLength()) + return MaxDerivedLength(); + return keylength; +} + +template +size_t PKCS5_PBKDF2_HMAC::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS5_PBKDF2_HMAC::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + CRYPTOPP_UNUSED(purpose); + + ThrowIfInvalidDerivedLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + HMAC hmac(secret, secretLen); + SecByteBlock buffer(hmac.DigestSize()); + ThreadUserTimer timer; + + unsigned int i=1; + while (derivedLen > 0) + { + hmac.Update(salt, saltLen); + unsigned int j; + for (j=0; j<4; j++) + { + byte b = byte(i >> ((3-j)*8)); + hmac.Update(&b, 1); + } + hmac.Final(buffer); + +#if CRYPTOPP_MSC_VERSION + const size_t segmentLen = STDMIN(derivedLen, buffer.size()); + memcpy_s(derived, segmentLen, buffer, segmentLen); +#else + const size_t segmentLen = STDMIN(derivedLen, buffer.size()); + memcpy(derived, buffer, segmentLen); +#endif + + if (timeInSeconds) + { + timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size()); + timer.StartTimer(); + } + + for (j=1; j +class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS12_PBKDF() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF_PKCS12(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // TODO - check this + size_t MaxDerivedKeyLength() const { + return static_cast(-1); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \returns the number of iterations performed + /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS12_PBKDF::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedLength()) + return MaxDerivedLength(); + return keylength; +} + +template +size_t PKCS12_PBKDF::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + // NULL or 0 length salt OK + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS12_PBKDF::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + + ThrowIfInvalidDerivedLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12 + const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v); + const size_t PLen = RoundUpToMultipleOf(secretLen, v), ILen = SLen + PLen; + SecByteBlock buffer(DLen + SLen + PLen); + byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S; + + memset(D, purpose, DLen); + size_t i; + for (i=0; i 0) + { + hash.CalculateDigest(Ai, buffer, buffer.size()); + + if (timeInSeconds) + { + timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size()); + timer.StartTimer(); + } + + for (i=1; i +{ +public: + /// \brief Construct a ByteQueue + /// \param nodeSize the initial node size + /// \details Internally, ByteQueue uses a ByteQueueNode to store bytes, and \p nodeSize determines the + /// size of the ByteQueueNode. A value of 0 indicates the ByteQueueNode should be automatically sized, + /// which means a value of 256 is used. + ByteQueue(size_t nodeSize=0); + + /// \brief Copy construct a ByteQueue + /// \param copy the other ByteQueue + ByteQueue(const ByteQueue ©); + ~ByteQueue(); + + lword MaxRetrievable() const + {return CurrentSize();} + bool AnyRetrievable() const + {return !IsEmpty();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(size_t &size); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + size_t Get(byte &outByte); + size_t Get(byte *outString, size_t getMax); + + size_t Peek(byte &outByte) const; + size_t Peek(byte *outString, size_t peekMax) const; + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + // these member functions are not inherited + void SetNodeSize(size_t nodeSize); + + lword CurrentSize() const; + bool IsEmpty() const; + + void Clear(); + + void Unget(byte inByte); + void Unget(const byte *inString, size_t length); + + const byte * Spy(size_t &contiguousSize) const; + + void LazyPut(const byte *inString, size_t size); + void LazyPutModifiable(byte *inString, size_t size); + void UndoLazyPut(size_t size); + void FinalizeLazyPut(); + + ByteQueue & operator=(const ByteQueue &rhs); + bool operator==(const ByteQueue &rhs) const; + bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);} + byte operator[](lword i) const; + void swap(ByteQueue &rhs); + + /// \brief A ByteQueue iterator + class Walker : public InputRejecting + { + public: + /// \brief Construct a ByteQueue Walker + /// \param queue a ByteQueue + Walker(const ByteQueue &queue) + : m_queue(queue), m_node(NULLPTR), m_position(0), m_offset(0), m_lazyString(NULLPTR), m_lazyLength(0) + {Initialize();} + + lword GetCurrentPosition() {return m_position;} + + lword MaxRetrievable() const + {return m_queue.CurrentSize() - m_position;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + + size_t Get(byte &outByte); + size_t Get(byte *outString, size_t getMax); + + size_t Peek(byte &outByte) const; + size_t Peek(byte *outString, size_t peekMax) const; + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + private: + const ByteQueue &m_queue; + const ByteQueueNode *m_node; + lword m_position; + size_t m_offset; + const byte *m_lazyString; + size_t m_lazyLength; + }; + + friend class Walker; + +private: + void CleanupUsedNodes(); + void CopyFrom(const ByteQueue ©); + void Destroy(); + + bool m_autoNodeSize; + size_t m_nodeSize; + ByteQueueNode *m_head, *m_tail; + byte *m_lazyString; + size_t m_lazyLength; + bool m_lazyStringModifiable; +}; + +/// use this to make sure LazyPut is finalized in event of exception +class CRYPTOPP_DLL LazyPutter +{ +public: + LazyPutter(ByteQueue &bq, const byte *inString, size_t size) + : m_bq(bq) {bq.LazyPut(inString, size);} + ~LazyPutter() + {try {m_bq.FinalizeLazyPut();} catch(const Exception&) {CRYPTOPP_ASSERT(0);}} +protected: + LazyPutter(ByteQueue &bq) : m_bq(bq) {} +private: + ByteQueue &m_bq; +}; + +/// like LazyPutter, but does a LazyPutModifiable instead +class LazyPutterModifiable : public LazyPutter +{ +public: + LazyPutterModifiable(ByteQueue &bq, byte *inString, size_t size) + : LazyPutter(bq) {bq.LazyPutModifiable(inString, size);} +}; + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/include/cryptlib/rabin.h b/include/cryptlib/rabin.h new file mode 100644 index 0000000..f127157 --- /dev/null +++ b/include/cryptlib/rabin.h @@ -0,0 +1,135 @@ +// rabin.h - originally written and placed in the public domain by Wei Dai + +/// \file rabin.h +/// \brief Classes for Rabin encryption and signature schemes + +#ifndef CRYPTOPP_RABIN_H +#define CRYPTOPP_RABIN_H + +#include "cryptlib.h" +#include "oaep.h" +#include "pssr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabin trapdoor function using the public key +/// \since Crypto++ 2.0 +class RabinFunction : public TrapdoorFunction, public PublicKey +{ + typedef RabinFunction ThisClass; + +public: + + /// \brief Initialize a Rabin public key + /// \param n the modulus + /// \param r element r + /// \param s element s + void Initialize(const Integer &n, const Integer &r, const Integer &s) + {m_n = n; m_r = r; m_s = s;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + const Integer& GetQuadraticResidueModPrime1() const {return m_r;} + const Integer& GetQuadraticResidueModPrime2() const {return m_s;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetQuadraticResidueModPrime1(const Integer &r) {m_r = r;} + void SetQuadraticResidueModPrime2(const Integer &s) {m_s = s;} + +protected: + Integer m_n, m_r, m_s; +}; + +/// \brief Rabin trapdoor function using the private key +/// \since Crypto++ 2.0 +class InvertibleRabinFunction : public RabinFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRabinFunction ThisClass; + +public: + + /// \brief Initialize a Rabin private key + /// \param n modulus + /// \param r element r + /// \param s element s + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &r, const Integer &s, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_r = r; m_s = s; m_p = p; m_q = q; m_u = u;} + + /// \brief Create a Rabin private key + /// \param rng a RandomNumberGenerator derived class + /// \param keybits the size of the key, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int keybits) + {GenerateRandomWithKeySize(rng, keybits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +/// \brief Rabin keys +struct Rabin +{ + static std::string StaticAlgorithmName() {return "Rabin-Crypto++Variant";} + typedef RabinFunction PublicKey; + typedef InvertibleRabinFunction PrivateKey; +}; + +/// \brief Rabin encryption scheme +/// \tparam STANDARD encryption standard +template +struct RabinES : public TF_ES +{ +}; + +/// \brief Rabin signature scheme +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +template +struct RabinSS : public TF_SS +{ +}; + +// More typedefs for backwards compatibility +class SHA1; +typedef RabinES >::Decryptor RabinDecryptor; +typedef RabinES >::Encryptor RabinEncryptor; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/randpool.h b/include/cryptlib/randpool.h new file mode 100644 index 0000000..2f46f33 --- /dev/null +++ b/include/cryptlib/randpool.h @@ -0,0 +1,98 @@ +// randpool.h - originally written and placed in the public domain by Wei Dai +// OldRandPool added by JW in August, 2017. + +/// \file randpool.h +/// \brief Class file for Randomness Pool +/// \details RandomPool can be used to generate cryptographic quality pseudorandom bytes +/// after seeding the pool with IncorporateEntropy(). Internally, the generator uses +/// AES-256 to produce the stream. Entropy is stirred in using SHA-256. +/// \details RandomPool used to follow the design of randpool in PGP 2.6.x. At version 5.5 +/// RandomPool was redesigned to reduce the risk of reusing random numbers after state +/// rollback (which may occur when running in a virtual machine like VMware or a hosted +/// environment). +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You +/// should migrate away from OldRandomPool at the earliest opportunity. Use RandomPool +/// or AutoSeededRandomPool instead. +/// \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based) + +#ifndef CRYPTOPP_RANDPOOL_H +#define CRYPTOPP_RANDPOOL_H + +#include "cryptlib.h" +#include "filters.h" +#include "secblock.h" +#include "smartptr.h" +#include "aes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Randomness Pool based on AES-256 +/// \details RandomPool can be used to generate cryptographic quality pseudorandom bytes +/// after seeding the pool with IncorporateEntropy(). Internally, the generator uses +/// AES-256 to produce the stream. Entropy is stirred in using SHA-256. +/// \details RandomPool used to follow the design of randpool in PGP 2.6.x. At version 5.5 +/// RandomPool was redesigned to reduce the risk of reusing random numbers after state +/// rollback, which may occur when running in a virtual machine like VMware or a hosted +/// environment. +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You +/// should migrate away from OldRandomPool at the earliest opportunity. +/// \sa OldRandomPool +/// \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based) +class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable +{ +public: + /// \brief Construct a RandomPool + RandomPool(); + + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + +private: + FixedSizeAlignedSecBlock m_seed; + FixedSizeAlignedSecBlock m_key; + member_ptr m_pCipher; + bool m_keySet; +}; + +/// \brief Randomness Pool based on PGP 2.6.x with MDC +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. The +/// OldRandomPool class is always available so you dont need to define +/// CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY. OldRandomPool also provides the modern +/// interface, including CanIncorporateEntropy, IncorporateEntropy and +/// GenerateIntoBufferedTransformation. +/// \details You should migrate away from OldRandomPool at the earliest opportunity. Use a +/// modern random number generator or key derivation function, like AutoSeededRandomPool or +/// HKDF. +/// \warning This class uses an old style PGP 2.6.x with MDC. The generator risks reusing +/// random random numbers after state rollback. You should migrate away from OldRandomPool +/// at the earliest opportunity. +/// \sa RandomPool, AutoSeededRandomPool, HKDF, P1363_KDF2, PKCS12_PBKDF, PKCS5_PBKDF2_HMAC +/// \since Crypto++ 6.0 (PGP 2.6.x style) +class CRYPTOPP_DLL OldRandomPool : public RandomNumberGenerator +{ +public: + /// \brief Construct an OldRandomPool + /// \param poolSize internal pool size of the generator + /// \details poolSize must be greater than 16 + OldRandomPool(unsigned int poolSize=384); + + // RandomNumberGenerator interface (Crypto++ 5.5 and above) + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + + byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); + +protected: + void Stir(); + +private: + SecByteBlock pool, key; + size_t addPos, getPos; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/rc2.h b/include/cryptlib/rc2.h new file mode 100644 index 0000000..0b9e636 --- /dev/null +++ b/include/cryptlib/rc2.h @@ -0,0 +1,91 @@ +// rc2.h - originally written and placed in the public domain by Wei Dai + +/// \file rc2.h +/// \brief Classes for the RC2 block cipher +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RC2_H +#define CRYPTOPP_RC2_H + +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC2 block cipher information +/// \since Crypto++ 3.0 +struct RC2_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 128> +{ + CRYPTOPP_CONSTANT(DEFAULT_EFFECTIVE_KEYLENGTH = 1024) + CRYPTOPP_CONSTANT(MAX_EFFECTIVE_KEYLENGTH = 1024) + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC2";} +}; + +/// \brief RC2 block cipher +/// \sa RC2 on the Crypto Lounge. +/// \since Crypto++ 3.0 +class RC2 : public RC2_Info, public BlockCipherDocumentation +{ + /// \brief Class specific methods used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + protected: + FixedSizeSecBlock K; // expanded key table + }; + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Dec apply to \p DECRYPTION. + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Encryption apply to \p ENCRYPTION. + class Encryption : public BlockCipherFinal + { + public: + Encryption() {} + Encryption(const byte *key, size_t keyLen=DEFAULT_KEYLENGTH) + {SetKey(key, keyLen);} + Encryption(const byte *key, size_t keyLen, int effectiveKeyLen) + {SetKey(key, keyLen, MakeParameters("EffectiveKeyLength", effectiveKeyLen));} + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Decryption apply to \p DECRYPTION. + class Decryption : public BlockCipherFinal + { + public: + Decryption() {} + Decryption(const byte *key, size_t keyLen=DEFAULT_KEYLENGTH) + {SetKey(key, keyLen);} + Decryption(const byte *key, size_t keyLen, int effectiveKeyLen) + {SetKey(key, keyLen, MakeParameters("EffectiveKeyLength", effectiveKeyLen));} + }; +}; + +typedef RC2::Encryption RC2Encryption; +typedef RC2::Decryption RC2Decryption; + +NAMESPACE_END + +#endif + diff --git a/include/cryptlib/rc5.h b/include/cryptlib/rc5.h new file mode 100644 index 0000000..541ffbc --- /dev/null +++ b/include/cryptlib/rc5.h @@ -0,0 +1,59 @@ +// rc5.h - originally written and placed in the public domain by Wei Dai + +/// \file rc5.h +/// \brief Classes for the RC5 block cipher + +#ifndef CRYPTOPP_RC5_H +#define CRYPTOPP_RC5_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC5 block cipher information +/// \since Crypto++ 1.0 +struct RC5_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 0, 255>, public VariableRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC5";} + typedef word32 RC5_WORD; +}; + +/// \brief RC5 block cipher +/// \sa RC5 +/// \since Crypto++ 1.0 +class RC5 : public RC5_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int r; // number of rounds + SecBlock sTable; // expanded key table + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef RC5::Encryption RC5Encryption; +typedef RC5::Decryption RC5Decryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/rc6.h b/include/cryptlib/rc6.h new file mode 100644 index 0000000..7b80d35 --- /dev/null +++ b/include/cryptlib/rc6.h @@ -0,0 +1,60 @@ +// rc6.h - originally written and placed in the public domain by Wei Dai + +/// \file rc6.h +/// \brief Classes for the RC6 block cipher +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RC6_H +#define CRYPTOPP_RC6_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC6 block cipher information +/// \since Crypto++ 3.0 +struct RC6_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, public VariableRounds<20> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC6";} + typedef word32 RC6_WORD; +}; + +/// \brief RC6 block cipher +/// \sa RC6 +/// \since Crypto++ 3.0 +class RC6 : public RC6_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int r; // number of rounds + SecBlock sTable; // expanded key table + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef RC6::Encryption RC6Encryption; +typedef RC6::Decryption RC6Decryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/rdrand.h b/include/cryptlib/rdrand.h new file mode 100644 index 0000000..1bb25f3 --- /dev/null +++ b/include/cryptlib/rdrand.h @@ -0,0 +1,137 @@ +// rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. + +/// \file rdrand.h +/// \brief Classes for RDRAND and RDSEED +/// \since Crypto++ 5.6.3 + +#ifndef CRYPTOPP_RDRAND_H +#define CRYPTOPP_RDRAND_H + +#include "cryptlib.h" + +// This class file provides both RDRAND and RDSEED. They were added at +// Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64} +// to select an implementation or "throw NotImplemented". At runtime the +// constructor will throw RDRAND_Err or RDSEED_Err if a generator is +// is not available. +// The original classes accepted a retry count. Retries were superflous for +// RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending +// on the processor. Retries were removed at Crypto++ 6.0 because +// GenerateBlock unconditionally retries and always fulfills the request. + +// Throughput varies wildly depending on processor and manufacturer. A Core i5 or +// Core i7 RDRAND can generate at over 200 MiB/s. Its below the theroetical +// maximum, but it takes about 5 instructions to generate, retry and store a +// result. A low-end Celeron may perform RDRAND at about 7 MiB/s. RDSEED +// performs at about 1/4 to 1/2 the rate of RDRAND. AMD RDRAND performed poorly +// during testing with Athlon X4 845. The Bulldozer v4 only performed at 1 MiB/s. + +// Microsoft added RDRAND in August 2012, VS2012; RDSEED in October 2013, VS2013. +// GCC added RDRAND in December 2010, GCC 4.6. LLVM added RDRAND in July 2012, +// Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1. + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a RDRAND generator encounters +/// a generator related error. +/// \since Crypto++ 5.6.3 +class RDRAND_Err : public Exception +{ +public: + RDRAND_Err(const std::string &operation) + : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using RDRAND instruction +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 5.6.3 +class RDRAND : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDRAND"; } + + virtual ~RDRAND() {} + + /// \brief Construct a RDRAND generator + /// \details According to DJ of Intel, the Intel RDRAND circuit does not underflow. + /// If it did hypothetically underflow, then it would return 0 for the random value. + /// AMD's RDRAND implementation appears to provide the same behavior. + /// \throws RDRAND_Err if the random number generator is not available + RDRAND(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } +}; + +/// \brief Exception thrown when a RDSEED generator encounters +/// a generator related error. +/// \since Crypto++ 5.6.3 +class RDSEED_Err : public Exception +{ +public: + RDSEED_Err(const std::string &operation) + : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using RDSEED instruction +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 5.6.3 +class RDSEED : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDSEED"; } + + virtual ~RDSEED() {} + + /// \brief Construct a RDSEED generator + /// \details Empirical testing under a 6th generaton i7 (6200U) shows RDSEED fails + /// to fulfill requests at about once every for every 256 bytes requested. + /// The generator runs about 4 times slower than RDRAND. + /// \throws RDSEED_Err if the random number generator is not available + RDSEED(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } +}; + +NAMESPACE_END + +#endif // CRYPTOPP_RDRAND_H diff --git a/include/cryptlib/resource.h b/include/cryptlib/resource.h new file mode 100644 index 0000000..ae07ae7 --- /dev/null +++ b/include/cryptlib/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by cryptopp.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/include/cryptlib/rijndael.h b/include/cryptlib/rijndael.h new file mode 100644 index 0000000..c295452 --- /dev/null +++ b/include/cryptlib/rijndael.h @@ -0,0 +1,101 @@ +// rijndael.h - originally written and placed in the public domain by Wei Dai + +/// \file rijndael.h +/// \brief Classes for Rijndael encryption algorithm +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 + +#ifndef CRYPTOPP_RIJNDAEL_H +#define CRYPTOPP_RIJNDAEL_H + +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || \ + CRYPTOPP_BOOL_ARM64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# define CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rijndael block cipher information +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 +struct Rijndael_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return CRYPTOPP_RIJNDAEL_NAME;} +}; + +/// \brief Rijndael block cipher +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 +/// \sa Rijndael +class CRYPTOPP_DLL Rijndael : public Rijndael_Info, public BlockCipherDocumentation +{ + /// \brief Rijndael block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + protected: + static void FillEncTable(); + static void FillDecTable(); + + // VS2005 workaround: have to put these on separate lines, or error C2487 is triggered in DLL build + static const byte Se[256]; + static const byte Sd[256]; + + static const word32 rcon[]; + + unsigned int m_rounds; + FixedSizeAlignedSecBlock m_key; + mutable SecByteBlock m_aliasBlock; + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key sizes are supported. + /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks + /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, + /// Power8 AES since Crypto++ 6.0 + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Provides implementation for decryption transformation + /// \details Dec provides implementation for decryption transformation. All key sizes are supported. + /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks + /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, + /// Power8 AES since Crypto++ 6.0 + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Rijndael::Encryption RijndaelEncryption; +typedef Rijndael::Decryption RijndaelDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/ripemd.h b/include/cryptlib/ripemd.h new file mode 100644 index 0000000..cf70084 --- /dev/null +++ b/include/cryptlib/ripemd.h @@ -0,0 +1,65 @@ +// ripemd.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for RIPEMD message digest + +#ifndef CRYPTOPP_RIPEMD_H +#define CRYPTOPP_RIPEMD_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RIPEMD-160 message digest +/// \details Digest size is 160-bits. +/// \sa RIPEMD-160 +/// \since Crypto++ 2.1 +class RIPEMD160 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-160";} +}; + +/// \brief RIPEMD-320 message digest +/// \details Digest size is 320-bits. +/// \sa RIPEMD-320 +/// \since Crypto++ 2.1 +class RIPEMD320 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-320";} +}; + +/// \brief RIPEMD-128 message digest +/// \details Digest size is 128-bits. +/// \warning RIPEMD-128 is considered insecure, and should not be used unless you absolutely need it for compatibility. +/// \sa RIPEMD-128 +/// \since Crypto++ 2.1 +class RIPEMD128 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-128";} +}; + +/// \brief RIPEMD-256 message digest +/// \details Digest size is 256-bits. +/// \warning RIPEMD-256 is considered insecure, and should not be used unless you absolutely need it for compatibility. +/// \sa RIPEMD-256 +/// \since Crypto++ 2.1 +class RIPEMD256 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-256";} +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/rng.h b/include/cryptlib/rng.h new file mode 100644 index 0000000..daa65da --- /dev/null +++ b/include/cryptlib/rng.h @@ -0,0 +1,109 @@ +// rng.h - originally written and placed in the public domain by Wei Dai + +/// \file rng.h +/// \brief Miscellaneous classes for RNGs +/// \details This file contains miscellaneous classes for RNGs, including LC_RNG(), +/// X917RNG() and MaurerRandomnessTest() +/// \sa osrng.h, randpool.h + +#ifndef CRYPTOPP_RNG_H +#define CRYPTOPP_RNG_H + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Linear Congruential Generator (LCG) +/// \details Originally propsed by William S. England. +/// \warning LC_RNG is suitable for simulations, where uniformaly distrubuted numbers are +/// required quickly. It should not be used for cryptographic purposes. +class LC_RNG : public RandomNumberGenerator +{ +public: + /// \brief Construct a Linear Congruential Generator (LCG) + /// \param init_seed the initial value for the generator + LC_RNG(word32 init_seed) + : seed(init_seed) {} + + void GenerateBlock(byte *output, size_t size); + + word32 GetSeed() {return seed;} + +private: + word32 seed; + + static const word32 m; + static const word32 q; + static const word16 a; + static const word16 r; +}; + +/// \brief ANSI X9.17 RNG +/// \details X917RNG is from ANSI X9.17 Appendix C, and it uses a 64-bit block cipher, like TripleDES. +/// If you use a 128-bit block cipher, like AES, then you are effectively using an ANSI X9.31 generator. +/// \sa AutoSeededX917RNG, DefaultAutoSeededRNG +class CRYPTOPP_DLL X917RNG : public RandomNumberGenerator, public NotCopyable +{ +public: + /// \brief Construct a X917RNG + /// \param cipher the block cipher to use for the generator + /// \param seed a byte buffer to use as a seed + /// \param deterministicTimeVector additional entropy + /// \details cipher will be deleted by the destructor. seed must be at least + /// BlockSize() in length. deterministicTimeVector = 0 means obtain time vector + /// from the system. + /// \details When constructing a X917RNG, the generator must be keyed or an access + /// violation will occur because the time vector is encrypted using the block cipher. + /// To key the generator during constructions, perform the following: + ///
+	///   SecByteBlock key(AES::DEFAULT_KEYLENGTH), seed(AES::BLOCKSIZE);
+	///   OS_GenerateRandomBlock(false, key, key.size());
+	///   OS_GenerateRandomBlock(false, seed, seed.size());
+	///   X917RNG prng(new AES::Encryption(key, AES::DEFAULT_KEYLENGTH), seed, NULLPTR);
+ /// \sa AutoSeededX917RNG + X917RNG(BlockTransformation *cipher, const byte *seed, const byte *deterministicTimeVector = NULLPTR); + + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + +private: + member_ptr m_cipher; + const unsigned int m_size; // S, blocksize of cipher + SecByteBlock m_datetime; // DT, buffer for enciphered timestamp + SecByteBlock m_randseed, m_lastBlock, m_deterministicTimeVector; +}; + +/// \brief Maurer's Universal Statistical Test for Random Bit Generators +/// \details This class implements Maurer's Universal Statistical Test for +/// Random Bit Generators. It is intended for measuring the randomness of +/// *PHYSICAL* RNGs. +/// \details For more details see Maurer's paper in Journal of Cryptology, 1992. +class MaurerRandomnessTest : public Bufferless +{ +public: + /// \brief Construct a MaurerRandomnessTest + MaurerRandomnessTest(); + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Provides the number of bytes of input is needed by the test + /// \returns how many more bytes of input is needed by the test + // BytesNeeded() returns how many more bytes of input is needed by the test + // GetTestValue() should not be called before BytesNeeded()==0 + unsigned int BytesNeeded() const {return n >= (Q+K) ? 0 : Q+K-n;} + + // returns a number between 0.0 and 1.0, describing the quality of the + // random numbers entered + double GetTestValue() const; + +private: + enum {L=8, V=256, Q=2000, K=2000}; + double sum; + unsigned int n; + unsigned int tab[V]; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/rsa.h b/include/cryptlib/rsa.h new file mode 100644 index 0000000..7fec3d3 --- /dev/null +++ b/include/cryptlib/rsa.h @@ -0,0 +1,263 @@ +// rsa.h - originally written and placed in the public domain by Wei Dai + +/// \file rsa.h +/// \brief Classes for the RSA cryptosystem +/// \details This file contains classes that implement the RSA +/// ciphers and signature schemes as defined in PKCS #1 v2.0. + +#ifndef CRYPTOPP_RSA_H +#define CRYPTOPP_RSA_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "pkcspad.h" +#include "oaep.h" +#include "emsa2.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RSA trapdoor function using the public key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RSAFunction : public TrapdoorFunction, public X509PublicKey +{ + typedef RSAFunction ThisClass; + +public: + /// \brief Initialize a RSA public key + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // X509PublicKey + OID GetAlgorithmID() const; + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +/// \brief RSA trapdoor function using the private key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL InvertibleRSAFunction : public RSAFunction, public TrapdoorFunctionInverse, public PKCS8PrivateKey +{ + typedef InvertibleRSAFunction ThisClass; + +public: + /// \brief Create a RSA private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \param e the desired public exponent + /// \details Initialize() creates a new keypair using a public exponent of 17. + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &e = 17); + + /// \brief Initialize a RSA private key + /// \param n modulus + /// \param e public exponent + /// \param d private exponent + /// \param p first prime factor + /// \param q second prime factor + /// \param dp d mod p + /// \param dq d mod q + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &d, const Integer &p, const Integer &q, const Integer &dp, const Integer &dq, const Integer &u) + {m_n = n; m_e = e; m_d = d; m_p = p; m_q = q; m_dp = dp; m_dq = dq; m_u = u;} + + /// \brief Initialize a RSA private key + /// \param n modulus + /// \param e public exponent + /// \param d private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + /// Initialize() will factor n using d and populate {p,q,dp,dq,u}. + void Initialize(const Integer &n, const Integer &e, const Integer &d); + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void DEREncode(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + void Load(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void Save(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + OID GetAlgorithmID() const {return RSAFunction::GetAlgorithmID();} + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + // TrapdoorFunctionInverse + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + // parameters: (ModulusSize, PublicExponent (default 17)) + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetPrivateExponent() const {return m_d;} + const Integer& GetModPrime1PrivateExponent() const {return m_dp;} + const Integer& GetModPrime2PrivateExponent() const {return m_dq;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetPrivateExponent(const Integer &d) {m_d = d;} + void SetModPrime1PrivateExponent(const Integer &dp) {m_dp = dp;} + void SetModPrime2PrivateExponent(const Integer &dq) {m_dq = dq;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_d, m_p, m_q, m_dp, m_dq, m_u; +}; + +/// \brief RSA trapdoor function using the public key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RSAFunction_ISO : public RSAFunction +{ +public: + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} +}; + +/// \brief RSA trapdoor function using the private key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL InvertibleRSAFunction_ISO : public InvertibleRSAFunction +{ +public: + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} +}; + +/// \brief RSA algorithm +/// \since Crypto++ 1.0 +struct CRYPTOPP_DLL RSA +{ + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA";} + typedef RSAFunction PublicKey; + typedef InvertibleRSAFunction PrivateKey; +}; + +/// \brief RSA encryption algorithm +/// \tparam STANDARD signature standard +/// \sa RSA cryptosystem +/// \since Crypto++ 1.0 +template +struct RSAES : public TF_ES +{ +}; + +/// \brief RSA signature algorithm +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \details See documentation of PKCS1v15 for a list of hash functions that can be used with it. +/// \sa RSA signature scheme with appendix +/// \since Crypto++ 1.0 +template +struct RSASS : public TF_SS +{ +}; + +/// \brief RSA algorithm +/// \since Crypto++ 1.0 +struct CRYPTOPP_DLL RSA_ISO +{ + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA-ISO";} + typedef RSAFunction_ISO PublicKey; + typedef InvertibleRSAFunction_ISO PrivateKey; +}; + +/// \brief RSA signature algorithm +/// \tparam H hash transformation +/// \since Crypto++ 1.0 +template +struct RSASS_ISO : public TF_SS +{ +}; + +/// \brief \ref RSAES "RSAES::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES::Decryptor, RSAES_PKCS1v15_Decryptor) +/// \brief \ref RSAES "RSAES::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES::Encryptor, RSAES_PKCS1v15_Encryptor) + +/// \brief \ref RSAES "RSAES>::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES >::Decryptor, RSAES_OAEP_SHA_Decryptor) +/// \brief \ref RSAES "RSAES>::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES >::Encryptor, RSAES_OAEP_SHA_Encryptor) + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_SHA_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_SHA_Verifier : public RSASS::Verifier {}; + +namespace Weak { + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD2_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD2_Verifier : public RSASS::Verifier {}; + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD5_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD5_Verifier : public RSASS::Verifier {}; +} + +#else +typedef RSASS::Signer RSASSA_PKCS1v15_SHA_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_SHA_Verifier; + +namespace Weak { + typedef RSASS::Signer RSASSA_PKCS1v15_MD2_Signer; + typedef RSASS::Verifier RSASSA_PKCS1v15_MD2_Verifier; + typedef RSASS::Signer RSASSA_PKCS1v15_MD5_Signer; + typedef RSASS::Verifier RSASSA_PKCS1v15_MD5_Verifier; +} +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/rw.h b/include/cryptlib/rw.h new file mode 100644 index 0000000..ca2cd30 --- /dev/null +++ b/include/cryptlib/rw.h @@ -0,0 +1,146 @@ +// rw.h - originally written and placed in the public domain by Wei Dai + +/// \file rw.h +/// \brief Classes for Rabin-Williams signature scheme +/// \details The implementation provides Rabin-Williams signature schemes as defined in +/// IEEE P1363. It uses Bernstein's tweaked square roots in place of square roots to +/// speedup calculations. +/// \sa RSA signatures and Rabin–Williams +/// signatures: the state of the art (20080131), Section 6, The tweaks e and f. +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RW_H +#define CRYPTOPP_RW_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabin-Williams trapdoor function using the public key +/// \since Crypto++ 3.0, Tweaked roots using e and f since Crypto++ 5.6.4 +class CRYPTOPP_DLL RWFunction : public TrapdoorFunction, public PublicKey +{ + typedef RWFunction ThisClass; + +public: + + /// \brief Initialize a Rabin-Williams public key + /// \param n the modulus + void Initialize(const Integer &n) + {m_n = n;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void Save(BufferedTransformation &bt) const + {DEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + void SetModulus(const Integer &n) {m_n = n;} + +protected: + Integer m_n; +}; + +/// \brief Rabin-Williams trapdoor function using the private key +/// \since Crypto++ 3.0, Tweaked roots using e and f since Crypto++ 5.6.4 +class CRYPTOPP_DLL InvertibleRWFunction : public RWFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRWFunction ThisClass; + +public: + /// \brief Construct an InvertibleRWFunction + InvertibleRWFunction() : m_precompute(false) {} + + /// \brief Initialize a Rabin-Williams private key + /// \param n modulus + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &p, const Integer &q, const Integer &u); + + /// \brief Create a Rabin-Williams private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void Save(BufferedTransformation &bt) const + {DEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + + virtual bool SupportsPrecomputation() const {return true;} + virtual void Precompute(unsigned int unused = 0) {CRYPTOPP_UNUSED(unused); PrecomputeTweakedRoots();} + virtual void Precompute(unsigned int unused = 0) const {CRYPTOPP_UNUSED(unused); PrecomputeTweakedRoots();} + + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation); + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const; + +protected: + void PrecomputeTweakedRoots() const; + +protected: + Integer m_p, m_q, m_u; + + mutable Integer m_pre_2_9p, m_pre_2_3q, m_pre_q_p; + mutable bool m_precompute; +}; + +/// \brief Rabin-Williams keys +/// \since Crypto++ 3.0 +struct RW +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RW";} + typedef RWFunction PublicKey; + typedef InvertibleRWFunction PrivateKey; +}; + +/// \brief Rabin-Williams signature scheme +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \since Crypto++ 3.0 +template +struct RWSS : public TF_SS +{ +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/safer.h b/include/cryptlib/safer.h new file mode 100644 index 0000000..dacd8c3 --- /dev/null +++ b/include/cryptlib/safer.h @@ -0,0 +1,98 @@ +// safer.h - originally written and placed in the public domain by Wei Dai + +/// \file safer.h +/// \brief Classes for the SAFER and SAFER-K block ciphers + +#ifndef CRYPTOPP_SAFER_H +#define CRYPTOPP_SAFER_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SAFER block cipher +class SAFER +{ +public: + /// \brief SAFER block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipher + { + public: + unsigned int OptimalDataAlignment() const {return 1;} + void UncheckedSetKey(const byte *userkey, unsigned int length, const NameValuePairs ¶ms); + + protected: + virtual bool Strengthened() const =0; + + SecByteBlock keySchedule; + static const byte exp_tab[256]; + static const byte log_tab[256]; + }; + + /// \brief SAFER block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SAFER block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; +}; + +/// \brief SAFER block cipher default implementation +/// \tparam BASE SAFER::Enc or SAFER::Dec derived base class +/// \tparam INFO SAFER_Info derived class +/// \tparam STR flag indicating a strengthened implementation +/// \details SAFER-K is not strengthened; while SAFER-SK is strengthened. +template +class CRYPTOPP_NO_VTABLE SAFER_Impl : public BlockCipherImpl +{ +protected: + bool Strengthened() const {return STR;} +}; + +/// \brief SAFER-K block cipher information +struct SAFER_K_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SAFER-K";} +}; + +/// \brief SAFER-K block cipher +/// \sa SAFER-K +class SAFER_K : public SAFER_K_Info, public SAFER, public BlockCipherDocumentation +{ +public: + typedef BlockCipherFinal > Encryption; + typedef BlockCipherFinal > Decryption; +}; + +/// \brief SAFER-SK block cipher information +struct SAFER_SK_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SAFER-SK";} +}; + +/// \brief SAFER-SK block cipher +/// \sa SAFER-SK +class SAFER_SK : public SAFER_SK_Info, public SAFER, public BlockCipherDocumentation +{ +public: + typedef BlockCipherFinal > Encryption; + typedef BlockCipherFinal > Decryption; +}; + +typedef SAFER_K::Encryption SAFER_K_Encryption; +typedef SAFER_K::Decryption SAFER_K_Decryption; + +typedef SAFER_SK::Encryption SAFER_SK_Encryption; +typedef SAFER_SK::Decryption SAFER_SK_Decryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/salsa.h b/include/cryptlib/salsa.h new file mode 100644 index 0000000..e01c9a0 --- /dev/null +++ b/include/cryptlib/salsa.h @@ -0,0 +1,89 @@ +// salsa.h - originally written and placed in the public domain by Wei Dai + +/// \file salsa.h +/// \brief Classes for Salsa and Salsa20 stream ciphers + +#ifndef CRYPTOPP_SALSA_H +#define CRYPTOPP_SALSA_H + +#include "strciphr.h" +#include "secblock.h" + +// "Inline assembly operands don't work with .intel_syntax", http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_INTEL_ASM) +# define CRYPTOPP_DISABLE_SALSA_ASM +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Salsa20 core transform +/// \param data the data to transform +/// \param rounds the number of rounds +/// \details Several algorithms, like CryptoBox and Scrypt, require access to +/// the core Salsa20 transform. The current Crypto++ implementation does not +/// lend itself to disgorging the Salsa20 cipher from the Salsa20 core transform. +/// Instead Salsa20_Core is provided with customary accelerations. +void Salsa20_Core(word32* data, unsigned int rounds); + +/// \brief Salsa20 stream cipher information +struct Salsa20_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + static std::string StaticAlgorithmName() {return "Salsa20";} +}; + +/// \brief Salsa20 stream cipher operation +class CRYPTOPP_NO_VTABLE Salsa20_Policy : public AdditiveCipherConcretePolicy +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; +#endif + + FixedSizeAlignedSecBlock m_state; + int m_rounds; +}; + +/// \brief Salsa20 stream cipher +/// \details Salsa20 provides a variable number of rounds: 8, 12 or 20. The default number of rounds is 20. +/// \sa XSalsa20 +struct Salsa20 : public Salsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, Salsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +/// \brief XSalsa20 stream cipher information +struct XSalsa20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24> +{ + static std::string StaticAlgorithmName() {return "XSalsa20";} +}; + +/// \brief XSalsa20 stream cipher operation +class CRYPTOPP_NO_VTABLE XSalsa20_Policy : public Salsa20_Policy +{ +public: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + +protected: + FixedSizeSecBlock m_key; +}; + +/// \brief XSalsa20 stream cipher +/// \details XSalsa20 provides a variable number of rounds: 8, 12 or 20. The default number of rounds is 20. +/// \sa XSalsa20 +struct XSalsa20 : public XSalsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, XSalsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/scrypt.h b/include/cryptlib/scrypt.h new file mode 100644 index 0000000..5d36ab6 --- /dev/null +++ b/include/cryptlib/scrypt.h @@ -0,0 +1,101 @@ +// scrypt.h - written and placed in public domain by Jeffrey Walton. +// Based on reference source code by Colin Percival. + +/// \file scrypt.h +/// \brief Classes for Scrypt from RFC 7914 +/// \sa Stronger Key Derivation via +/// Sequential Memory-Hard Functions, +/// The scrypt key derivation function +/// and RFC 7914, The scrypt Password-Based +/// Key Derivation Function +/// \since Crypto++ 6.2 + +#ifndef CRYPTOPP_SCRYPT_H +#define CRYPTOPP_SCRYPT_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Scrypt key derivation function +/// \details The Crypto++ implementation uses OpenMP to accelerate the derivation when +/// available. +/// \details The Crypto++ implementation of Scrypt is limited by C++ datatypes. For +/// example, the library is limited to a derived key length of SIZE_MAX, +/// and not (2^32 - 1) * 32. +/// \sa Stronger Key Derivation via +/// Sequential Memory-Hard Functions, +/// The scrypt key derivation function +/// and RFC 7914, The scrypt Password-Based +/// Key Derivation Function +/// \since Crypto++ 6.2 +class Scrypt : public KeyDerivationFunction +{ +public: + virtual ~Scrypt() {} + + static std::string StaticAlgorithmName () { + return "scrypt"; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedLength() const { + return static_cast(-1); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params) const; + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param cost the CPU/memory cost factor + /// \param blockSize the block size + /// \param parallelization the parallelization factor + /// \returns the number of iterations performed + /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details The CPU/Memory cost parameter ("N" in the documents) must be + /// larger than 1, a power of 2, and less than 2^(128 * r / 8). + /// \details The parameter blockSize ("r" in the documents) specifies the block + /// size. + /// \details The parallelization parameter ("p" in the documents) is a positive + /// integer less than or equal to ((2^32-1) * 32) / (128 * r). + /// \details Scrypt always returns 1 because it only performs 1 iteration. Other + /// derivation functions, like PBKDF's, will return more interesting values. + /// \details The Crypto++ implementation of Scrypt is limited by C++ datatypes. For + /// example, the library is limited to a derived key length of SIZE_MAX, + /// and not (2^32 - 1) * 32. + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, word64 cost=2, word64 blockSize=8, word64 parallelization=1) const; + +protected: + enum {defaultCost=2, defaultBlockSize=8, defaultParallelization=1}; + + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } + + inline void ValidateParameters(size_t derivedlen, word64 cost, word64 blockSize, word64 parallelization) const; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SCRYPT_H diff --git a/include/cryptlib/seal.h b/include/cryptlib/seal.h new file mode 100644 index 0000000..750df96 --- /dev/null +++ b/include/cryptlib/seal.h @@ -0,0 +1,59 @@ +// seal.h - originally written and placed in the public domain by Wei Dai + +/// \file seal.h +/// \brief Classes for SEAL stream cipher +/// \since Crypto++ 2.2 + +#ifndef CRYPTOPP_SEAL_H +#define CRYPTOPP_SEAL_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SEAL stream cipher information +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 2.2 +template +struct SEAL_Info : public FixedKeyLength<20, SimpleKeyingInterface::INTERNALLY_GENERATED_IV, 4> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "SEAL-3.0-LE" : "SEAL-3.0-BE";} +}; + +/// \brief SEAL stream cipher operation +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 2.2 +template +class CRYPTOPP_NO_VTABLE SEAL_Policy : public AdditiveCipherConcretePolicy, public SEAL_Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + +private: + FixedSizeSecBlock m_T; + FixedSizeSecBlock m_S; + SecBlock m_R; + + word32 m_startCount, m_iterationsPerCount; + word32 m_outsideCounter, m_insideCounter; +}; + +/// \brief SEAL stream cipher +/// \tparam B Endianness of the stream cipher +/// \sa SEAL +/// \since Crypto++ 2.2 +template +struct SEAL : public SEAL_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, SEAL_Info > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/secblock.h b/include/cryptlib/secblock.h new file mode 100644 index 0000000..013e703 --- /dev/null +++ b/include/cryptlib/secblock.h @@ -0,0 +1,899 @@ +// secblock.h - originally written and placed in the public domain by Wei Dai + +/// \file secblock.h +/// \brief Classes and functions for secure memory allocations. + +#ifndef CRYPTOPP_SECBLOCK_H +#define CRYPTOPP_SECBLOCK_H + +#include "config.h" +#include "stdcpp.h" +#include "misc.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275 4700) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** secure memory allocation *************** + +/// \brief Base class for all allocators used by SecBlock +/// \tparam T the class or type +template +class AllocatorBase +{ +public: + typedef T value_type; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef T & reference; + typedef const T & const_reference; + + pointer address(reference r) const {return (&r);} + const_pointer address(const_reference r) const {return (&r); } + void construct(pointer p, const T& val) {new (p) T(val);} + void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();} + + /// \brief Returns the maximum number of elements the allocator can provide + /// \details ELEMS_MAX is the maximum number of elements the + /// Allocator can provide. The value of ELEMS_MAX is + /// SIZE_MAX/sizeof(T). std::numeric_limits was avoided + /// due to lack of constexpr-ness in C++03 and below. + /// \note In C++03 and below ELEMS_MAX is a static data member of type + /// size_type. In C++11 and above ELEMS_MAX is an enum + /// inheriting from size_type. In both cases ELEMS_MAX can be + /// used before objects are fully constructed, and it does not suffer the + /// limitations of class methods like max_size. + /// \sa Issue 346/CVE-2016-9939 + /// \since Crypto++ 6.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + static const size_type ELEMS_MAX = ...; +#elif defined(CRYPTOPP_CXX11_ENUM) + enum : size_type {ELEMS_MAX = SIZE_MAX/sizeof(T)}; +#else + static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); +#endif + + /// \brief Returns the maximum number of elements the allocator can provide + /// \returns the maximum number of elements the allocator can provide + /// \details Internally, preprocessor macros are used rather than std::numeric_limits + /// because the latter is not a constexpr. Some compilers, like Clang, do not + /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + /// to optimize it well in either form. + CRYPTOPP_CONSTEXPR size_type max_size() const {return ELEMS_MAX;} + +#if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief Constructs a new V using variadic arguments + /// \tparam V the type to be forwarded + /// \tparam Args the arguments to be forwarded + /// \param ptr pointer to type V + /// \param args variadic arguments + /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + /// is defined. The define is controlled by compiler versions detected in config.h. + template + void construct(V* ptr, Args&&... args) {::new ((void*)ptr) V(std::forward(args)...);} + + /// \brief Destroys an V constructed with variadic arguments + /// \tparam V the type to be forwarded + /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + /// is defined. The define is controlled by compiler versions detected in config.h. + template + void destroy(V* ptr) {if (ptr) ptr->~V();} + +#endif + +protected: + + /// \brief Verifies the allocator can satisfy a request based on size + /// \param size the size of the allocation, in elements + /// \throws InvalidArgument + /// \details CheckSize verifies the number of elements requested is valid. + /// \details If size is greater than max_size(), then InvalidArgument is thrown. + /// The library throws InvalidArgument if the size is too large to satisfy. + /// \details Internally, preprocessor macros are used rather than std::numeric_limits + /// because the latter is not a constexpr. Some compilers, like Clang, do not + /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + /// to optimize it well in either form. + /// \details The sizeof(T) != 1 in the condition attempts to help the + /// compiler optimize the check for byte types. Coverity findings for + /// CONSTANT_EXPRESSION_RESULT were generated without it. For byte types, + /// size never exceeded ELEMS_MAX but the code was not removed. + /// \note size is the count of elements, and not the number of bytes + static void CheckSize(size_t size) + { + // Squash MSC C4100 warning for size. Also see commit 42b7c4ea5673. + CRYPTOPP_UNUSED(size); + // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here. + if (sizeof(T) != 1 && size > ELEMS_MAX) + throw InvalidArgument("AllocatorBase: requested size would cause integer overflow"); + } +}; + +#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \ +typedef typename AllocatorBase::value_type value_type;\ +typedef typename AllocatorBase::size_type size_type;\ +typedef typename AllocatorBase::difference_type difference_type;\ +typedef typename AllocatorBase::pointer pointer;\ +typedef typename AllocatorBase::const_pointer const_pointer;\ +typedef typename AllocatorBase::reference reference;\ +typedef typename AllocatorBase::const_reference const_reference; + +/// \brief Reallocation function +/// \tparam T the class or type +/// \tparam A the class or type's allocator +/// \param alloc the allocator +/// \param oldPtr the previous allocation +/// \param oldSize the size of the previous allocation +/// \param newSize the new, requested size +/// \param preserve flag that indicates if the old allocation should be preserved +/// \note oldSize and newSize are the count of elements, and not the +/// number of bytes. +template +typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve) +{ + CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize)); + if (oldSize == newSize) + return oldPtr; + + if (preserve) + { + typename A::pointer newPointer = alloc.allocate(newSize, NULLPTR); + const size_t copySize = STDMIN(oldSize, newSize) * sizeof(T); + + if (oldPtr && newPointer) {memcpy_s(newPointer, copySize, oldPtr, copySize);} + alloc.deallocate(oldPtr, oldSize); + return newPointer; + } + else + { + alloc.deallocate(oldPtr, oldSize); + return alloc.allocate(newSize, NULLPTR); + } +} + +/// \brief Allocates a block of memory with cleanup +/// \tparam T class or type +/// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary +/// \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate() +/// for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls +/// UnalignedAllocate() for memory allocations. +/// \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors +/// CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter. +template +class AllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + /// \brief Allocates a block of memory + /// \param ptr the size of the allocation + /// \param size the size of the allocation, in elements + /// \returns a memory block + /// \throws InvalidArgument + /// \details allocate() first checks the size of the request. If it is non-0 + /// and less than max_size(), then an attempt is made to fulfill the request using either + /// AlignedAllocate() or UnalignedAllocate(). + /// \details AlignedAllocate() is used if T_Align16 is true. + /// UnalignedAllocate() used if T_Align16 is false. + /// \details This is the C++ *Placement New* operator. ptr is not used, and the function + /// CRYPTOPP_ASSERTs in Debug builds if ptr is non-NULL. + /// \sa CallNewHandler() for the methods used to recover from a failed + /// allocation attempt. + /// \note size is the count of elements, and not the number of bytes + pointer allocate(size_type size, const void *ptr = NULLPTR) + { + CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULLPTR); + this->CheckSize(size); + if (size == 0) + return NULLPTR; + +#if CRYPTOPP_BOOL_ALIGN16 + // TODO: Does this need the test 'size*sizeof(T) >= 16'? + if (T_Align16 && size) + return (pointer)AlignedAllocate(size*sizeof(T)); +#endif + + return (pointer)UnalignedAllocate(size*sizeof(T)); + } + + /// \brief Deallocates a block of memory + /// \param ptr the pointer for the allocation + /// \param size the size of the allocation, in elements + /// \details Internally, SecureWipeArray() is called before deallocating the memory. + /// Once the memory block is wiped or zeroized, AlignedDeallocate() or + /// UnalignedDeallocate() is called. + /// \details AlignedDeallocate() is used if T_Align16 is true. + /// UnalignedDeallocate() used if T_Align16 is false. + void deallocate(void *ptr, size_type size) + { + // This will fire if SetMark(0) was called in the SecBlock + // Our self tests exercise it, disable it now. + // CRYPTOPP_ASSERT((ptr && size) || !(ptr || size)); + SecureWipeArray((pointer)ptr, size); + +#if CRYPTOPP_BOOL_ALIGN16 + if (T_Align16 && size) + return AlignedDeallocate(ptr); +#endif + + UnalignedDeallocate(ptr); + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should be preserved + /// \returns pointer to the new memory block + /// \details Internally, reallocate() calls StandardReallocate(). + /// \details If preserve is true, then index 0 is used to begin copying the + /// old memory block to the new one. If the block grows, then the old array + /// is copied in its entirety. If the block shrinks, then only newSize + /// elements are copied from the old block to the new one. + /// \note oldSize and newSize are the count of elements, and not the + /// number of bytes. + pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize)); + return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve); + } + + /// \brief Template class memeber Rebind + /// \tparam V bound class or type + /// \details Rebind allows a container class to allocate a different type of object + /// to store elements. For example, a std::list will allocate std::list_node to + /// store elements in the list. + /// \details VS.NET STL enforces the policy of "All STL-compliant allocators + /// have to provide a template class member called rebind". + template struct rebind { typedef AllocatorWithCleanup other; }; +#if _MSC_VER >= 1500 + AllocatorWithCleanup() {} + template AllocatorWithCleanup(const AllocatorWithCleanup &) {} +#endif +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +#if defined(CRYPTOPP_WORD128_AVAILABLE) +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; // for Integer +#endif +#if CRYPTOPP_BOOL_X86 +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; // for Integer +#endif + +/// \brief NULL allocator +/// \tparam T class or type +/// \details A NullAllocator is useful for fixed-size, stack based allocations +/// (i.e., static arrays used by FixedSizeAllocatorWithCleanup). +/// \details A NullAllocator always returns 0 for max_size(), and always returns +/// NULL for allocation requests. Though the allocator does not allocate at +/// runtime, it does perform a secure wipe or zeroization during cleanup. +template +class NullAllocator : public AllocatorBase +{ +public: + //LCOV_EXCL_START + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard + // libraries always throw. And late mode Windows throws. Early model Windows + // (circa VC++ 6.0) returned NULL. + pointer allocate(size_type n, const void* unused = NULLPTR) + { + CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused); + CRYPTOPP_ASSERT(false); return NULLPTR; + } + + void deallocate(void *p, size_type n) + { + CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n); + CRYPTOPP_ASSERT(false); + } + + CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;} + //LCOV_EXCL_STOP +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template , bool T_Align16 = false> +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES + + /// \brief Constructs a FixedSizeAllocatorWithCleanup + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based + /// allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size); + } + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \param hint an unused hint + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size, const void *hint) + { + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size, hint); + } + + /// \brief Deallocates a block of memory + /// \param ptr a pointer to the memory block to deallocate + /// \param size the count elements in the memory block + /// \details The memory block is wiped or zeroized before deallocation. + /// If the statically allocated memory block is active, then no + /// additional actions are taken after the wipe. + /// \details If a dynamic memory block is active, then the pointer and + /// size are passed to the allocator for deallocation. + void deallocate(void *ptr, size_type size) + { + if (ptr == GetAlignedArray()) + { + CRYPTOPP_ASSERT(size <= S); + CRYPTOPP_ASSERT(m_allocated); + m_allocated = false; + SecureWipeArray((pointer)ptr, size); + } + else + m_fallbackAllocator.deallocate(ptr, size); + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should be preserved + /// \returns pointer to the new memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \note size is the count of elements, and not the number of bytes. + /// \sa reallocate(), SecBlockWithHint + pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + if (oldPtr == GetAlignedArray() && newSize <= S) + { + CRYPTOPP_ASSERT(oldSize <= S); + if (oldSize > newSize) + SecureWipeArray(oldPtr+newSize, oldSize-newSize); + return oldPtr; + } + + pointer newPointer = allocate(newSize, NULLPTR); + if (preserve && newSize) + { + const size_t copySize = STDMIN(oldSize, newSize); + memcpy_s(newPointer, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); + } + deallocate(oldPtr, oldSize); + return newPointer; + } + + CRYPTOPP_CONSTEXPR size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);} + +private: + +#ifdef __BORLANDC__ + T* GetAlignedArray() {return m_array;} + T m_array[S]; +#else + T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? (T*)(void *)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;} + CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16 && T_Align16) ? S+8/sizeof(T) : S]; +#endif + + A m_fallbackAllocator; + bool m_allocated; +}; + +/// \brief Secure memory block with allocator and cleanup +/// \tparam T a class or type +/// \tparam A AllocatorWithCleanup derived class for allocation and cleanup +template > +class SecBlock +{ +public: + typedef typename A::value_type value_type; + typedef typename A::pointer iterator; + typedef typename A::const_pointer const_iterator; + typedef typename A::size_type size_type; + + /// \brief Returns the maximum number of elements the block can hold + /// \details ELEMS_MAX is the maximum number of elements the + /// SecBlock can hold. The value of ELEMS_MAX is + /// SIZE_MAX/sizeof(T). std::numeric_limits was avoided + /// due to lack of constexpr-ness in C++03 and below. + /// \note In C++03 and below ELEMS_MAX is a static data member of type + /// size_type. In C++11 and above ELEMS_MAX is an enum + /// inheriting from size_type. In both cases ELEMS_MAX can be + /// used before objects are fully constructed, and it does not suffer the + /// limitations of class methods like max_size. + /// \sa Issue 346/CVE-2016-9939 + /// \since Crypto++ 6.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + static const size_type ELEMS_MAX = ...; +#elif defined(CRYPTOPP_CXX11_ENUM) + enum : size_type {ELEMS_MAX = A::ELEMS_MAX}; +#else + static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); +#endif + + /// \brief Construct a SecBlock with space for size elements. + /// \param size the size of the allocation, in elements + /// \throws std::bad_alloc + /// \details The elements are not initialized. + /// \note size is the count of elements, and not the number of bytes + explicit SecBlock(size_type size=0) + : m_mark(ELEMS_MAX), m_size(size), m_ptr(m_alloc.allocate(size, NULLPTR)) { } + + /// \brief Copy construct a SecBlock from another SecBlock + /// \param t the other SecBlock + /// \throws std::bad_alloc + SecBlock(const SecBlock &t) + : m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULLPTR)) { + CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size)); + if (t.m_ptr) {memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));} + } + + /// \brief Construct a SecBlock from an array of elements. + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \throws std::bad_alloc + /// \details If ptr!=NULL and len!=0, then the block is initialized from the pointer + /// ptr. If ptr==NULL and len!=0, then the block is initialized to 0. + /// Otherwise, the block is empty and not initialized. + /// \note size is the count of elements, and not the number of bytes + SecBlock(const T *ptr, size_type len) + : m_mark(ELEMS_MAX), m_size(len), m_ptr(m_alloc.allocate(len, NULLPTR)) { + CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); + if (ptr && m_ptr) + memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); + else if (m_size) + memset(m_ptr, 0, m_size*sizeof(T)); + } + + ~SecBlock() + {m_alloc.deallocate(m_ptr, STDMIN(m_size, m_mark));} + +#ifdef __BORLANDC__ + operator T *() const + {return (T*)m_ptr;} +#else + operator const void *() const + {return m_ptr;} + operator void *() + {return m_ptr;} + + operator const T *() const + {return m_ptr;} + operator T *() + {return m_ptr;} +#endif + + /// \brief Provides an iterator pointing to the first element in the memory block + /// \returns iterator pointing to the first element in the memory block + iterator begin() + {return m_ptr;} + /// \brief Provides a constant iterator pointing to the first element in the memory block + /// \returns constant iterator pointing to the first element in the memory block + const_iterator begin() const + {return m_ptr;} + /// \brief Provides an iterator pointing beyond the last element in the memory block + /// \returns iterator pointing beyond the last element in the memory block + iterator end() + {return m_ptr+m_size;} + /// \brief Provides a constant iterator pointing beyond the last element in the memory block + /// \returns constant iterator pointing beyond the last element in the memory block + const_iterator end() const + {return m_ptr+m_size;} + + /// \brief Provides a pointer to the first element in the memory block + /// \returns pointer to the first element in the memory block + typename A::pointer data() {return m_ptr;} + /// \brief Provides a pointer to the first element in the memory block + /// \returns constant pointer to the first element in the memory block + typename A::const_pointer data() const {return m_ptr;} + + /// \brief Provides the count of elements in the SecBlock + /// \returns number of elements in the memory block + /// \note the return value is the count of elements, and not the number of bytes + size_type size() const {return m_size;} + /// \brief Determines if the SecBlock is empty + /// \returns true if number of elements in the memory block is 0, false otherwise + bool empty() const {return m_size == 0;} + + /// \brief Provides a byte pointer to the first element in the memory block + /// \returns byte pointer to the first element in the memory block + byte * BytePtr() {return (byte *)m_ptr;} + /// \brief Return a byte pointer to the first element in the memory block + /// \returns constant byte pointer to the first element in the memory block + const byte * BytePtr() const {return (const byte *)m_ptr;} + /// \brief Provides the number of bytes in the SecBlock + /// \return the number of bytes in the memory block + /// \note the return value is the number of bytes, and not count of elements. + size_type SizeInBytes() const {return m_size*sizeof(T);} + + /// \brief Sets the number of elements to zeroize + /// \param count the number of elements + /// \details SetMark is a remediation for Issue 346/CVE-2016-9939 while + /// preserving the streaming interface. The count controls the number of + /// elements zeroized, which can be less than size or 0. + /// \details An internal variable, m_mark, is initialized to the maximum number + /// of elements. The maximum number of elements is ELEMS_MAX. Deallocation + /// triggers a zeroization, and the number of elements zeroized is + /// STDMIN(m_size, m_mark). After zeroization, the memory is returned to the + /// system. + /// \details The ASN.1 decoder uses SetMark() to set the element count to 0 + /// before throwing an exception. In this case, the attacker provides a large + /// BER encoded length (say 64MB) but only a small number of content octets + /// (say 16). If the allocator zeroized all 64MB, then a transient DoS could + /// occur as CPU cycles are spent zeroizing unintialized memory. + /// \details Generally speaking, any operation which changes the size of the SecBlock + /// results in the mark being reset to ELEMS_MAX. In particular, if Assign(), + /// New(), Grow(), CleanNew(), CleanGrow() are called, then the count is reset to + /// ELEMS_MAX. The list is not exhaustive. + /// \since Crypto++ 6.0 + /// \sa Issue 346/CVE-2016-9939 + void SetMark(size_t count) {m_mark = count;} + + /// \brief Set contents and size from an array + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0. + /// Assign() resets the element count after the previous block is zeroized. + void Assign(const T *ptr, size_type len) + { + New(len); + if (m_ptr && ptr) + {memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));} + m_mark = ELEMS_MAX; + } + + /// \brief Set contents from a value + /// \param count the number of values to copy + /// \param value the value, repeated count times + /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0. + /// Assign() resets the element count after the previous block is zeroized. + void Assign(size_type count, T value) + { + New(count); + for (size_t i=0; i &t) + { + if (this != &t) + { + New(t.m_size); + if (m_ptr && t.m_ptr) + {memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T));} + } + m_mark = ELEMS_MAX; + } + + /// \brief Assign contents from another SecBlock + /// \param t the other SecBlock + /// \details Internally, operator=() calls Assign(). + /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0. + /// If an assignment occurs, then Assign() resets the element count after the previous block + /// is zeroized. + SecBlock& operator=(const SecBlock &t) + { + // Assign guards for self-assignment + Assign(t); + return *this; + } + + /// \brief Append contents from another SecBlock + /// \param t the other SecBlock + /// \details Internally, this SecBlock calls Grow and then appends t. + SecBlock& operator+=(const SecBlock &t) + { + CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size)); + if (t.m_size) + { + const size_type oldSize = m_size; + if (this != &t) // s += t + { + Grow(m_size+t.m_size); + memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + } + else // t += t + { + Grow(m_size*2); + memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T)); + } + } + m_mark = ELEMS_MAX; + return *this; + } + + /// \brief Construct a SecBlock from this and another SecBlock + /// \param t the other SecBlock + /// \returns a newly constructed SecBlock that is a conacentation of this and t + /// \details Internally, a new SecBlock is created from this and a concatenation of t. + SecBlock operator+(const SecBlock &t) + { + CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); + CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size)); + if(!t.m_size) return SecBlock(*this); + + SecBlock result(m_size+t.m_size); + if (m_size) {memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));} + memcpy_s(result.m_ptr+m_size, (result.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + return result; + } + + /// \brief Bitwise compare two SecBlocks + /// \param t the other SecBlock + /// \returns true if the size and bits are equal, false otherwise + /// \details Uses a constant time compare if the arrays are equal size. The constant time + /// compare is VerifyBufsEqual() found in misc.h. + /// \sa operator!=() + bool operator==(const SecBlock &t) const + { + return m_size == t.m_size && + VerifyBufsEqual(reinterpret_cast(m_ptr), reinterpret_cast(t.m_ptr), m_size*sizeof(T)); + } + + /// \brief Bitwise compare two SecBlocks + /// \param t the other SecBlock + /// \returns true if the size and bits are equal, false otherwise + /// \details Uses a constant time compare if the arrays are equal size. The constant time + /// compare is VerifyBufsEqual() found in misc.h. + /// \details Internally, operator!=() returns the inverse of operator==(). + /// \sa operator==() + bool operator!=(const SecBlock &t) const + { + return !operator==(t); + } + + /// \brief Change size without preserving contents + /// \param newSize the new size of the memory block + /// \details Old content is not preserved. If the memory block is reduced in size, + /// then the reclaimed memory is set to 0. If the memory block grows in size, then + /// the new memory is not initialized. New() resets the element count after the + /// previous block is zeroized. + /// \details Internally, this SecBlock calls reallocate(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void New(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false); + m_size = newSize; + m_mark = ELEMS_MAX; + } + + /// \brief Change size without preserving contents + /// \param newSize the new size of the memory block + /// \details Old content is not preserved. If the memory block is reduced in size, + /// then the reclaimed content is set to 0. If the memory block grows in size, then + /// the new memory is initialized to 0. CleanNew() resets the element count after the + /// previous block is zeroized. + /// \details Internally, this SecBlock calls New(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void CleanNew(size_type newSize) + { + New(newSize); + if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));} + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. New content is not initialized. + /// \details Internally, this SecBlock calls reallocate() when size must increase. If the + /// size does not increase, then Grow() does not take action. If the size must + /// change, then use resize(). Grow() resets the element count after the + /// previous block is zeroized. + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void Grow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. New content is initialized to 0. + /// \details Internally, this SecBlock calls reallocate() when size must increase. If the + /// size does not increase, then CleanGrow() does not take action. If the size must + /// change, then use resize(). CleanGrow() resets the element count after the + /// previous block is zeroized. + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void CleanGrow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T)); + m_size = newSize; + } + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. If the memory block grows in size, then + /// new memory is not initialized. resize() resets the element count after + /// the previous block is zeroized. + /// \details Internally, this SecBlock calls reallocate(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void resize(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + m_mark = ELEMS_MAX; + } + + /// \brief Swap contents with another SecBlock + /// \param b the other SecBlock + /// \details Internally, std::swap() is called on m_alloc, m_size and m_ptr. + void swap(SecBlock &b) + { + // Swap must occur on the allocator in case its FixedSize that spilled into the heap. + std::swap(m_alloc, b.m_alloc); + std::swap(m_mark, b.m_mark); + std::swap(m_size, b.m_size); + std::swap(m_ptr, b.m_ptr); + } + +protected: + A m_alloc; + size_type m_mark, m_size; + T *m_ptr; +}; + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief \ref SecBlock "SecBlock" typedef. +class SecByteBlock : public SecBlock {}; +/// \brief \ref SecBlock "SecBlock" typedef. +class SecWordBlock : public SecBlock {}; +/// \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup" typedef +class AlignedSecByteBlock : public SecBlock > {}; +#else +typedef SecBlock SecByteBlock; +typedef SecBlock SecWordBlock; +typedef SecBlock > AlignedSecByteBlock; +#endif + +// No need for move semantics on derived class *if* the class does not add any +// data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}. + +/// \brief Fixed size stack-based SecBlock +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam A AllocatorBase derived class for allocation and cleanup +template > +class FixedSizeSecBlock : public SecBlock +{ +public: + /// \brief Construct a FixedSizeSecBlock + explicit FixedSizeSecBlock() : SecBlock(S) {} +}; + +/// \brief Fixed size stack-based SecBlock with 16-byte alignment +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary +template +class FixedSizeAlignedSecBlock : public FixedSizeSecBlock, T_Align16> > +{ +}; + +/// \brief Stack-based SecBlock that grows into the heap +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam A AllocatorBase derived class for allocation and cleanup +template > > +class SecBlockWithHint : public SecBlock +{ +public: + /// construct a SecBlockWithHint with a count of elements + explicit SecBlockWithHint(size_t size) : SecBlock(size) {} +}; + +template +inline bool operator==(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (true);} +template +inline bool operator!=(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (false);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template +inline void swap(CryptoPP::SecBlock &a, CryptoPP::SecBlock &b) +{ + a.swap(b); +} + +#if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES)) +// working for STLport 5.1.3 and MSVC 6 SP5 +template +inline CryptoPP::AllocatorWithCleanup<_Tp2>& +__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*) +{ + return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a); +} +#endif + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/seckey.h b/include/cryptlib/seckey.h new file mode 100644 index 0000000..b4d1faa --- /dev/null +++ b/include/cryptlib/seckey.h @@ -0,0 +1,466 @@ +// seckey.h - originally written and placed in the public domain by Wei Dai + +/// \file seckey.h +/// \brief Classes and functions for implementing secret key algorithms. + +#ifndef CRYPTOPP_SECKEY_H +#define CRYPTOPP_SECKEY_H + +#include "config.h" +#include "cryptlib.h" +#include "misc.h" +#include "simple.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4189) +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Inverts the cipher's direction +/// \param dir the cipher's direction +/// \returns DECRYPTION if \ref CipherDir "dir" is ENCRYPTION, DECRYPTION otherwise +inline CipherDir ReverseCipherDir(CipherDir dir) +{ + return (dir == ENCRYPTION) ? DECRYPTION : ENCRYPTION; +} + +/// \brief Inherited by algorithms with fixed block size +/// \tparam N the blocksize of the algorithm +template +class FixedBlockSize +{ +public: + /// \brief The block size of the algorithm provided as a constant. + CRYPTOPP_CONSTANT(BLOCKSIZE = N) + /// \brief The default blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(DEFAULT_BLOCKSIZE = N) + /// \brief The minimum blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MIN_BLOCKSIZE = N) + /// \brief The maximum blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MAX_BLOCKSIZE = N) + /// \brief The default block size for the algorithm provided by a static function. + /// \param blocksize the block size, in bytes + /// \details The default implementation returns BLOCKSIZE. blocksize is unused + /// in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidBlockSize(size_t blocksize) + { + return CRYPTOPP_UNUSED(blocksize), static_cast(BLOCKSIZE); + } + /// \brief The default block size under a key provided by a static function. + /// \param keylength the size of the key, in bytes + /// \param blocksize the block size, in bytes + /// \details The default implementation returns BLOCKSIZE. blocksize is unused + /// in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidBlockSize(size_t keylength, size_t blocksize) + { + return CRYPTOPP_UNUSED(keylength), CRYPTOPP_UNUSED(blocksize), static_cast(BLOCKSIZE); + } +}; + +// ************** rounds *************** + +/// \brief Inherited by algorithms with fixed number of rounds +/// \tparam R the number of rounds used by the algorithm +template +class FixedRounds +{ +public: + /// \brief The number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(ROUNDS = R) +}; + +/// \brief Inherited by algorithms with variable number of rounds +/// \tparam D Default number of rounds +/// \tparam N Minimum number of rounds +/// \tparam M Maximum number of rounds +template // use INT_MAX here because enums are treated as signed ints +class VariableRounds +{ +public: + /// \brief The default number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(DEFAULT_ROUNDS = D) + /// \brief The minimum number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MIN_ROUNDS = N) + /// \brief The maximum number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MAX_ROUNDS = M) + /// \brief The default number of rounds for the algorithm based on key length + /// provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details keylength is unused in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR unsigned int StaticGetDefaultRounds(size_t keylength) + { + return CRYPTOPP_UNUSED(keylength), static_cast(DEFAULT_ROUNDS); + } + +protected: + /// \brief Validates the number of rounds for an algorithm. + /// \param rounds the candidate number of rounds + /// \param alg an Algorithm object used if the number of rounds are invalid + /// \throws InvalidRounds if the number of rounds are invalid + /// \details ThrowIfInvalidRounds() validates the number of rounds and throws if invalid. + inline void ThrowIfInvalidRounds(int rounds, const Algorithm *alg) + { + if (M == INT_MAX) // Coverity and result_independent_of_operands + { + if (rounds < MIN_ROUNDS) + throw InvalidRounds(alg ? alg->AlgorithmName() : std::string("VariableRounds"), rounds); + } + else + { + if (rounds < MIN_ROUNDS || rounds > MAX_ROUNDS) + throw InvalidRounds(alg ? alg->AlgorithmName() : std::string("VariableRounds"), rounds); + } + } + + /// \brief Validates the number of rounds for an algorithm + /// \param param the candidate number of rounds + /// \param alg an Algorithm object used if the number of rounds are invalid + /// \returns the number of rounds for the algorithm + /// \throws InvalidRounds if the number of rounds are invalid + /// \details GetRoundsAndThrowIfInvalid() validates the number of rounds and throws if invalid. + inline unsigned int GetRoundsAndThrowIfInvalid(const NameValuePairs ¶m, const Algorithm *alg) + { + int rounds = param.GetIntValueWithDefault("Rounds", DEFAULT_ROUNDS); + ThrowIfInvalidRounds(rounds, alg); + return static_cast(rounds); + } +}; + +// ************** key length *************** + +/// \brief Inherited by keyed algorithms with fixed key length +/// \tparam N Default key length, in bytes +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes +/// \sa SimpleKeyingInterface +template +class FixedKeyLength +{ +public: + /// \brief The default key length used by the algorithm provided as a constant + /// \details KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(KEYLENGTH=N) + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=N) + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=N) + /// \brief The default key length used by the algorithm provided as a constant + /// \details DEFAULT_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=N) + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT = IV_REQ) + /// \brief The default IV length used by the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH = IV_L) + /// \brief The default key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details The default implementation returns KEYLENGTH. keylength is unused + /// in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + { + return CRYPTOPP_UNUSED(keylength), static_cast(KEYLENGTH); + } +}; + +/// \brief Inherited by keyed algorithms with variable key length +/// \tparam D Default key length, in bytes +/// \tparam N Minimum key length, in bytes +/// \tparam M Maximum key length, in bytes +/// \tparam Q Default key length multiple, in bytes. The default multiple is 1. +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes. The default length is 0. +/// \sa SimpleKeyingInterface +template +class VariableKeyLength +{ + // Make these private to avoid Doxygen documenting them in all derived classes + CRYPTOPP_COMPILE_ASSERT(Q > 0); + CRYPTOPP_COMPILE_ASSERT(N % Q == 0); + CRYPTOPP_COMPILE_ASSERT(M % Q == 0); + CRYPTOPP_COMPILE_ASSERT(N < M); + CRYPTOPP_COMPILE_ASSERT(D >= N); + CRYPTOPP_COMPILE_ASSERT(M >= D); + +public: + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=N) + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=M) + /// \brief The default key length used by the algorithm provided as a constant + /// \details DEFAULT_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=D) + /// \brief The key length multiple used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(KEYLENGTH_MULTIPLE=Q) + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT=IV_REQ) + /// \brief The default initialization vector length for the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH=IV_L) + /// \brief Provides a valid key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details If keylength is less than MIN_KEYLENGTH, then the function returns + /// MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, then the function + /// returns MAX_KEYLENGTH. If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns keylength rounded + /// \a down to the next smaller multiple of KEYLENGTH_MULTIPLE. + /// \details keylength is provided in bytes, not bits. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + { + return (keylength <= N) ? N : + (keylength >= M) ? M : + (keylength+Q-1) - (keylength+Q-1)%Q; + } +}; + +/// \brief Provides key lengths based on another class's key length +/// \tparam T another FixedKeyLength or VariableKeyLength class +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes +/// \sa SimpleKeyingInterface +template +class SameKeyLengthAs +{ +public: + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=T::MIN_KEYLENGTH) + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=T::MAX_KEYLENGTH) + /// \brief The default key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=T::DEFAULT_KEYLENGTH) + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT=IV_REQ) + /// \brief The default initialization vector length for the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH=IV_L) + /// \brief Provides a valid key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details If keylength is less than MIN_KEYLENGTH, then the function returns + /// MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, then the function + /// returns MAX_KEYLENGTH. If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns keylength rounded + /// \a down to the next smaller multiple of KEYLENGTH_MULTIPLE. + /// \details keylength is provided in bytes, not bits. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + {return T::StaticGetValidKeyLength(keylength);} +}; + +// ************** implementation helper for SimpleKeyingInterface *************** + +/// \brief Provides a base implementation of SimpleKeyingInterface +/// \tparam BASE a SimpleKeyingInterface derived class +/// \tparam INFO a SimpleKeyingInterface derived class +/// \details SimpleKeyingInterfaceImpl() provides a default implementation for ciphers providing a keying interface. +/// Functions are virtual and not eligible for C++11 constexpr-ness. +/// \sa Algorithm(), SimpleKeyingInterface() +template +class CRYPTOPP_NO_VTABLE SimpleKeyingInterfaceImpl : public BASE +{ +public: + /// \brief The minimum key length used by the algorithm + /// \returns minimum key length used by the algorithm, in bytes + size_t MinKeyLength() const + {return INFO::MIN_KEYLENGTH;} + + /// \brief The maximum key length used by the algorithm + /// \returns maximum key length used by the algorithm, in bytes + size_t MaxKeyLength() const + {return (size_t)INFO::MAX_KEYLENGTH;} + + /// \brief The default key length used by the algorithm + /// \returns default key length used by the algorithm, in bytes + size_t DefaultKeyLength() const + {return INFO::DEFAULT_KEYLENGTH;} + + /// \brief Provides a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \returns the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + size_t GetValidKeyLength(size_t keylength) const {return INFO::StaticGetValidKeyLength(keylength);} + + /// \brief The default IV requirements for the algorithm + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + SimpleKeyingInterface::IV_Requirement IVRequirement() const + {return (SimpleKeyingInterface::IV_Requirement)INFO::IV_REQUIREMENT;} + + /// \brief The default initialization vector length for the algorithm + /// \details IVSize is provided in bytes, not bits. The default implementation uses IV_LENGTH, which is 0. + unsigned int IVSize() const + {return INFO::IV_LENGTH;} +}; + +/// \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for block ciphers +/// \tparam INFO a SimpleKeyingInterface derived class +/// \tparam BASE a SimpleKeyingInterface derived class +/// \details BlockCipherImpl() provides a default implementation for block ciphers using AlgorithmImpl() +/// and SimpleKeyingInterfaceImpl(). Functions are virtual and not eligible for C++11 constexpr-ness. +/// \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class CRYPTOPP_NO_VTABLE BlockCipherImpl : public AlgorithmImpl > > +{ +public: + /// Provides the block size of the algorithm + /// \returns the block size of the algorithm, in bytes + unsigned int BlockSize() const {return this->BLOCKSIZE;} +}; + +/// \brief Provides class member functions to key a block cipher +/// \tparam DIR a CipherDir +/// \tparam BASE a BlockCipherImpl derived class +template +class BlockCipherFinal : public ClonableImpl, BASE> +{ +public: + /// \brief Construct a default BlockCipherFinal + /// \details The cipher is not keyed. + BlockCipherFinal() {} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + BlockCipherFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \param length the length of the byte array + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + BlockCipherFinal(const byte *key, size_t length) + {this->SetKey(key, length);} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \param length the length of the byte array + /// \param rounds the number of rounds + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKeyWithRounds. + BlockCipherFinal(const byte *key, size_t length, unsigned int rounds) + {this->SetKeyWithRounds(key, length, rounds);} + + /// \brief Provides the direction of the cipher + /// \returns true if DIR is ENCRYPTION, false otherwise + /// \sa GetCipherDirection(), IsPermutation() + bool IsForwardTransformation() const {return DIR == ENCRYPTION;} +}; + +/// \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for message authentication codes +/// \tparam INFO a SimpleKeyingInterface derived class +/// \tparam BASE a SimpleKeyingInterface derived class +/// \details MessageAuthenticationCodeImpl() provides a default implementation for message authentication codes +/// using AlgorithmImpl() and SimpleKeyingInterfaceImpl(). Functions are virtual and not subject to C++11 +/// constexpr. +/// \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class MessageAuthenticationCodeImpl : public AlgorithmImpl, INFO> +{ +}; + +/// \brief Provides class member functions to key a message authentication code +/// \tparam BASE a BlockCipherImpl derived class +/// \details A default implementation for MessageAuthenticationCode +template +class MessageAuthenticationCodeFinal : public ClonableImpl, MessageAuthenticationCodeImpl > +{ +public: + /// \brief Construct a default MessageAuthenticationCodeFinal + /// \details The message authentication code is not keyed. + MessageAuthenticationCodeFinal() {} + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the algorithm + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + MessageAuthenticationCodeFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the algorithm + /// \param length the length of the byte array + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + MessageAuthenticationCodeFinal(const byte *key, size_t length) + {this->SetKey(key, length);} +}; + +// ************** documentation *************** + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement a block cipher +/// \details These objects usually should not be used directly. See CipherModeDocumentation +/// instead. Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the BlockCipher interface. +struct BlockCipherDocumentation +{ + /// implements the BlockCipher interface + typedef BlockCipher Encryption; + /// implements the BlockCipher interface + typedef BlockCipher Decryption; +}; + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement a symmetric cipher +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the SymmetricCipher interface. Two types of classes derive +/// from this class: stream ciphers and block cipher modes. Stream ciphers can be used +/// alone, cipher mode classes need to be used with a block cipher. See CipherModeDocumentation +/// for more for information about using cipher modes and block ciphers. +struct SymmetricCipherDocumentation +{ + /// implements the SymmetricCipher interface + typedef SymmetricCipher Encryption; + /// implements the SymmetricCipher interface + typedef SymmetricCipher Decryption; +}; + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement an authenticated encryption cipher +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the AuthenticatedSymmetricCipher interface. +struct AuthenticatedSymmetricCipherDocumentation +{ + /// implements the AuthenticatedSymmetricCipher interface + typedef AuthenticatedSymmetricCipher Encryption; + /// implements the AuthenticatedSymmetricCipher interface + typedef AuthenticatedSymmetricCipher Decryption; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/include/cryptlib/seed.h b/include/cryptlib/seed.h new file mode 100644 index 0000000..63ee028 --- /dev/null +++ b/include/cryptlib/seed.h @@ -0,0 +1,44 @@ +// seed.h - originally written and placed in the public domain by Wei Dai + +/// \file seed.h +/// \brief Classes for the SEED block cipher +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_SEED_H +#define CRYPTOPP_SEED_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SEED block cipher information +/// \since Crypto++ 5.6.0 +struct SEED_Info : public FixedBlockSize<16>, public FixedKeyLength<16>, public FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SEED";} +}; + +/// \brief SEED block cipher +/// \sa SEED +/// \since Crypto++ 5.6.0 +class SEED : public SEED_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_k; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/serpent.h b/include/cryptlib/serpent.h new file mode 100644 index 0000000..02433ce --- /dev/null +++ b/include/cryptlib/serpent.h @@ -0,0 +1,57 @@ +// serpent.h - originally written and placed in the public domain by Wei Dai + +/// \file serpent.h +/// \brief Classes for the Serpent block cipher + +#ifndef CRYPTOPP_SERPENT_H +#define CRYPTOPP_SERPENT_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Serpent block cipher information +/// \since Crypto++ 3.1 +struct Serpent_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, public FixedRounds<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Serpent";} +}; + +/// \brief Serpent block cipher +/// \sa Serpent +/// \since Crypto++ 3.1 +class Serpent : public Serpent_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_key; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Serpent::Encryption SerpentEncryption; +typedef Serpent::Decryption SerpentDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/serpentp.h b/include/cryptlib/serpentp.h new file mode 100644 index 0000000..0160724 --- /dev/null +++ b/include/cryptlib/serpentp.h @@ -0,0 +1,434 @@ +// private header for Serpent and Sosemanuk + +NAMESPACE_BEGIN(CryptoPP) + +// linear transformation +#define LT(i,a,b,c,d,e) {\ + a = rotlConstant<13>(a); \ + c = rotlConstant<3>(c); \ + d = rotlConstant<7>(d ^ c ^ (a << 3)); \ + b = rotlConstant<1>(b ^ a ^ c); \ + a = rotlConstant<5>(a ^ b ^ d); \ + c = rotlConstant<22>(c ^ d ^ (b << 7));} + +// inverse linear transformation +#define ILT(i,a,b,c,d,e) {\ + c = rotrConstant<22>(c); \ + a = rotrConstant<5>(a); \ + c ^= d ^ (b << 7); \ + a ^= b ^ d; \ + b = rotrConstant<1>(b); \ + d = rotrConstant<7>(d) ^ c ^ (a << 3); \ + b ^= a ^ c; \ + c = rotrConstant<3>(c); \ + a = rotrConstant<13>(a);} + +// order of output from S-box functions +#define beforeS0(f) f(0,a,b,c,d,e) +#define afterS0(f) f(1,b,e,c,a,d) +#define afterS1(f) f(2,c,b,a,e,d) +#define afterS2(f) f(3,a,e,b,d,c) +#define afterS3(f) f(4,e,b,d,c,a) +#define afterS4(f) f(5,b,a,e,c,d) +#define afterS5(f) f(6,a,c,b,e,d) +#define afterS6(f) f(7,a,c,d,b,e) +#define afterS7(f) f(8,d,e,b,a,c) + +// order of output from inverse S-box functions +#define beforeI7(f) f(8,a,b,c,d,e) +#define afterI7(f) f(7,d,a,b,e,c) +#define afterI6(f) f(6,a,b,c,e,d) +#define afterI5(f) f(5,b,d,e,c,a) +#define afterI4(f) f(4,b,c,e,a,d) +#define afterI3(f) f(3,a,b,e,c,d) +#define afterI2(f) f(2,b,d,e,c,a) +#define afterI1(f) f(1,a,b,c,e,d) +#define afterI0(f) f(0,a,d,b,e,c) + +// The instruction sequences for the S-box functions +// come from Dag Arne Osvik's paper "Speeding up Serpent". + +#define S0(i, r0, r1, r2, r3, r4) \ + { \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r4 ^= r2; \ + r1 ^= r0; \ + r0 |= r3; \ + r0 ^= r4; \ + r4 ^= r3; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 ^= r4; \ + r4 = ~r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r1 ^= r4; \ + r3 |= r0; \ + r1 ^= r3; \ + r4 ^= r3; \ + } + +#define I0(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r1; \ + r1 |= r0; \ + r4 = ~r4; \ + r1 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 &= r3; \ + r4 ^= r0; \ + r0 |= r1; \ + r0 ^= r2; \ + r3 ^= r4; \ + r2 ^= r1; \ + r3 ^= r0; \ + r3 ^= r1; \ + r2 &= r3; \ + r4 ^= r2; \ + } + +#define S1(i, r0, r1, r2, r3, r4) \ + { \ + r0 = ~r0; \ + r2 = ~r2; \ + r4 = r0; \ + r0 &= r1; \ + r2 ^= r0; \ + r0 |= r3; \ + r3 ^= r2; \ + r1 ^= r0; \ + r0 ^= r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r2 |= r0; \ + r2 &= r4; \ + r0 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r2; \ + r0 ^= r4; \ + } + +#define I1(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r1; \ + r1 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r3 ^= r0; \ + r0 |= r1; \ + r2 ^= r3; \ + r0 ^= r4; \ + r0 |= r2; \ + r1 ^= r3; \ + r0 ^= r1; \ + r1 |= r3; \ + r1 ^= r0; \ + r4 = ~r4; \ + r4 ^= r1; \ + r1 |= r0; \ + r1 ^= r0; \ + r1 |= r4; \ + r3 ^= r1; \ + } + +#define S2(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 &= r2; \ + r0 ^= r3; \ + r2 ^= r1; \ + r2 ^= r0; \ + r3 |= r4; \ + r3 ^= r1; \ + r4 ^= r2; \ + r1 = r3; \ + r3 |= r4; \ + r3 ^= r0; \ + r0 &= r1; \ + r4 ^= r0; \ + r1 ^= r3; \ + r1 ^= r4; \ + r4 = ~r4; \ + } + +#define I2(i, r0, r1, r2, r3, r4) \ + { \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r3; \ + r3 &= r2; \ + r3 ^= r1; \ + r1 |= r2; \ + r1 ^= r4; \ + r4 &= r3; \ + r2 ^= r3; \ + r4 &= r0; \ + r4 ^= r2; \ + r2 &= r1; \ + r2 |= r0; \ + r3 = ~r3; \ + r2 ^= r3; \ + r0 ^= r3; \ + r0 &= r1; \ + r3 ^= r4; \ + r3 ^= r0; \ + } + +#define S3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 |= r3; \ + r3 ^= r1; \ + r1 &= r4; \ + r4 ^= r2; \ + r2 ^= r3; \ + r3 &= r0; \ + r4 |= r1; \ + r3 ^= r4; \ + r0 ^= r1; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r2; \ + r1 |= r0; \ + r1 ^= r2; \ + r0 ^= r3; \ + r2 = r1; \ + r1 |= r3; \ + r1 ^= r0; \ + } + +#define I3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r4; \ + r4 ^= r3; \ + r3 |= r1; \ + r3 ^= r2; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 |= r3; \ + r0 ^= r1; \ + r4 ^= r2; \ + r2 &= r3; \ + r1 |= r3; \ + r1 ^= r2; \ + r4 ^= r0; \ + r2 ^= r4; \ + } + +#define S4(i, r0, r1, r2, r3, r4) \ + { \ + r1 ^= r3; \ + r3 = ~r3; \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r1 ^= r2; \ + r4 ^= r3; \ + r0 ^= r4; \ + r2 &= r4; \ + r2 ^= r0; \ + r0 &= r1; \ + r3 ^= r0; \ + r4 |= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r2 &= r3; \ + r0 = ~r0; \ + r4 ^= r2; \ + } + +#define I4(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r3; \ + r2 ^= r1; \ + r1 |= r3; \ + r1 &= r0; \ + r4 ^= r2; \ + r4 ^= r1; \ + r1 &= r2; \ + r0 = ~r0; \ + r3 ^= r4; \ + r1 ^= r3; \ + r3 &= r0; \ + r3 ^= r2; \ + r0 ^= r1; \ + r2 &= r0; \ + r3 ^= r0; \ + r2 ^= r4; \ + r2 |= r3; \ + r3 ^= r0; \ + r2 ^= r1; \ + } + +#define S5(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r1; \ + r1 ^= r3; \ + r3 = ~r3; \ + r4 = r1; \ + r1 &= r0; \ + r2 ^= r3; \ + r1 ^= r2; \ + r2 |= r4; \ + r4 ^= r3; \ + r3 &= r1; \ + r3 ^= r0; \ + r4 ^= r1; \ + r4 ^= r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r0 ^= r4; \ + r4 |= r3; \ + r2 ^= r4; \ + } + +#define I5(i, r0, r1, r2, r3, r4) \ + { \ + r1 = ~r1; \ + r4 = r3; \ + r2 ^= r1; \ + r3 |= r0; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 ^= r4; \ + r4 |= r0; \ + r4 ^= r1; \ + r1 &= r2; \ + r1 ^= r3; \ + r4 ^= r2; \ + r3 &= r4; \ + r4 ^= r1; \ + r3 ^= r0; \ + r3 ^= r4; \ + r4 = ~r4; \ + } + +#define S6(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r3; \ + r3 &= r0; \ + r0 ^= r4; \ + r3 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r2 ^= r0; \ + r0 |= r1; \ + r2 ^= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r4 ^= r3; \ + r4 ^= r0; \ + r3 = ~r3; \ + r2 &= r4; \ + r2 ^= r3; \ + } + +#define I6(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r2; \ + r4 = r2; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 = ~r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r4 |= r0; \ + r0 ^= r2; \ + r3 ^= r4; \ + r4 ^= r1; \ + r1 &= r3; \ + r1 ^= r0; \ + r0 ^= r3; \ + r0 |= r2; \ + r3 ^= r1; \ + r4 ^= r0; \ + } + +#define S7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r1; \ + r2 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r2 ^= r1; \ + r1 ^= r0; \ + r0 |= r4; \ + r0 ^= r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r3 &= r0; \ + r3 ^= r4; \ + r4 ^= r2; \ + r2 &= r0; \ + r4 = ~r4; \ + r2 ^= r4; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r1; \ + } + +#define I7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r4 |= r3; \ + r3 ^= r1; \ + r1 |= r0; \ + r0 ^= r2; \ + r2 &= r4; \ + r1 ^= r2; \ + r2 ^= r0; \ + r0 |= r2; \ + r3 &= r4; \ + r0 ^= r3; \ + r4 ^= r1; \ + r3 ^= r4; \ + r4 |= r0; \ + r3 ^= r2; \ + r4 ^= r2; \ + } + +// key xor +#define KX(r, a, b, c, d, e) {\ + a ^= k[4 * r + 0]; \ + b ^= k[4 * r + 1]; \ + c ^= k[4 * r + 2]; \ + d ^= k[4 * r + 3];} + +#define LK(r, a, b, c, d, e) {\ + a = k[(8-r)*4 + 0]; \ + b = k[(8-r)*4 + 1]; \ + c = k[(8-r)*4 + 2]; \ + d = k[(8-r)*4 + 3];} + +#define SK(r, a, b, c, d, e) {\ + k[(8-r)*4 + 4] = a; \ + k[(8-r)*4 + 5] = b; \ + k[(8-r)*4 + 6] = c; \ + k[(8-r)*4 + 7] = d;} + +void Serpent_KeySchedule(word32 *k, unsigned int rounds, const byte *userKey, size_t keylen); + +NAMESPACE_END diff --git a/include/cryptlib/sha.h b/include/cryptlib/sha.h new file mode 100644 index 0000000..615c34c --- /dev/null +++ b/include/cryptlib/sha.h @@ -0,0 +1,196 @@ +// sha.h - originally written and placed in the public domain by Wei Dai + +/// \file sha.h +/// \brief Classes for SHA-1 and SHA-2 family of message digests +/// \since SHA1 since Crypto++ 1.0, SHA2 since Crypto++ 4.0, ARMv8 SHA since +/// Crypto++ 6.0, Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 + +#ifndef CRYPTOPP_SHA_H +#define CRYPTOPP_SHA_H + +#include "config.h" +#include "iterhash.h" + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32) +# define SHA_X86_ALIGN16 true +#else +# define SHA_X86_ALIGN16 false +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHA-1 message digest +/// \sa SHA-1 +/// \since SHA1 since Crypto++ 1.0, SHA2 since Crypto++ 4.0, ARMv8 SHA since +/// Crypto++ 6.0, Intel SHA since Crypto++ 6.0 +class CRYPTOPP_DLL SHA1 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA1 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \returns C-style string "SHA-1" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-1";} + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-256 message digest +/// \sa SHA-256 +/// \since SHA2 since Crypto++ 4.0, ARMv8 SHA since Crypto++ 6.0, +/// Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA256 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA256 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \returns C-style string "SHA-256" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-256";} + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-224 message digest +/// \sa SHA-224 +/// \since SHA2 since Crypto++ 4.0, ARMv8 SHA since Crypto++ 6.0, +/// Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA224 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA224 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data) {SHA256::Transform(digest, data);} + /// \brief The algorithm name + /// \returns C-style string "SHA-224" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-224";} + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-512 message digest +/// \sa SHA-512 +/// \since SHA2 since Crypto++ 4.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA512 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA512 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \returns C-style string "SHA-512" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-512";} +}; + +/// \brief SHA-384 message digest +/// \sa SHA-384 +/// \since SHA2 since Crypto++ 4.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA384 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA384 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data) {SHA512::Transform(digest, data);} + /// \brief The algorithm name + /// \returns C-style string "SHA-384" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-384";} +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/sha3.h b/include/cryptlib/sha3.h new file mode 100644 index 0000000..caf72eb --- /dev/null +++ b/include/cryptlib/sha3.h @@ -0,0 +1,104 @@ +// sha3.h - originally written and placed in the public domain by Wei Dai + +/// \file sha3.h +/// \brief Classes for SHA3 message digests +/// \details The Crypto++ implementation conforms to the FIPS 202 version of SHA3 using F1600 with XOF d=0x06. +/// Previous behavior (XOF d=0x01) is available in Keccak classes. +/// \sa SHA-3, +/// SHA-3 STANDARD (FIPS 202). +/// \since Crypto++ 5.6.2 + +#ifndef CRYPTOPP_SHA3_H +#define CRYPTOPP_SHA3_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHA3 message digest base class +/// \details The Crypto++ implementation conforms to FIPS 202 version of SHA3 using F1600 with XOF d=0x06. +/// Previous behavior (XOF d=0x01) is available in Keccak classes. +/// \details SHA3 is the base class for SHA3_224, SHA3_256, SHA3_384 and SHA3_512. +/// Library users should instantiate a derived class, and only use SHA3 +/// as a base class reference or pointer. +/// \sa Keccak, SHA3_224, SHA3_256, SHA3_384 and SHA3_512. +/// \since Crypto++ 5.6.2 +class SHA3 : public HashTransformation +{ +public: + /// \brief Construct a SHA3 + /// \param digestSize the digest size, in bytes + /// \details SHA3 is the base class for SHA3_224, SHA3_256, SHA3_384 and SHA3_512. + /// Library users should instantiate a derived class, and only use SHA3 + /// as a base class reference or pointer. + SHA3(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + unsigned int DigestSize() const {return m_digestSize;} + std::string AlgorithmName() const {return "SHA3-" + IntToString(m_digestSize*8);} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "SHA3"; } + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + + // unsigned int BlockSize() const { return r(); } // that's the idea behind it +protected: + inline unsigned int r() const {return 200 - 2 * m_digestSize;} + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief SHA3 message digest template +/// \tparam T_DigestSize the size of the digest, in bytes +/// \since Crypto++ 5.6.2 +template +class SHA3_Final : public SHA3 +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize) + CRYPTOPP_CONSTANT(BLOCKSIZE = 200 - 2 * DIGESTSIZE) + + /// \brief Construct a SHA3-X message digest + SHA3_Final() : SHA3(DIGESTSIZE) {} + static std::string StaticAlgorithmName() { return "SHA3-" + IntToString(DIGESTSIZE * 8); } + unsigned int BlockSize() const { return BLOCKSIZE; } +private: +#if !defined(__BORLANDC__) + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE > (int)T_DigestSize); // this is a general expectation by HMAC +#endif +}; + +/// \brief SHA3-224 message digest +/// \since Crypto++ 5.6.2 +// typedef SHA3_Final<28> SHA3_224; +class SHA3_224 : public SHA3_Final<28> +{ +}; + +/// \brief SHA3-256 message digest +/// \since Crypto++ 5.6.2 +// typedef SHA3_Final<32> SHA3_256; +class SHA3_256 : public SHA3_Final<32> +{ +}; + +/// \brief SHA3-384 message digest +/// \since Crypto++ 5.6.2 +// typedef SHA3_Final<48> SHA3_384; +class SHA3_384 : public SHA3_Final<48> +{ +}; + +/// \brief SHA3-512 message digest +/// \since Crypto++ 5.6.2 +// typedef SHA3_Final<64> SHA3_512; +class SHA3_512 : public SHA3_Final<64> +{ +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/shacal2.h b/include/cryptlib/shacal2.h new file mode 100644 index 0000000..3417d72 --- /dev/null +++ b/include/cryptlib/shacal2.h @@ -0,0 +1,65 @@ +// shacal.h - originally written and placed in the public domain by Wei Dai + +/// \file shacal2.h +/// \brief Classes for the SHACAL-2 block cipher +/// \since Crypto++ 5.2, Intel SHA since Crypto++ 6.0 + +#ifndef CRYPTOPP_SHACAL2_H +#define CRYPTOPP_SHACAL2_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHACAL2 block cipher information +struct SHACAL2_Info : public FixedBlockSize<32>, public VariableKeyLength<16, 16, 64> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SHACAL-2";} +}; + +/// \brief SHACAL2 block cipher +/// \since Crypto++ 5.2, Intel SHA since Crypto++ 6.0 +/// \sa SHACAL-2 +class SHACAL2 : public SHACAL2_Info, public BlockCipherDocumentation +{ + /// \brief SHACAL2 block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeAlignedSecBlock m_key; + + static const word32 K[64]; + }; + + /// \brief SHACAL2 block cipher transformation functions + /// \details Provides implementation for encryption transformation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SHACAL2 block cipher transformation functions + /// \details Provides implementation for decryption transformation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SHACAL2::Encryption SHACAL2Encryption; +typedef SHACAL2::Decryption SHACAL2Decryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/shark.h b/include/cryptlib/shark.h new file mode 100644 index 0000000..8c73d26 --- /dev/null +++ b/include/cryptlib/shark.h @@ -0,0 +1,77 @@ +// shark.h - originally written and placed in the public domain by Wei Dai + +/// \file shark.h +/// \brief Classes for the SHARK block cipher +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_SHARK_H +#define CRYPTOPP_SHARK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHARK block cipher information +/// \since Crypto++ 2.1 +struct SHARK_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<6, 2> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SHARK-E";} +}; + +/// \brief SHARK block cipher +/// SHARK-E +/// \since Crypto++ 2.1 +class SHARK : public SHARK_Info, public BlockCipherDocumentation +{ + /// \brief SHARK block cipher default operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶m); + + protected: + unsigned int m_rounds; + SecBlock m_roundKeys; + }; + + /// \brief SHARK block cipher encryption operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + // used by Base to do key setup + void InitForKeySetup(); + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + + /// \brief SHARK block cipher decryption operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SHARK::Encryption SHARKEncryption; +typedef SHARK::Decryption SHARKDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/simon.h b/include/cryptlib/simon.h new file mode 100644 index 0000000..0dab94c --- /dev/null +++ b/include/cryptlib/simon.h @@ -0,0 +1,180 @@ +// simon.h - written and placed in the public domain by Jeffrey Walton + +/// \file simon.h +/// \brief Classes for the Simon block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \sa The SIMON and SPECK Families of +/// Lightweight Block Ciphers, +/// The Simon and Speck GitHub and +/// SIMON on the Crypto++ wiki. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SIMON_H +#define CRYPTOPP_SIMON_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 +# define CRYPTOPP_SIMON64_ADVANCED_PROCESS_BLOCKS 1 +#endif + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 +# define CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SIMON block cipher information +/// \tparam L block size of the cipher, in bytes +/// \tparam D default key length, in bytes +/// \tparam N minimum key length, in bytes +/// \tparam M maximum key length, in bytes +/// \since Crypto++ 6.0 +template +struct SIMON_Info : public FixedBlockSize, VariableKeyLength +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "SIMON-" + IntToString(L*8); + } +}; + +/// \brief SIMON block cipher base class +/// \tparam W the word type +/// \details User code should use SIMON64 or SIMON128 +/// \sa SIMON64, SIMON128, SIMON on the Crypto++ wiki +/// \since Crypto++ 6.0 +template +struct SIMON_Base +{ + virtual ~SIMON_Base() {} +SIMON_Base() : m_kwords(0), m_rounds(0) {} + + typedef SecBlock > AlignedSecBlock; + mutable AlignedSecBlock m_wspace; // workspace + AlignedSecBlock m_rkeys; // round keys + unsigned int m_kwords; // number of key words + unsigned int m_rounds; // number of rounds +}; + +/// \brief SIMON 64-bit block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SIMON64 provides 64-bit block size. The valid key sizes are 96-bit and 128-bit. +/// \sa SIMON64, SIMON128, The SIMON and SIMON +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SIMON on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SIMON64 : public SIMON_Info<8, 12, 12, 16>, public BlockCipherDocumentation +{ +public: + /// \brief SIMON block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SIMON_Base, public BlockCipherImpl > + { + public: + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word32)*8) + ")"); + } + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON64_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON64_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief SIMON 128-bit block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SIMON128 provides 128-bit block size. The valid key sizes are 128-bit, 192-bit and 256-bit. +/// \sa SIMON64, SIMON128, The SIMON and SIMON +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SIMON on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SIMON128 : public SIMON_Info<16, 16, 16, 32>, public BlockCipherDocumentation +{ +public: + /// \brief SIMON block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SIMON_Base, public BlockCipherImpl > + { + public: + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word64)*8) + ")"); + } + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SIMON_H diff --git a/include/cryptlib/simple.h b/include/cryptlib/simple.h new file mode 100644 index 0000000..3ade488 --- /dev/null +++ b/include/cryptlib/simple.h @@ -0,0 +1,365 @@ +// simple.h - originally written and placed in the public domain by Wei Dai + +/// \file simple.h +/// \brief Classes providing basic library services. + +#ifndef CRYPTOPP_SIMPLE_H +#define CRYPTOPP_SIMPLE_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189) +#endif + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base class for identifying alogorithm +/// \tparam BASE base class from which to derive +/// \tparam DERIVED class which to clone +template +class CRYPTOPP_NO_VTABLE ClonableImpl : public BASE +{ +public: + Clonable * Clone() const {return new DERIVED(*static_cast(this));} +}; + +/// \brief Base class information +/// \tparam BASE an Algorithm derived class +/// \tparam ALGORITHM_INFO an Algorithm derived class +/// \details AlgorithmImpl provides StaticAlgorithmName from the template parameter BASE +template +class CRYPTOPP_NO_VTABLE AlgorithmImpl : public BASE +{ +public: + /// \brief The algorithm name + /// \returns the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static member function. + /// The name is taken from information provided by BASE. + static std::string CRYPTOPP_API StaticAlgorithmName() {return ALGORITHM_INFO::StaticAlgorithmName();} + /// \brief The algorithm name + /// \returns the algorithm name + /// \details AlgorithmName returns the algorithm's name as a member function. + /// The name is is acquired by calling StaticAlgorithmName. + std::string AlgorithmName() const {return ALGORITHM_INFO::StaticAlgorithmName();} +}; + +/// \brief Exception thrown when an invalid key length is encountered +class CRYPTOPP_DLL InvalidKeyLength : public InvalidArgument +{ +public: + explicit InvalidKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid key length") {} +}; + +/// \brief Exception thrown when an invalid number of rounds is encountered +class CRYPTOPP_DLL InvalidRounds : public InvalidArgument +{ +public: + explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {} +}; + +/// \brief Exception thrown when an invalid block size is encountered +class CRYPTOPP_DLL InvalidBlockSize : public InvalidArgument +{ +public: + explicit InvalidBlockSize(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid block size") {} +}; + +/// \brief Exception thrown when an invalid derived key length is encountered +class CRYPTOPP_DLL InvalidDerivedLength : public InvalidArgument +{ +public: + explicit InvalidDerivedLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid derived key length") {} +}; + +/// \brief Exception thrown when an invalid personalization string length is encountered +class CRYPTOPP_DLL InvalidPersonalizationLength : public InvalidArgument +{ +public: + explicit InvalidPersonalizationLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {} +}; + +/// \brief Exception thrown when an invalid salt length is encountered +class CRYPTOPP_DLL InvalidSaltLength : public InvalidArgument +{ +public: + explicit InvalidSaltLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {} +}; + +// ***************************** + +/// \brief Base class for bufferless filters +/// \tparam T the class or type +template +class CRYPTOPP_NO_VTABLE Bufferless : public T +{ +public: + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;} +}; + +/// \brief Base class for unflushable filters +/// \tparam T the class or type +template +class CRYPTOPP_NO_VTABLE Unflushable : public T +{ +public: + bool Flush(bool completeFlush, int propagation=-1, bool blocking=true) + {return ChannelFlush(DEFAULT_CHANNEL, completeFlush, propagation, blocking);} + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;} + bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) + { + if (hardFlush && !InputBufferIsEmpty()) + throw CannotFlush("Unflushable: this object has buffered input that cannot be flushed"); + else + { + BufferedTransformation *attached = this->AttachedTransformation(); + return attached && propagation ? attached->ChannelFlush(channel, hardFlush, propagation-1, blocking) : false; + } + } + +protected: + virtual bool InputBufferIsEmpty() const {return false;} +}; + +/// \brief Base class for input rejecting filters +/// \tparam T the class or type +/// \details T should be a BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE InputRejecting : public T +{ +public: + struct InputRejected : public NotImplemented + {InputRejected() : NotImplemented("BufferedTransformation: this object doesn't allow input") {}}; + + /// \name INPUT + //@{ + + /// \brief Input a byte array for processing + /// \param inString the byte array to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \throws InputRejected + /// \returns the number of bytes that remain in the block (i.e., bytes not processed) + /// \details Internally, the default implementation throws InputRejected. + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + //@} + + /// \name SIGNALS + //@{ + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;} + bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); throw InputRejected();} + size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + bool ChannelMessageSeriesEnd(const std::string& channel, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + //@} +}; + +/// \brief Interface for custom flush signals propagation +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE CustomFlushPropagation : public T +{ +public: + /// \name SIGNALS + //@{ + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) =0; + + //@} + +private: + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;} +}; + +/// \brief Interface for custom flush signals +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE CustomSignalPropagation : public CustomFlushPropagation +{ +public: + /// \brief Initialize or reinitialize this object, with signal propagation + /// \param parameters a set of NameValuePairs to initialize or reinitialize this object + /// \param propagation the number of attached transformations the Initialize() signal should be passed + /// \details Initialize() is used to initialize or reinitialize an object using a variable number of + /// arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) =0; + +private: + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} +}; + +/// \brief Multiple channels support for custom signal processing +/// \tparam T the class or type +/// \details T should be a BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE Multichannel : public CustomFlushPropagation +{ +public: + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return this->ChannelFlush(DEFAULT_CHANNEL, hardFlush, propagation, blocking);} + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return this->ChannelMessageSeriesEnd(DEFAULT_CHANNEL, propagation, blocking);} + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of + /// an ArraySink, the pointer to the array is returned and the size is remaining size. + byte * CreatePutSpace(size_t &size) + {return this->ChannelCreatePutSpace(DEFAULT_CHANNEL, size);} + + /// \brief Input multiple bytes for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \details Derived classes must implement Put2(). + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return this->ChannelPut2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);} + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \details Internally, PutModifiable2() calls Put2(). + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + {return this->ChannelPutModifiable2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);} + +// void ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1) +// {PropagateMessageSeriesEnd(propagation, channel);} + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + {CRYPTOPP_UNUSED(channel); size = 0; return NULLPTR;} + bool ChannelPutModifiable(const std::string &channel, byte *inString, size_t length) + {this->ChannelPut(channel, inString, length); return false;} + + virtual size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) =0; + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return ChannelPut2(channel, begin, length, messageEnd, blocking);} + + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) =0; +}; + +/// \brief Provides auto signaling support +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE AutoSignaling : public T +{ +public: + /// \brief Construct an AutoSignaling + /// \param propagation the propagation count + AutoSignaling(int propagation=-1) : m_autoSignalPropagation(propagation) {} + + void SetAutoSignalPropagation(int propagation) + {m_autoSignalPropagation = propagation;} + int GetAutoSignalPropagation() const + {return m_autoSignalPropagation;} + +private: + int m_autoSignalPropagation; +}; + +/// \brief Acts as a Source for pre-existing, static data +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Store : public AutoSignaling > +{ +public: + /// \brief Construct a Store + Store() : m_messageEnd(false) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) + { + m_messageEnd = false; + StoreInitialize(parameters); + } + + unsigned int NumberOfMessages() const {return m_messageEnd ? 0 : 1;} + bool GetNextMessage(); + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + +protected: + virtual void StoreInitialize(const NameValuePairs ¶meters) =0; + + bool m_messageEnd; +}; + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Sink is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details A Sink doesnot produce any retrievable output. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Sink : public BufferedTransformation +{ +public: + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) + {CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(transferBytes); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); transferBytes = 0; return 0;} + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const + {CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); return 0;} +}; + +/// \brief Acts as an input discarding Filter or Sink +/// \details The BitBucket discards all input and returns 0 to the caller +/// to indicate all data was processed. +class CRYPTOPP_DLL BitBucket : public Bufferless +{ +public: + std::string AlgorithmName() const {return "BitBucket";} + void IsolatedInitialize(const NameValuePairs ¶ms) + {CRYPTOPP_UNUSED(params);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); return 0;} +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/siphash.h b/include/cryptlib/siphash.h new file mode 100644 index 0000000..8d3a09e --- /dev/null +++ b/include/cryptlib/siphash.h @@ -0,0 +1,312 @@ +// siphash.h - written and placed in public domain by Jeffrey Walton. + +/// \file siphash.h +/// \brief Classes for SipHash message authentication code +/// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length +/// message and 128-bit secret key. It was designed to be efficient even for short inputs, with +/// performance comparable to non-cryptographic hash functions. +/// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,false> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,true> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: +/// a fast short-input PRF +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SIPHASH_H +#define CRYPTOPP_SIPHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SipHash message authentication code information +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +template +class SipHash_Info : public FixedKeyLength<16> +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SipHash";} + CRYPTOPP_CONSTANT(DIGESTSIZE = (T_128bit ? 16 : 8)) +}; + +/// \brief SipHash message authentication code base class +/// \tparam C the number of compression rounds +/// \tparam D the number of finalization rounds +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +template +class SipHash_Base : public MessageAuthenticationCode, public SipHash_Info +{ +public: + static std::string StaticAlgorithmName() { + return std::string(SipHash_Info::StaticAlgorithmName())+"-"+IntToString(C)+"-"+IntToString(D); + } + + virtual ~SipHash_Base() {} + + SipHash_Base() : m_idx(0) {} + + virtual unsigned int DigestSize() const + {return SipHash_Info::DIGESTSIZE;} + virtual size_t MinKeyLength() const + {return SipHash_Info::MIN_KEYLENGTH;} + virtual size_t MaxKeyLength() const + {return SipHash_Info::MAX_KEYLENGTH;} + virtual size_t DefaultKeyLength() const + {return SipHash_Info::DEFAULT_KEYLENGTH;} + virtual size_t GetValidKeyLength(size_t keylength) const + {CRYPTOPP_UNUSED(keylength); return SipHash_Info::DEFAULT_KEYLENGTH;} + virtual IV_Requirement IVRequirement() const + {return SimpleKeyingInterface::NOT_RESYNCHRONIZABLE;} + virtual unsigned int IVSize() const + {return 0;} + virtual unsigned int OptimalBlockSize() const + {return sizeof(word64);} + virtual unsigned int OptimalDataAlignment () const + {return GetAlignmentOf();} + + virtual void Update(const byte *input, size_t length); + virtual void TruncatedFinal(byte *digest, size_t digestSize); + +protected: + + virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + virtual void Restart(); + + inline void SIPROUND() + { + m_v[0] += m_v[1]; + m_v[1] = rotlConstant<13>(m_v[1]); + m_v[1] ^= m_v[0]; + m_v[0] = rotlConstant<32>(m_v[0]); + m_v[2] += m_v[3]; + m_v[3] = rotlConstant<16>(m_v[3]); + m_v[3] ^= m_v[2]; + m_v[0] += m_v[3]; + m_v[3] = rotlConstant<21>(m_v[3]); + m_v[3] ^= m_v[0]; + m_v[2] += m_v[1]; + m_v[1] = rotlConstant<17>(m_v[1]); + m_v[1] ^= m_v[2]; + m_v[2] = rotlConstant<32>(m_v[2]); + } + +private: + FixedSizeSecBlock m_v; + FixedSizeSecBlock m_k; + FixedSizeSecBlock m_b; + + // Tail bytes + FixedSizeSecBlock m_acc; + size_t m_idx; +}; + +/// \brief SipHash message authentication code +/// \tparam C the number of compression rounds +/// \tparam D the number of finalization rounds +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +/// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length +/// message and 128-bit secret key. It was designed to be efficient even for short inputs, with +/// performance comparable to non-cryptographic hash functions. +/// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,false> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,true> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: +/// a fast short-input PRF +/// \since Crypto++ 6.0 +template +class SipHash : public SipHash_Base +{ +public: + /// \brief Create a SipHash + SipHash() + {this->UncheckedSetKey(NULLPTR, 0, g_nullNameValuePairs);} + /// \brief Create a SipHash + /// \param key a byte array used to key the cipher + /// \param length the size of the byte array, in bytes + SipHash(const byte *key, unsigned int length) + {this->UncheckedSetKey(key, length, g_nullNameValuePairs);} +}; + +template +void SipHash_Base::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT((input && length) || !length); + if (!length) return; + + if (m_idx) + { + size_t head = STDMIN(size_t(8U-m_idx), length); + memcpy(m_acc+m_idx, input, head); + m_idx += head; input += head; length -= head; + + if (m_idx == 8) + { + word64 m = GetWord(true, LITTLE_ENDIAN_ORDER, m_acc); + m_v[3] ^= m; + for (unsigned int i = 0; i < C; ++i) + SIPROUND(); + + m_v[0] ^= m; + m_b[0] += 8; + + m_idx = 0; + } + } + + while (length >= 8) + { + word64 m = GetWord(false, LITTLE_ENDIAN_ORDER, input); + m_v[3] ^= m; + for (unsigned int i = 0; i < C; ++i) + SIPROUND(); + + m_v[0] ^= m; + m_b[0] += 8; + + input += 8; + length -= 8; + } + + CRYPTOPP_ASSERT(length < 8); + size_t tail = length % 8; + if (tail) + { + memcpy(m_acc+m_idx, input, tail); + m_idx += tail; + } +} + +template +void SipHash_Base::TruncatedFinal(byte *digest, size_t digestSize) +{ + CRYPTOPP_ASSERT(digest); // Pointer is valid + + ThrowIfInvalidTruncatedSize(digestSize); + + // The high octet holds length and is digested mod 256 + m_b[0] += m_idx; m_b[0] <<= 56U; + switch (m_idx) + { + case 7: + m_b[0] |= ((word64)m_acc[6]) << 48; + // fall through + case 6: + m_b[0] |= ((word64)m_acc[5]) << 40; + // fall through + case 5: + m_b[0] |= ((word64)m_acc[4]) << 32; + // fall through + case 4: + m_b[0] |= ((word64)m_acc[3]) << 24; + // fall through + case 3: + m_b[0] |= ((word64)m_acc[2]) << 16; + // fall through + case 2: + m_b[0] |= ((word64)m_acc[1]) << 8; + // fall through + case 1: + m_b[0] |= ((word64)m_acc[0]); + // fall through + case 0: + break; + } + + m_v[3] ^= m_b[0]; + + for (unsigned int i=0; i::DIGESTSIZE)); + Restart(); +} + +template +void SipHash_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + if (key && length) + { + m_k[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key); + m_k[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key+8); + } + else + { + // Avoid Coverity finding + m_k[0] = m_k[1] = 0; + } + Restart(); +} + +template +void SipHash_Base::Restart () +{ + m_v[0] = W64LIT(0x736f6d6570736575); + m_v[1] = W64LIT(0x646f72616e646f6d); + m_v[2] = W64LIT(0x6c7967656e657261); + m_v[3] = W64LIT(0x7465646279746573); + + m_v[3] ^= m_k[1]; + m_v[2] ^= m_k[0]; + m_v[1] ^= m_k[1]; + m_v[0] ^= m_k[0]; + + if (T_128bit) + { + m_v[1] ^= 0xee; + } + + m_idx = 0; + m_b[0] = 0; +} + +NAMESPACE_END + +#endif // CRYPTOPP_SIPHASH_H diff --git a/include/cryptlib/skipjack.h b/include/cryptlib/skipjack.h new file mode 100644 index 0000000..a92ef35 --- /dev/null +++ b/include/cryptlib/skipjack.h @@ -0,0 +1,67 @@ +// skipjack.h - originally written and placed in the public domain by Wei Dai + +/// \file skipjack.h +/// \brief Classes for the SKIPJACK block cipher + +#ifndef CRYPTOPP_SKIPJACK_H +#define CRYPTOPP_SKIPJACK_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SKIPJACK block cipher information +struct SKIPJACK_Info : public FixedBlockSize<8>, public FixedKeyLength<10> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "SKIPJACK";} +}; + +/// \brief SKIPJACK block cipher +/// \sa SKIPJACK +class SKIPJACK : public SKIPJACK_Info, public BlockCipherDocumentation +{ + /// \brief SKIPJACK block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + protected: + static const byte fTable[256]; + + FixedSizeSecBlock tab; + }; + + /// \brief SKIPJACK block cipher encryption operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + /// \brief SKIPJACK block cipher decryption operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SKIPJACK::Encryption SKIPJACKEncryption; +typedef SKIPJACK::Decryption SKIPJACKDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/sm3.h b/include/cryptlib/sm3.h new file mode 100644 index 0000000..3e50d91 --- /dev/null +++ b/include/cryptlib/sm3.h @@ -0,0 +1,61 @@ +// sm3.h - written and placed in the public domain by Jeffrey Walton and Han Lulu +// Based on the specification provided by Sean Shen and Xiaodong Lee. +// Based on code by Krzysztof Kwiatkowski and Jack Lloyd. +// Also see https://tools.ietf.org/html/draft-shen-sm3-hash. + +/// \file sm3.h +/// \brief Classes for the SM3 hash function +/// \details SM3 is a hash function designed by Xiaoyun Wang, et al. The hash is part of the +/// Chinese State Cryptography Administration portfolio. +/// \sa SM3 Hash Function and +/// Reference implementation using OpenSSL. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SM3_H +#define CRYPTOPP_SM3_H + +#include "config.h" +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SM3 hash function +/// \details SM3 is a hash function designed by Xiaoyun Wang, et al. The hash is part of the +/// Chinese State Cryptography Administration portfolio. +/// \sa SM3 Hash Function +/// \since Crypto++ 6.0 +class SM3 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA256 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState() and Transform(). External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + static void InitState(HashWordType *state); + + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform() operates the hash on data. When the call is invoked + /// digest holds initial or current state. Upon return digest holds + /// the hash or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState() and Transform(). External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + static void Transform(HashWordType *digest, const HashWordType *data); + + /// \brief The algorithm name + /// \returns C-style string "SM3" + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "SM3"; } + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SM3_H diff --git a/include/cryptlib/sm4.h b/include/cryptlib/sm4.h new file mode 100644 index 0000000..6774ca1 --- /dev/null +++ b/include/cryptlib/sm4.h @@ -0,0 +1,76 @@ +// sm4.h - written and placed in the public domain by Jeffrey Walton and Han Lulu + +/// \file sm4.h +/// \brief Classes for the SM4 block cipher +/// \details SM4 is a block cipher designed by Xiaoyun Wang, et al. The block cipher is part of the +/// Chinese State Cryptography Administration portfolio. The cipher was formely known as SMS4. +/// \sa SMS4 Encryption Algorithm for Wireless Networks and +/// Reference implementation using OpenSSL. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SM4_H +#define CRYPTOPP_SM4_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SM4 block cipher information +/// \since Crypto++ 6.0 +struct SM4_Info : public FixedBlockSize<16>, FixedKeyLength<16> +{ + static const std::string StaticAlgorithmName() + { + return "SM4"; + } +}; + +/// \brief Classes for the SM4 block cipher +/// \details SM4 is a block cipher designed by Xiaoyun Wang, et al. The block cipher is part of the +/// Chinese State Cryptography Administration portfolio. The cipher was formely known as SMS4. +/// \sa SMS4 Encryption Algorithm for Wireless Networks +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SM4 : public SM4_Info, public BlockCipherDocumentation +{ +public: + /// \brief SM4 block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + protected: + SecBlock > m_rkeys; + mutable SecBlock > m_wspace; + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SM4_H diff --git a/include/cryptlib/smartptr.h b/include/cryptlib/smartptr.h new file mode 100644 index 0000000..f1b735c --- /dev/null +++ b/include/cryptlib/smartptr.h @@ -0,0 +1,256 @@ +// smartptr.h - originally written and placed in the public domain by Wei Dai + +/// \file smartptr.h +/// \brief Classes for automatic resource management + +#ifndef CRYPTOPP_SMARTPTR_H +#define CRYPTOPP_SMARTPTR_H + +#include "config.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Manages resources for a single object +/// \tparam T class or type +/// \details \p simple_ptr is used frequently in the library to manage resources and +/// ensure cleanup under the RAII pattern (Resource Acquisition Is Initialization). +template class simple_ptr +{ +public: + simple_ptr(T *p = NULLPTR) : m_p(p) {} + ~simple_ptr() + { + delete m_p; + m_p = NULLPTR; + } + + T *m_p; +}; + +/// \brief Pointer that overloads operator -> +/// \tparam T class or type +/// \details member_ptr is used frequently in the library to avoid the issues related to +/// std::auto_ptr in C++11 (deprecated) and std::unique_ptr in C++03 (non-existent). +/// \bug Issue 48: "Use of auto_ptr causes dirty compile under C++11" +template class member_ptr +{ +public: + explicit member_ptr(T *p = NULLPTR) : m_p(p) {} + + ~member_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return m_p; } + + const T* get() const { return m_p; } + T* get() { return m_p; } + + T* release() + { + T *old_p = m_p; + m_p = NULLPTR; + return old_p; + } + + void reset(T *p = 0); + +protected: + member_ptr(const member_ptr& rhs); // copy not allowed + void operator=(const member_ptr& rhs); // assignment not allowed + + T *m_p; +}; + +template member_ptr::~member_ptr() {delete m_p;} +template void member_ptr::reset(T *p) {delete m_p; m_p = p;} + +// ******************************************************** + +/// \brief Value pointer +/// \tparam T class or type +template class value_ptr : public member_ptr +{ +public: + value_ptr(const T &obj) : member_ptr(new T(obj)) {} + value_ptr(T *p = NULLPTR) : member_ptr(p) {} + value_ptr(const value_ptr& rhs) + : member_ptr(rhs.m_p ? new T(*rhs.m_p) : NULLPTR) {} + + value_ptr& operator=(const value_ptr& rhs); + bool operator==(const value_ptr& rhs) + { + return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p); + } +}; + +template value_ptr& value_ptr::operator=(const value_ptr& rhs) +{ + T *old_p = this->m_p; + this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULLPTR; + delete old_p; + return *this; +} + +// ******************************************************** + +/// \brief A pointer which can be copied and cloned +/// \tparam T class or type +/// \details \p T should adhere to the \p Clonable interface +template class clonable_ptr : public member_ptr +{ +public: + clonable_ptr(const T &obj) : member_ptr(obj.Clone()) {} + clonable_ptr(T *p = NULLPTR) : member_ptr(p) {} + clonable_ptr(const clonable_ptr& rhs) + : member_ptr(rhs.m_p ? rhs.m_p->Clone() : NULLPTR) {} + + clonable_ptr& operator=(const clonable_ptr& rhs); +}; + +template clonable_ptr& clonable_ptr::operator=(const clonable_ptr& rhs) +{ + T *old_p = this->m_p; + this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULLPTR; + delete old_p; + return *this; +} + +// ******************************************************** + +/// \brief Reference counted pointer +/// \tparam T class or type +/// \details users should declare \p m_referenceCount as std::atomic +/// (or similar) under C++ 11 +template class counted_ptr +{ +public: + explicit counted_ptr(T *p = 0); + counted_ptr(const T &r) : m_p(0) {attach(r);} + counted_ptr(const counted_ptr& rhs); + + ~counted_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return get(); } + + const T* get() const { return m_p; } + T* get(); + + void attach(const T &p); + + counted_ptr & operator=(const counted_ptr& rhs); + +private: + T *m_p; +}; + +template counted_ptr::counted_ptr(T *p) + : m_p(p) +{ + if (m_p) + m_p->m_referenceCount = 1; +} + +template counted_ptr::counted_ptr(const counted_ptr& rhs) + : m_p(rhs.m_p) +{ + if (m_p) + m_p->m_referenceCount++; +} + +template counted_ptr::~counted_ptr() +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; +} + +template void counted_ptr::attach(const T &r) +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + if (r.m_referenceCount == 0) + { + m_p = r.clone(); + m_p->m_referenceCount = 1; + } + else + { + m_p = const_cast(&r); + m_p->m_referenceCount++; + } +} + +template T* counted_ptr::get() +{ + if (m_p && m_p->m_referenceCount > 1) + { + T *temp = m_p->clone(); + m_p->m_referenceCount--; + m_p = temp; + m_p->m_referenceCount = 1; + } + return m_p; +} + +template counted_ptr & counted_ptr::operator=(const counted_ptr& rhs) +{ + if (m_p != rhs.m_p) + { + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + m_p = rhs.m_p; + if (m_p) + m_p->m_referenceCount++; + } + return *this; +} + +// ******************************************************** + +/// \brief Manages resources for an array of objects +/// \tparam T class or type +template class vector_member_ptrs +{ +public: + /// Construct an arry of \p T + /// \param size the size of the array, in elements + /// \details If \p T is a Plain Old Dataype (POD), then the array is uninitialized. + vector_member_ptrs(size_t size=0) + : m_size(size), m_ptr(new member_ptr[size]) {} + ~vector_member_ptrs() + {delete [] this->m_ptr;} + + member_ptr& operator[](size_t index) + {CRYPTOPP_ASSERT(indexm_size); return this->m_ptr[index];} + const member_ptr& operator[](size_t index) const + {CRYPTOPP_ASSERT(indexm_size); return this->m_ptr[index];} + + size_t size() const {return this->m_size;} + void resize(size_t newSize) + { + member_ptr *newPtr = new member_ptr[newSize]; + for (size_t i=0; im_size && im_ptr[i].release()); + delete [] this->m_ptr; + this->m_size = newSize; + this->m_ptr = newPtr; + } + +private: + vector_member_ptrs(const vector_member_ptrs &c); // copy not allowed + void operator=(const vector_member_ptrs &x); // assignment not allowed + + size_t m_size; + member_ptr *m_ptr; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/socketft.h b/include/cryptlib/socketft.h new file mode 100644 index 0000000..e02f6b7 --- /dev/null +++ b/include/cryptlib/socketft.h @@ -0,0 +1,227 @@ +#ifndef CRYPTOPP_SOCKETFT_H +#define CRYPTOPP_SOCKETFT_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(SOCKETS_AVAILABLE) + +#include "cryptlib.h" +#include "network.h" +#include "queue.h" + +#ifdef USE_WINDOWS_STYLE_SOCKETS +# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# error Winsock 1 is not supported by this library. Please include this file or winsock2.h before windows.h. +# endif +#include +#include +#include "winpipes.h" +#else +#include +#include +#include +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef USE_WINDOWS_STYLE_SOCKETS +typedef ::SOCKET socket_t; +#else +typedef int socket_t; +const socket_t INVALID_SOCKET = -1; +// cygwin 1.1.4 doesn't have SHUT_RD +const int SD_RECEIVE = 0; +const int SD_SEND = 1; +const int SD_BOTH = 2; +const int SOCKET_ERROR = -1; +#endif + +#ifndef socklen_t +typedef TYPE_OF_SOCKLEN_T socklen_t; // see config.h +#endif + +/// wrapper for Windows or Berkeley Sockets +class Socket +{ +public: + /// exception thrown by Socket class + class Err : public OS_Error + { + public: + Err(socket_t s, const std::string& operation, int error); + socket_t GetSocket() const {return m_s;} + + private: + socket_t m_s; + }; + + Socket(socket_t s = INVALID_SOCKET, bool own=false) : m_s(s), m_own(own) {} + Socket(const Socket &s) : m_s(s.m_s), m_own(false) {} + virtual ~Socket(); + + bool GetOwnership() const {return m_own;} + void SetOwnership(bool own) {m_own = own;} + + operator socket_t() {return m_s;} + socket_t GetSocket() const {return m_s;} + void AttachSocket(socket_t s, bool own=false); + socket_t DetachSocket(); + void CloseSocket(); + + void Create(int nType = SOCK_STREAM); + void Bind(unsigned int port, const char *addr=NULLPTR); + void Bind(const sockaddr* psa, socklen_t saLen); + void Listen(int backlog = SOMAXCONN); + // the next three functions return false if the socket is in nonblocking mode + // and the operation cannot be completed immediately + bool Connect(const char *addr, unsigned int port); + bool Connect(const sockaddr* psa, socklen_t saLen); + bool Accept(Socket& s, sockaddr *psa=NULLPTR, socklen_t *psaLen=NULLPTR); + void GetSockName(sockaddr *psa, socklen_t *psaLen); + void GetPeerName(sockaddr *psa, socklen_t *psaLen); + unsigned int Send(const byte* buf, size_t bufLen, int flags=0); + unsigned int Receive(byte* buf, size_t bufLen, int flags=0); + void ShutDown(int how = SD_SEND); + + void IOCtl(long cmd, unsigned long *argp); + bool SendReady(const timeval *timeout); + bool ReceiveReady(const timeval *timeout); + + virtual void HandleError(const char *operation) const; + void CheckAndHandleError_int(const char *operation, int result) const + {if (result == SOCKET_ERROR) HandleError(operation);} + void CheckAndHandleError(const char *operation, socket_t result) const + {if (result == static_cast(SOCKET_ERROR)) HandleError(operation);} +#ifdef USE_WINDOWS_STYLE_SOCKETS + void CheckAndHandleError(const char *operation, BOOL result) const + {if (!result) HandleError(operation);} + void CheckAndHandleError(const char *operation, bool result) const + {if (!result) HandleError(operation);} +#endif + + /// look up the port number given its name, returns 0 if not found + static unsigned int PortNameToNumber(const char *name, const char *protocol="tcp"); + /// start Windows Sockets 2 + static void StartSockets(); + /// calls WSACleanup for Windows Sockets + static void ShutdownSockets(); + /// returns errno or WSAGetLastError + static int GetLastError(); + /// sets errno or calls WSASetLastError + static void SetLastError(int errorCode); + +protected: + virtual void SocketChanged() {} + + socket_t m_s; + bool m_own; +}; + +class SocketsInitializer +{ +public: + SocketsInitializer() {Socket::StartSockets();} + ~SocketsInitializer() {try {Socket::ShutdownSockets();} catch (const Exception&) {CRYPTOPP_ASSERT(0);}} +}; + +class SocketReceiver : public NetworkReceiver +{ +public: + SocketReceiver(Socket &s); + +#ifdef USE_BERKELEY_STYLE_SOCKETS + bool MustWaitToReceive() {return true;} +#else + ~SocketReceiver(); + bool MustWaitForResult() {return true;} +#endif + bool Receive(byte* buf, size_t bufLen); + unsigned int GetReceiveResult(); + bool EofReceived() const {return m_eofReceived;} + + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + +private: + Socket &m_s; + +#ifdef USE_WINDOWS_STYLE_SOCKETS + WindowsHandle m_event; + OVERLAPPED m_overlapped; + DWORD m_lastResult; + bool m_resultPending; +#else + unsigned int m_lastResult; +#endif + + bool m_eofReceived; +}; + +class SocketSender : public NetworkSender +{ +public: + SocketSender(Socket &s); + +#ifdef USE_BERKELEY_STYLE_SOCKETS + bool MustWaitToSend() {return true;} +#else + ~SocketSender(); + bool MustWaitForResult() {return true;} + bool MustWaitForEof() { return true; } + bool EofSent(); +#endif + void Send(const byte* buf, size_t bufLen); + unsigned int GetSendResult(); + void SendEof(); + + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + +private: + Socket &m_s; +#ifdef USE_WINDOWS_STYLE_SOCKETS + WindowsHandle m_event; + OVERLAPPED m_overlapped; + DWORD m_lastResult; + bool m_resultPending; +#else + unsigned int m_lastResult; +#endif +}; + +/// socket-based implementation of NetworkSource +class SocketSource : public NetworkSource, public Socket +{ +public: + SocketSource(socket_t s = INVALID_SOCKET, bool pumpAll = false, BufferedTransformation *attachment = NULLPTR) + : NetworkSource(attachment), Socket(s), m_receiver(*this) + { + if (pumpAll) + PumpAll(); + } + +private: + NetworkReceiver & AccessReceiver() {return m_receiver;} + SocketReceiver m_receiver; +}; + +/// socket-based implementation of NetworkSink +class SocketSink : public NetworkSink, public Socket +{ +public: + SocketSink(socket_t s=INVALID_SOCKET, unsigned int maxBufferSize=0, unsigned int autoFlushBound=16*1024) + : NetworkSink(maxBufferSize, autoFlushBound), Socket(s), m_sender(*this) {} + + void SendEof() {ShutDown(SD_SEND);} + +private: + NetworkSender & AccessSender() {return m_sender;} + SocketSender m_sender; +}; + +NAMESPACE_END + +#endif // SOCKETS_AVAILABLE + +#endif // CRYPTOPP_SOCKETFT_H diff --git a/include/cryptlib/sosemanuk.h b/include/cryptlib/sosemanuk.h new file mode 100644 index 0000000..d59a28d --- /dev/null +++ b/include/cryptlib/sosemanuk.h @@ -0,0 +1,61 @@ +// sosemanuk.h - originally written and placed in the public domain by Wei Dai + +/// \file sosemanuk.h +/// \brief Classes for Sosemanuk stream cipher +/// \since Crypto++ 5.5 + +#ifndef CRYPTOPP_SOSEMANUK_H +#define CRYPTOPP_SOSEMANUK_H + +#include "strciphr.h" +#include "secblock.h" + +// Clang due to "Inline assembly operands don't work with .intel_syntax" +// https://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_INTEL_ASM) +# define CRYPTOPP_DISABLE_SOSEMANUK_ASM +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Sosemanuk stream cipher information + /// \since Crypto++ 5.5 +struct SosemanukInfo : public VariableKeyLength<16, 1, 32, 1, SimpleKeyingInterface::UNIQUE_IV, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Sosemanuk";} +}; + +/// \brief Sosemanuk stream cipher implementation +/// \since Crypto++ 5.5 +class SosemanukPolicy : public AdditiveCipherConcretePolicy, public SosemanukInfo +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CipherIsRandomAccess() const {return false;} +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; +#endif + + FixedSizeSecBlock m_key; + FixedSizeAlignedSecBlock m_state; +}; + +/// \brief Sosemanuk stream cipher +/// \details is a stream cipher developed by Come Berbain, Olivier Billet, Anne Canteaut, Nicolas Courtois, +/// Henri Gilbert, Louis Goubin, Aline Gouget, Louis Granboulan, Cédric Lauradoux, Marine Minier, Thomas +/// Pornin and Hervé Sibert. Sosemanuk is one of the final four Profile 1 (software) ciphers selected for +/// the eSTREAM Portfolio. +/// \sa Sosemanuk +/// \since Crypto++ 5.5 +struct Sosemanuk : public SosemanukInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, SosemanukInfo> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/speck.h b/include/cryptlib/speck.h new file mode 100644 index 0000000..9ba53cd --- /dev/null +++ b/include/cryptlib/speck.h @@ -0,0 +1,180 @@ +// speck.h - written and placed in the public domain by Jeffrey Walton + +/// \file speck.h +/// \brief Classes for the Speck block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \sa The SIMON and SPECK Families of +/// Lightweight Block Ciphers, +/// The Simon and Speck GitHub and +/// SPECK on the Crypto++ wiki. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SPECK_H +#define CRYPTOPP_SPECK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 +# define CRYPTOPP_SPECK64_ADVANCED_PROCESS_BLOCKS 1 +#endif + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 +# define CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SPECK block cipher information +/// \tparam L block size of the cipher, in bytes +/// \tparam D default key length, in bytes +/// \tparam N minimum key length, in bytes +/// \tparam M maximum key length, in bytes +/// \since Crypto++ 6.0 +template +struct SPECK_Info : public FixedBlockSize, VariableKeyLength +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "SPECK-" + IntToString(L*8); + } +}; + +/// \brief SPECK block cipher base class +/// \tparam W the word type +/// \details User code should use SPECK64 or SPECK128 +/// \sa SPECK64, SPECK128, SPECK +/// \since Crypto++ 6.0 +template +struct SPECK_Base +{ + virtual ~SPECK_Base() {} + SPECK_Base() : m_kwords(0), m_rounds(0) {} + + typedef SecBlock > AlignedSecBlock; + mutable AlignedSecBlock m_wspace; // workspace + AlignedSecBlock m_rkeys; // round keys + unsigned int m_kwords; // number of key words + unsigned int m_rounds; // number of rounds +}; + +/// \brief SPECK 64-bit block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SPECK64 provides 64-bit block size. The valid key sizes are 96-bit and 128-bit. +/// \sa SPECK64, SPECK128, The SIMON and SPECK +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SPECK on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SPECK64 : public SPECK_Info<8, 12, 12, 16>, public BlockCipherDocumentation +{ +public: + /// \brief SPECK block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SPECK_Base, public BlockCipherImpl > + { + public: + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word32)*8) + ")"); + } + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK64_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK64_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief SPECK 128-bit block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SPECK128 provides 128-bit block size. The valid key sizes are 128-bit, 192-bit and 256-bit. +/// \sa SPECK64, SPECK128, The SIMON and SPECK +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SPECK on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SPECK128 : public SPECK_Info<16, 16, 16, 32>, public BlockCipherDocumentation +{ +public: + /// \brief SPECK block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SPECK_Base, public BlockCipherImpl > + { + public: + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word64)*8) + ")"); + } + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SPECK_H diff --git a/include/cryptlib/square.h b/include/cryptlib/square.h new file mode 100644 index 0000000..e43e796 --- /dev/null +++ b/include/cryptlib/square.h @@ -0,0 +1,63 @@ +// square.h - originally written and placed in the public domain by Wei Dai + +/// \file square.h +/// \brief Classes for the Square block cipher + +#ifndef CRYPTOPP_SQUARE_H +#define CRYPTOPP_SQUARE_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Square block cipher information +/// \since Crypto++ 2.2 +struct Square_Info : public FixedBlockSize<16>, public FixedKeyLength<16>, FixedRounds<8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Square";} +}; + +/// \brief Square block cipher +/// \sa Square +/// \since Crypto++ 2.2 +class Square : public Square_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_roundkeys; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Square::Encryption SquareEncryption; +typedef Square::Decryption SquareDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/stdcpp.h b/include/cryptlib/stdcpp.h new file mode 100644 index 0000000..26bb135 --- /dev/null +++ b/include/cryptlib/stdcpp.h @@ -0,0 +1,76 @@ +// stdcpp.h - originally written and placed in the public domain by Wei Dai + +/// \file stdcpp.h +/// \brief Common C++ header files + +#ifndef CRYPTOPP_STDCPP_H +#define CRYPTOPP_STDCPP_H + +#if _MSC_VER >= 1500 +#define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// http://connect.microsoft.com/VisualStudio/feedback/details/1600701/type-info-does-not-compile-with-has-exceptions-0 +#if defined(_MSC_VER) && (_MSC_VER < 1900) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 0) +namespace std { + using ::type_info; +} +#endif + +// make_unchecked_array_iterator +#if _MSC_VER >= 1600 +#include +#endif + +#if defined(CRYPTOPP_CXX11_ATOMICS) +#include +#endif + +#if defined(CRYPTOPP_CXX11_SYNCHRONIZATION) +#include +#endif + +#if defined(CRYPTOPP_CXX11_RVALUES) +# include +#endif + +#include +#include +#include +#include +#include + +// uintptr_t and ptrdiff_t +#if (__cplusplus < 201103L) && (!defined(_MSC_VER) || (_MSC_VER >= 1700)) +# include +#elif defined(_MSC_VER) && (_MSC_VER < 1700) +# include +#endif + +// workaround needed on Sun Studio 12u1 Sun C++ 5.10 SunOS_i386 128229-02 2009/09/21 +#ifdef CRYPTOPP_INCLUDE_VECTOR_CC +# include +#endif + +// C++Builder's standard library (Dinkumware) do not have C's global log() function +// https://github.com/weidai11/cryptopp/issues/520 +#ifdef __BORLANDC__ +using std::log; +#endif + +#endif diff --git a/include/cryptlib/strciphr.h b/include/cryptlib/strciphr.h new file mode 100644 index 0000000..ea35ed5 --- /dev/null +++ b/include/cryptlib/strciphr.h @@ -0,0 +1,622 @@ +// strciphr.h - originally written and placed in the public domain by Wei Dai + +/// \file strciphr.h +/// \brief Classes for implementing stream ciphers +/// \details This file contains helper classes for implementing stream ciphers. +/// All this infrastructure may look very complex compared to what's in Crypto++ 4.x, +/// but stream ciphers implementations now support a lot of new functionality, +/// including better performance (minimizing copying), resetting of keys and IVs, and methods to +/// query which features are supported by a cipher. +/// \details Here's an explanation of these classes. The word "policy" is used here to mean a class with a +/// set of methods that must be implemented by individual stream cipher implementations. +/// This is usually much simpler than the full stream cipher API, which is implemented by +/// either AdditiveCipherTemplate or CFB_CipherTemplate using the policy. So for example, an +/// implementation of SEAL only needs to implement the AdditiveCipherAbstractPolicy interface +/// (since it's an additive cipher, i.e., it xors a keystream into the plaintext). +/// See this line in seal.h: +///
+///     typedef SymmetricCipherFinal\, AdditiveCipherTemplate\<\> \> \> Encryption;
+/// 
+/// \details AdditiveCipherTemplate and CFB_CipherTemplate are designed so that they don't need +/// to take a policy class as a template parameter (although this is allowed), so that +/// their code is not duplicated for each new cipher. Instead they each +/// get a reference to an abstract policy interface by calling AccessPolicy() on itself, so +/// AccessPolicy() must be overridden to return the actual policy reference. This is done +/// by the ConceretePolicyHolder class. Finally, SymmetricCipherFinal implements the constructors and +/// other functions that must be implemented by the most derived class. + +#ifndef CRYPTOPP_STRCIPHR_H +#define CRYPTOPP_STRCIPHR_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4231 4275) +#endif + +#include "cryptlib.h" +#include "seckey.h" +#include "secblock.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Access a stream cipher policy object +/// \tparam POLICY_INTERFACE class implementing AbstractPolicyHolder +/// \tparam BASE class or type to use as a base class +template +class CRYPTOPP_NO_VTABLE AbstractPolicyHolder : public BASE +{ +public: + typedef POLICY_INTERFACE PolicyInterface; + virtual ~AbstractPolicyHolder() {} + +protected: + virtual const POLICY_INTERFACE & GetPolicy() const =0; + virtual POLICY_INTERFACE & AccessPolicy() =0; +}; + +/// \brief Stream cipher policy object +/// \tparam POLICY class implementing AbstractPolicyHolder +/// \tparam BASE class or type to use as a base class +template +class ConcretePolicyHolder : public BASE, protected POLICY +{ +public: + virtual ~ConcretePolicyHolder() {} +protected: + const POLICY_INTERFACE & GetPolicy() const {return *this;} + POLICY_INTERFACE & AccessPolicy() {return *this;} +}; + +/// \brief Keystream operation flags +/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize() +/// and AdditiveCipherAbstractPolicy::GetAlignment() +enum KeystreamOperationFlags { + /// \brief Output buffer is aligned + OUTPUT_ALIGNED=1, + /// \brief Input buffer is aligned + INPUT_ALIGNED=2, + /// \brief Input buffer is NULL + INPUT_NULL = 4 +}; + +/// \brief Keystream operation flags +/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize() +/// and AdditiveCipherAbstractPolicy::GetAlignment() +enum KeystreamOperation { + /// \brief Wirte the keystream to the output buffer, input is NULL + WRITE_KEYSTREAM = INPUT_NULL, + /// \brief Wirte the keystream to the aligned output buffer, input is NULL + WRITE_KEYSTREAM_ALIGNED = INPUT_NULL | OUTPUT_ALIGNED, + /// \brief XOR the input buffer and keystream, write to the output buffer + XOR_KEYSTREAM = 0, + /// \brief XOR the aligned input buffer and keystream, write to the output buffer + XOR_KEYSTREAM_INPUT_ALIGNED = INPUT_ALIGNED, + /// \brief XOR the input buffer and keystream, write to the aligned output buffer + XOR_KEYSTREAM_OUTPUT_ALIGNED= OUTPUT_ALIGNED, + /// \brief XOR the aligned input buffer and keystream, write to the aligned output buffer + XOR_KEYSTREAM_BOTH_ALIGNED = OUTPUT_ALIGNED | INPUT_ALIGNED}; + +/// \brief Policy object for additive stream ciphers +struct CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AdditiveCipherAbstractPolicy +{ + virtual ~AdditiveCipherAbstractPolicy() {} + + /// \brief Provides data alignment requirements + /// \returns data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + virtual unsigned int GetAlignment() const {return 1;} + + /// \brief Provides number of bytes operated upon during an iteration + /// \returns bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + virtual unsigned int GetBytesPerIteration() const =0; + + /// \brief Provides number of ideal bytes to process + /// \returns the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() + virtual unsigned int GetOptimalBlockSize() const {return GetBytesPerIteration();} + + /// \brief Provides buffer size based on iterations + /// \returns the buffer size based on iterations, in bytes + virtual unsigned int GetIterationsToBuffer() const =0; + + /// \brief Generate the keystream + /// \param keystream the key stream + /// \param iterationCount the number of iterations to generate the key stream + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + virtual void WriteKeystream(byte *keystream, size_t iterationCount) + {OperateKeystream(KeystreamOperation(INPUT_NULL | (KeystreamOperationFlags)IsAlignedOn(keystream, GetAlignment())), keystream, NULLPTR, iterationCount);} + + /// \brief Flag indicating + /// \returns true if the stream can be generated independent of the transformation input, false otherwise + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + virtual bool CanOperateKeystream() const {return false;} + + /// \brief Operates the keystream + /// \param operation the operation with additional flags + /// \param output the output buffer + /// \param input the input buffer + /// \param iterationCount the number of iterations to perform on the input + /// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer, + /// which will be derived from GetBytesPerIteration(). + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation() + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) + {CRYPTOPP_UNUSED(operation); CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(false);} + + /// \brief Key the cipher + /// \param params set of NameValuePairs use to initialize this object + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; + + /// \brief Resynchronize the cipher + /// \param keystreamBuffer the keystream buffer + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) + {CRYPTOPP_UNUSED(keystreamBuffer); CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + + /// \brief Flag indicating random access + /// \returns true if the cipher is seekable, false otherwise + /// \sa SeekToIteration() + virtual bool CipherIsRandomAccess() const =0; + + /// \brief Seeks to a random position in the stream + /// \sa CipherIsRandomAccess() + virtual void SeekToIteration(lword iterationCount) + {CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(!CipherIsRandomAccess()); throw NotImplemented("StreamTransformation: this object doesn't support random access");} +}; + +/// \brief Base class for additive stream ciphers +/// \tparam WT word type +/// \tparam W count of words +/// \tparam X bytes per iteration count +/// \tparam BASE AdditiveCipherAbstractPolicy derived base class +template +struct CRYPTOPP_NO_VTABLE AdditiveCipherConcretePolicy : public BASE +{ + typedef WT WordType; + CRYPTOPP_CONSTANT(BYTES_PER_ITERATION = sizeof(WordType) * W) + +#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X64) + /// \brief Provides data alignment requirements + /// \returns data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + unsigned int GetAlignment() const {return GetAlignmentOf();} +#endif + + /// \brief Provides number of bytes operated upon during an iteration + /// \returns bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + unsigned int GetBytesPerIteration() const {return BYTES_PER_ITERATION;} + + /// \brief Provides buffer size based on iterations + /// \returns the buffer size based on iterations, in bytes + unsigned int GetIterationsToBuffer() const {return X;} + + /// \brief Flag indicating + /// \returns true if the stream can be generated independent of the transformation input, false otherwise + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + bool CanOperateKeystream() const {return true;} + + /// \brief Operates the keystream + /// \param operation the operation with additional flags + /// \param output the output buffer + /// \param input the input buffer + /// \param iterationCount the number of iterations to perform on the input + /// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer, + /// which will be derived from GetBytesPerIteration(). + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation() + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) =0; +}; + +/// \brief Helper macro to implement OperateKeystream +#define CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, b, i, a) \ + PutWord(bool(x & OUTPUT_ALIGNED), b, output+i*sizeof(WordType), (x & INPUT_NULL) ? (a) : (a) ^ GetWord(bool(x & INPUT_ALIGNED), b, input+i*sizeof(WordType))); + +/// \brief Helper macro to implement OperateKeystream +#define CRYPTOPP_KEYSTREAM_OUTPUT_XMM(x, i, a) {\ + __m128i t = (x & INPUT_NULL) ? a : _mm_xor_si128(a, (x & INPUT_ALIGNED) ? _mm_load_si128((__m128i *)input+i) : _mm_loadu_si128((__m128i *)input+i));\ + if (x & OUTPUT_ALIGNED) _mm_store_si128((__m128i *)output+i, t);\ + else _mm_storeu_si128((__m128i *)output+i, t);} + +/// \brief Helper macro to implement OperateKeystream +#define CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(x, y) \ + switch (operation) \ + { \ + case WRITE_KEYSTREAM: \ + x(WRITE_KEYSTREAM) \ + break; \ + case XOR_KEYSTREAM: \ + x(XOR_KEYSTREAM) \ + input += y; \ + break; \ + case XOR_KEYSTREAM_INPUT_ALIGNED: \ + x(XOR_KEYSTREAM_INPUT_ALIGNED) \ + input += y; \ + break; \ + case XOR_KEYSTREAM_OUTPUT_ALIGNED: \ + x(XOR_KEYSTREAM_OUTPUT_ALIGNED) \ + input += y; \ + break; \ + case WRITE_KEYSTREAM_ALIGNED: \ + x(WRITE_KEYSTREAM_ALIGNED) \ + break; \ + case XOR_KEYSTREAM_BOTH_ALIGNED: \ + x(XOR_KEYSTREAM_BOTH_ALIGNED) \ + input += y; \ + break; \ + } \ + output += y; + +/// \brief Base class for additive stream ciphers with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE AdditiveCipherTemplate : public BASE, public RandomNumberGenerator +{ +public: + virtual ~AdditiveCipherTemplate() {} + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + void GenerateBlock(byte *output, size_t size); + + /// \brief Apply keystream to data + /// \param outString a buffer to write the transformed data + /// \param inString a buffer to read the data + /// \param length the size fo the buffers, in bytes + /// \details This is the primary method to operate a stream cipher. For example: + ///
+	///     size_t size = 30;
+	///     byte plain[size] = "Do or do not; there is no try";
+	///     byte cipher[size];
+	///     ...
+	///     ChaCha20 chacha(key, keySize);
+	///     chacha.ProcessData(cipher, plain, size);
+	/// 
+ void ProcessData(byte *outString, const byte *inString, size_t length); + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + void Resynchronize(const byte *iv, int length=-1); + + /// \brief Provides number of ideal bytes to process + /// \returns the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() and GetOptimalNextBlockSize() + unsigned int OptimalBlockSize() const {return this->GetPolicy().GetOptimalBlockSize();} + + /// \brief Provides number of ideal bytes to process + /// \returns the ideal number of bytes to process + /// \details Internally, the default implementation returns remaining unprocessed bytes + /// \sa GetBytesPerIteration() and OptimalBlockSize() + unsigned int GetOptimalNextBlockSize() const {return (unsigned int)this->m_leftOver;} + + /// \brief Provides number of ideal data alignment + /// \returns the ideal data alignment, in bytes + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} + + /// \brief Determines if the cipher is self inverting + /// \returns true if the stream cipher is self inverting, false otherwise + bool IsSelfInverting() const {return true;} + + /// \brief Determines if the cipher is a forward transformation + /// \returns true if the stream cipher is a forward transformation, false otherwise + bool IsForwardTransformation() const {return true;} + + /// \brief Flag indicating random access + /// \returns true if the cipher is seekable, false otherwise + /// \sa Seek() + bool IsRandomAccess() const {return this->GetPolicy().CipherIsRandomAccess();} + + /// \brief Seeks to a random position in the stream + /// \param position the absolute position in the stream + /// \sa IsRandomAccess() + void Seek(lword position); + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + unsigned int GetBufferByteSize(const PolicyInterface &policy) const {return policy.GetBytesPerIteration() * policy.GetIterationsToBuffer();} + + inline byte * KeystreamBufferBegin() {return this->m_buffer.data();} + inline byte * KeystreamBufferEnd() {return (this->m_buffer.data() + this->m_buffer.size());} + + SecByteBlock m_buffer; + size_t m_leftOver; +}; + +/// \brief Policy object for feeback based stream ciphers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_CipherAbstractPolicy +{ +public: + virtual ~CFB_CipherAbstractPolicy() {} + + /// \brief Provides data alignment requirements + /// \returns data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + virtual unsigned int GetAlignment() const =0; + + /// \brief Provides number of bytes operated upon during an iteration + /// \returns bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + virtual unsigned int GetBytesPerIteration() const =0; + + /// \brief Access the feedback register + /// \returns pointer to the first byte of the feedback register + virtual byte * GetRegisterBegin() =0; + + /// \brief TODO + virtual void TransformRegister() =0; + + /// \brief Flag indicating iteration support + /// \returns true if the cipher supports iteration, false otherwise + virtual bool CanIterate() const {return false;} + + /// \brief Iterate the cipher + /// \param output the output buffer + /// \param input the input buffer + /// \param dir the direction of the cipher + /// \param iterationCount the number of iterations to perform on the input + /// \sa IsSelfInverting() and IsForwardTransformation() + virtual void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) + {CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(dir); CRYPTOPP_UNUSED(iterationCount); + CRYPTOPP_ASSERT(false); /*throw 0;*/ throw Exception(Exception::OTHER_ERROR, "SimpleKeyingInterface: unexpected error");} + + /// \brief Key the cipher + /// \param params set of NameValuePairs use to initialize this object + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + virtual void CipherResynchronize(const byte *iv, size_t length) + {CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} +}; + +/// \brief Base class for feedback based stream ciphers +/// \tparam WT word type +/// \tparam W count of words +/// \tparam BASE CFB_CipherAbstractPolicy derived base class +template +struct CRYPTOPP_NO_VTABLE CFB_CipherConcretePolicy : public BASE +{ + typedef WT WordType; + + /// \brief Provides data alignment requirements + /// \returns data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + unsigned int GetAlignment() const {return sizeof(WordType);} + + /// \brief Provides number of bytes operated upon during an iteration + /// \returns bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;} + + /// \brief Flag indicating iteration support + /// \returns true if the cipher supports iteration, false otherwise + bool CanIterate() const {return true;} + + /// \brief Perform one iteration in the forward direction + void TransformRegister() {this->Iterate(NULLPTR, NULLPTR, ENCRYPTION, 1);} + + /// \brief Provides alternate access to a feedback register + /// \tparam B enumeration indicating endianness + /// \details RegisterOutput() provides alternate access to the feedback register. The + /// enumeration B is BigEndian or LittleEndian. Repeatedly applying operator() + /// results in advancing in the register. + template + struct RegisterOutput + { + RegisterOutput(byte *output, const byte *input, CipherDir dir) + : m_output(output), m_input(input), m_dir(dir) {} + + /// \brief XOR feedback register with data + /// \param registerWord data represented as a word type + /// \returns reference to the next feedback register word + inline RegisterOutput& operator()(WordType ®isterWord) + { + CRYPTOPP_ASSERT(IsAligned(m_output)); + CRYPTOPP_ASSERT(IsAligned(m_input)); + + if (!NativeByteOrderIs(B::ToEnum())) + registerWord = ByteReverse(registerWord); + + if (m_dir == ENCRYPTION) + { + if (m_input == NULLPTR) + { + CRYPTOPP_ASSERT(m_output == NULLPTR); + } + else + { + WordType ct = *(const WordType *)m_input ^ registerWord; + registerWord = ct; + *(WordType*)m_output = ct; + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + } + else + { + WordType ct = *(const WordType *)m_input; + *(WordType*)m_output = registerWord ^ ct; + registerWord = ct; + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + + // registerWord is left unreversed so it can be xor-ed with further input + + return *this; + } + + byte *m_output; + const byte *m_input; + CipherDir m_dir; + }; +}; + +/// \brief Base class for feedback based stream ciphers with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template +class CRYPTOPP_NO_VTABLE CFB_CipherTemplate : public BASE +{ +public: + /// \brief Apply keystream to data + /// \param outString a buffer to write the transformed data + /// \param inString a buffer to read the data + /// \param length the size fo the buffers, in bytes + /// \details This is the primary method to operate a stream cipher. For example: + ///
+	///     size_t size = 30;
+	///     byte plain[size] = "Do or do not; there is no try";
+	///     byte cipher[size];
+	///     ...
+	///     ChaCha20 chacha(key, keySize);
+	///     chacha.ProcessData(cipher, plain, size);
+	/// 
+ void ProcessData(byte *outString, const byte *inString, size_t length); + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + void Resynchronize(const byte *iv, int length=-1); + + /// \brief Provides number of ideal bytes to process + /// \returns the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() and GetOptimalNextBlockSize() + unsigned int OptimalBlockSize() const {return this->GetPolicy().GetBytesPerIteration();} + + /// \brief Provides number of ideal bytes to process + /// \returns the ideal number of bytes to process + /// \details Internally, the default implementation returns remaining unprocessed bytes + /// \sa GetBytesPerIteration() and OptimalBlockSize() + unsigned int GetOptimalNextBlockSize() const {return (unsigned int)m_leftOver;} + + /// \brief Provides number of ideal data alignment + /// \returns the ideal data alignment, in bytes + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} + + /// \brief Flag indicating random access + /// \returns true if the cipher is seekable, false otherwise + /// \sa Seek() + bool IsRandomAccess() const {return false;} + + /// \brief Determines if the cipher is self inverting + /// \returns true if the stream cipher is self inverting, false otherwise + bool IsSelfInverting() const {return false;} + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + virtual void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) =0; + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + size_t m_leftOver; +}; + +/// \brief Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE CFB_EncryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return true;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); +}; + +/// \brief Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE CFB_DecryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return false;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); +}; + +/// \brief Base class for feedback based stream ciphers with a mandatory block size +/// \tparam BASE CFB_EncryptionTemplate or CFB_DecryptionTemplate base class +template +class CFB_RequireFullDataBlocks : public BASE +{ +public: + unsigned int MandatoryBlockSize() const {return this->OptimalBlockSize();} +}; + +/// \brief SymmetricCipher implementation +/// \tparam BASE AbstractPolicyHolder derived base class +/// \tparam INFO AbstractPolicyHolder derived information class +/// \sa Weak::ARC4, ChaCha8, ChaCha12, ChaCha20, Salsa20, SEAL, Sosemanuk, WAKE +template +class SymmetricCipherFinal : public AlgorithmImpl, INFO> +{ +public: + virtual ~SymmetricCipherFinal() {} + + /// \brief Construct a stream cipher + SymmetricCipherFinal() {} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \details This overload uses DEFAULT_KEYLENGTH + SymmetricCipherFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + SymmetricCipherFinal(const byte *key, size_t length) + {this->SetKey(key, length);} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + /// \param iv a byte array used as an initialization vector + SymmetricCipherFinal(const byte *key, size_t length, const byte *iv) + {this->SetKeyWithIV(key, length, iv);} + + /// \brief Clone a SymmetricCipher + /// \returns a new SymmetricCipher based on this object + Clonable * Clone() const {return static_cast(new SymmetricCipherFinal(*this));} +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "strciphr.cpp" +#endif + +NAMESPACE_BEGIN(CryptoPP) +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractPolicyHolder; +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/include/cryptlib/tea.h b/include/cryptlib/tea.h new file mode 100644 index 0000000..d747be8 --- /dev/null +++ b/include/cryptlib/tea.h @@ -0,0 +1,148 @@ +// tea.h - originally written and placed in the public domain by Wei Dai + +/// \file tea.h +/// \brief Classes for the TEA, BTEA and XTEA block ciphers + +#ifndef CRYPTOPP_TEA_H +#define CRYPTOPP_TEA_H + +#include "seckey.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief TEA block cipher information +struct TEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "TEA";} +}; + +/// \brief TEA block cipher +/// \sa TEA +class TEA : public TEA_Info, public BlockCipherDocumentation +{ + /// \brief TEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_k; + word32 m_limit; + }; + + /// \brief TEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief TEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef TEA::Encryption TEAEncryption; +typedef TEA::Decryption TEADecryption; + +/// \brief XTEA block cipher information +struct XTEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "XTEA";} +}; + +/// \brief XTEA block cipher +/// \sa XTEA +class XTEA : public XTEA_Info, public BlockCipherDocumentation +{ + /// \brief XTEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_k; + word32 m_limit; + }; + + /// \brief XTEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief XTEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief BTEA block cipher information +struct BTEA_Info : public FixedKeyLength<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BTEA";} +}; + +/// \brief BTEA block cipher +/// \details Corrected Block TEA as described in "xxtea". This class hasn't been tested yet. +/// \sa Corrected Block TEA. +class BTEA : public BTEA_Info, public BlockCipherDocumentation +{ + /// \brief BTEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public AlgorithmImpl, BTEA_Info>, public BTEA_Info + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); + m_blockSize = params.GetIntValueWithDefault("BlockSize", 60*4); + GetUserKey(BIG_ENDIAN_ORDER, m_k.begin(), 4, key, KEYLENGTH); + } + + unsigned int BlockSize() const {return m_blockSize;} + + protected: + FixedSizeSecBlock m_k; + unsigned int m_blockSize; + }; + + /// \brief BTEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief BTEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/threefish.h b/include/cryptlib/threefish.h new file mode 100644 index 0000000..6ab21fb --- /dev/null +++ b/include/cryptlib/threefish.h @@ -0,0 +1,201 @@ +// threefish.h - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. Kuro's code is +// available at http://cppcrypto.sourceforge.net/. + +/// \file Threefish.h +/// \brief Classes for the Threefish block cipher +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_THREEFISH_H +#define CRYPTOPP_THREEFISH_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" +#include "argnames.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Threefish block cipher information +/// \tparam BS block size of the cipher, in bytes +/// \since Crypto++ 6.0 +template +struct Threefish_Info : public FixedBlockSize, FixedKeyLength +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Threefish-" + IntToString(BS*8) + "(" + IntToString(BS*8) + ")"; + } +}; + +/// \brief Threefish block cipher base class +/// \tparam BS block size of the cipher, in bytes +/// \details User code should use Threefish256, Threefish512, Threefish1024 +/// \sa Threefish256, Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +template +struct CRYPTOPP_NO_VTABLE Threefish_Base +{ + virtual ~Threefish_Base() {} + + void SetTweak(const NameValuePairs ¶ms) + { + m_tweak.New(3); + ConstByteArrayParameter t; + if (params.GetValue(Name::Tweak(), t)) + { + // Tweak size is fixed at 16 for Threefish + CRYPTOPP_ASSERT(t.size() == 16); + GetUserKey(LITTLE_ENDIAN_ORDER, m_tweak.begin(), 2, t.begin(), 16); + m_tweak[2] = m_tweak[0] ^ m_tweak[1]; + } + else + { + std::memset(m_tweak.begin(), 0x00, 24); + } + } + + typedef SecBlock > AlignedSecBlock64; + mutable AlignedSecBlock64 m_wspace; // workspace + AlignedSecBlock64 m_rkey; // keys + AlignedSecBlock64 m_tweak; +}; + +/// \brief Threefish 256-bit block cipher +/// \details Threefish256 provides 256-bit block size. The valid key size is 256-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish256 : public Threefish_Info<32>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<32>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish256::Encryption Threefish256Encryption; +typedef Threefish256::Decryption Threefish256Decryption; + +/// \brief Threefish 512-bit block cipher +/// \details Threefish512 provides 512-bit block size. The valid key size is 512-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish512 : public Threefish_Base<32>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<64>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish512::Encryption Threefish512Encryption; +typedef Threefish512::Decryption Threefish512Decryption; + +/// \brief Threefish 1024-bit block cipher +/// \details Threefish1024 provides 1024-bit block size. The valid key size is 1024-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish1024 : public Threefish_Base<32>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<128>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Provides implementation for encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Provides implementation for encryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish1024::Encryption Threefish1024Encryption; +typedef Threefish1024::Decryption Threefish1024Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_THREEFISH_H diff --git a/include/cryptlib/tiger.h b/include/cryptlib/tiger.h new file mode 100644 index 0000000..a83d142 --- /dev/null +++ b/include/cryptlib/tiger.h @@ -0,0 +1,38 @@ +// tiger.h - originally written and placed in the public domain by Wei Dai + +/// \file tiger.h +/// \brief Classes for the Tiger message digest +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_TIGER_H +#define CRYPTOPP_TIGER_H + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux +// http://github.com/weidai11/cryptopp/issues/264 +#if defined(CRYPTOPP_LLVM_CLANG_VERSION) && (CRYPTOPP_LLVM_CLANG_VERSION < 30400) +# define CRYPTOPP_DISABLE_TIGER_ASM +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Tiger message digest +/// \sa Tiger +/// \since Crypto++ 2.1 +class Tiger : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word64 *digest, const word64 *data); + void TruncatedFinal(byte *hash, size_t size); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Tiger";} + +protected: + static const word64 table[4*256+3]; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/trap.h b/include/cryptlib/trap.h new file mode 100644 index 0000000..67599db --- /dev/null +++ b/include/cryptlib/trap.h @@ -0,0 +1,144 @@ +// trap.h - written and placed in public domain by Jeffrey Walton. + +/// \file trap.h +/// \brief Debugging and diagnostic assertions +/// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic assertion. CRYPTOPP_ASSERT +/// is enabled by CRYPTOPP_DEBUG, DEBUG or _DEBUG. +/// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls __debugbreak() (Windows). +/// CRYPTOPP_ASSERT is only in effect when the user requests a debug configuration. Unlike Posix assert, +/// NDEBUG (or failure to define it) does not affect the library. +/// The traditional Posix define NDEBUG has no effect on CRYPTOPP_DEBUG or DebugTrapHandler. +/// \since Crypto++ 5.6.5 +/// \sa DebugTrapHandler, Issue 277, +/// CVE-2016-7420 + +#ifndef CRYPTOPP_TRAP_H +#define CRYPTOPP_TRAP_H + +#include "config.h" + +#if defined(CRYPTOPP_DEBUG) +# include +# include +# if defined(UNIX_SIGNALS_AVAILABLE) +# include "ossig.h" +# elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +# endif +#endif // CRYPTOPP_DEBUG + +// ************** run-time assertion *************** + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Debugging and diagnostic assertion +/// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic assertion. CRYPTOPP_ASSERT +/// is enabled by the preprocessor macros CRYPTOPP_DEBUG, DEBUG or _DEBUG. +/// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls DebugBreak() (Windows). +/// CRYPTOPP_ASSERT is only in effect when the user explicitly requests a debug configuration. +/// \details If you want to ensure CRYPTOPP_ASSERT is inert, then do not define +/// CRYPTOPP_DEBUG, DEBUG or _DEBUG. Avoiding the defines means CRYPTOPP_ASSERT +/// is preprocessed into an empty string. +/// \details The traditional Posix define NDEBUG has no effect on CRYPTOPP_DEBUG, CRYPTOPP_ASSERT +/// or DebugTrapHandler. +/// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and DebugTrapHandler is shown below. The library's +/// test program, cryptest.exe (from test.cpp), exercises the structure: +///
+///    #if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
+///    static const DebugTrapHandler g_dummyHandler;
+///    #endif
+///
+///    int main(int argc, char* argv[])
+///    {
+///       CRYPTOPP_ASSERT(argv != nullptr);
+///       ...
+///    }
+///  
+/// \since Crypto++ 5.6.5 +/// \sa DebugTrapHandler, SignalHandler, Issue 277, +/// CVE-2016-7420 +# define CRYPTOPP_ASSERT(exp) { ... } +#endif + +#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE) +# define CRYPTOPP_ASSERT(exp) { \ + if (!(exp)) { \ + std::ostringstream oss; \ + oss << "Assertion failed: " << (char*)(__FILE__) << "(" \ + << (int)(__LINE__) << "): " << (char*)(__func__) \ + << std::endl; \ + std::cerr << oss.str(); \ + raise(SIGTRAP); \ + } \ + } +#elif CRYPTOPP_DEBUG && defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__) +# define CRYPTOPP_ASSERT(exp) { \ + if (!(exp)) { \ + std::ostringstream oss; \ + oss << "Assertion failed: " << (char*)(__FILE__) << "(" \ + << (int)(__LINE__) << "): " << (char*)(__FUNCTION__) \ + << std::endl; \ + std::cerr << oss.str(); \ + if (IsDebuggerPresent()) {DebugBreak();} \ + } \ + } +#endif // DEBUG and Unix or Windows + +// Remove CRYPTOPP_ASSERT in non-debug builds. +// Can't use CRYPTOPP_UNUSED due to circular dependency +#ifndef CRYPTOPP_ASSERT +# define CRYPTOPP_ASSERT(exp) (void)0 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** SIGTRAP handler *************** + +#if (CRYPTOPP_DEBUG && defined(UNIX_SIGNALS_AVAILABLE)) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Default SIGTRAP handler +/// \details DebugTrapHandler() can be used by a program to install an empty SIGTRAP handler. If present, +/// the handler ensures there is a signal handler in place for SIGTRAP raised by +/// CRYPTOPP_ASSERT. If CRYPTOPP_ASSERT raises SIGTRAP without +/// a handler, then one of two things can occur. First, the OS might allow the program +/// to continue. Second, the OS might terminate the program. OS X allows the program to continue, while +/// some Linuxes terminate the program. +/// \details If DebugTrapHandler detects another handler in place, then it will not install a handler. This +/// ensures a debugger can gain control of the SIGTRAP signal without contention. It also allows multiple +/// DebugTrapHandler to be created without contentious or unusual behavior. Though multiple DebugTrapHandler can be +/// created, a program should only create one, if needed. +/// \details A DebugTrapHandler is subject to C++ static initialization [dis]order. If you need to install a handler +/// and it must be installed early, then reference the code associated with CRYPTOPP_INIT_PRIORITY in +/// cryptlib.cpp and cpu.cpp. +/// \details If you want to ensure CRYPTOPP_ASSERT is inert, then do not define +/// CRYPTOPP_DEBUG, DEBUG or _DEBUG. Avoiding the defines means CRYPTOPP_ASSERT +/// is processed into ((void)(exp)). +/// \details The traditional Posix define NDEBUG has no effect on CRYPTOPP_DEBUG, CRYPTOPP_ASSERT +/// or DebugTrapHandler. +/// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and DebugTrapHandler is shown below. The library's +/// test program, cryptest.exe (from test.cpp), exercises the structure: +///
+///    #if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
+///    static const DebugTrapHandler g_dummyHandler;
+///    #endif
+///
+///    int main(int argc, char* argv[])
+///    {
+///       CRYPTOPP_ASSERT(argv != nullptr);
+///       ...
+///    }
+///  
+/// \since Crypto++ 5.6.5 +/// \sa \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", SignalHandler, Issue 277, +/// CVE-2016-7420 + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +class DebugTrapHandler : public SignalHandler { }; +#else +typedef SignalHandler DebugTrapHandler; +#endif + +#endif // Linux, Unix and Documentation + +NAMESPACE_END + +#endif // CRYPTOPP_TRAP_H diff --git a/include/cryptlib/trdlocal.h b/include/cryptlib/trdlocal.h new file mode 100644 index 0000000..527c3a7 --- /dev/null +++ b/include/cryptlib/trdlocal.h @@ -0,0 +1,44 @@ +#ifndef CRYPTOPP_TRDLOCAL_H +#define CRYPTOPP_TRDLOCAL_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(THREADS_AVAILABLE) + +#include "misc.h" + +#ifdef HAS_WINTHREADS +typedef unsigned long ThreadLocalIndexType; +#else +#include +typedef pthread_key_t ThreadLocalIndexType; +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// thread local storage +class CRYPTOPP_DLL ThreadLocalStorage : public NotCopyable +{ +public: + /// exception thrown by ThreadLocalStorage class + class Err : public OS_Error + { + public: + Err(const std::string& operation, int error); + }; + + ThreadLocalStorage(); + ~ThreadLocalStorage() CRYPTOPP_THROW; + + void SetValue(void *value); + void *GetValue() const; + +private: + ThreadLocalIndexType m_index; +}; + +NAMESPACE_END + +#endif // THREADS_AVAILABLE + +#endif // CRYPTOPP_TRDLOCAL_H diff --git a/include/cryptlib/trunhash.h b/include/cryptlib/trunhash.h new file mode 100644 index 0000000..681c1ee --- /dev/null +++ b/include/cryptlib/trunhash.h @@ -0,0 +1,52 @@ +#ifndef CRYPTOPP_TRUNHASH_H +#define CRYPTOPP_TRUNHASH_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +class NullHash : public HashTransformation +{ +public: + void Update(const byte *input, size_t length) + {CRYPTOPP_UNUSED(input);CRYPTOPP_UNUSED(length);} + unsigned int DigestSize() const + {return 0;} + void TruncatedFinal(byte *digest, size_t digestSize) + {CRYPTOPP_UNUSED(digest);CRYPTOPP_UNUSED(digestSize);} + bool TruncatedVerify(const byte *digest, size_t digestLength) + {CRYPTOPP_UNUSED(digest);CRYPTOPP_UNUSED(digestLength);return true;} +}; + +/// construct new HashModule with smaller DigestSize() from existing one +template +class TruncatedHashTemplate : public HashTransformation +{ +public: + TruncatedHashTemplate(T hm, unsigned int digestSize) + : m_hm(hm), m_digestSize(digestSize) {} + TruncatedHashTemplate(const byte *key, size_t keyLength, unsigned int digestSize) + : m_hm(key, keyLength), m_digestSize(digestSize) {} + TruncatedHashTemplate(size_t digestSize) + : m_digestSize(digestSize) {} + + void Restart() + {m_hm.Restart();} + void Update(const byte *input, size_t length) + {m_hm.Update(input, length);} + unsigned int DigestSize() const {return m_digestSize;} + void TruncatedFinal(byte *digest, size_t digestSize) + {m_hm.TruncatedFinal(digest, digestSize);} + bool TruncatedVerify(const byte *digest, size_t digestLength) + {return m_hm.TruncatedVerify(digest, digestLength);} + +private: + T m_hm; + unsigned int m_digestSize; +}; + +typedef TruncatedHashTemplate TruncatedHashModule; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/ttmac.h b/include/cryptlib/ttmac.h new file mode 100644 index 0000000..ac9aca0 --- /dev/null +++ b/include/cryptlib/ttmac.h @@ -0,0 +1,44 @@ +// ttmac.h - written and placed in the public domain by Kevin Springle + +/// \file ttmac.h +/// \brief Classes for the TTMAC message authentication code + +#ifndef CRYPTOPP_TTMAC_H +#define CRYPTOPP_TTMAC_H + +#include "seckey.h" +#include "iterhash.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief TTMAC message authentication code information +class CRYPTOPP_NO_VTABLE TTMAC_Base : public FixedKeyLength<20>, public IteratedHash +{ +public: + static std::string StaticAlgorithmName() {return std::string("Two-Track-MAC");} + CRYPTOPP_CONSTANT(DIGESTSIZE=20) + + unsigned int DigestSize() const {return DIGESTSIZE;}; + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + void TruncatedFinal(byte *mac, size_t size); + +protected: + static void Transform (word32 *digest, const word32 *X, bool last); + void HashEndianCorrectedBlock(const word32 *data) {Transform(m_digest, data, false);} + void Init(); + word32* StateBuf() {return m_digest;} + + FixedSizeSecBlock m_digest; + FixedSizeSecBlock m_key; +}; + +/// \brief Two-Track-MAC message authentication code +/// \tparam T HashTransformation class +/// \details 160-bit MAC with 160-bit key +/// \sa MessageAuthenticationCode(), Two-Track-MAC +DOCUMENTED_TYPEDEF(MessageAuthenticationCodeFinal, TTMAC) + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/tweetnacl.h b/include/cryptlib/tweetnacl.h new file mode 100644 index 0000000..9277fbf --- /dev/null +++ b/include/cryptlib/tweetnacl.h @@ -0,0 +1,272 @@ +#ifndef TWEETNACL_H +#define TWEETNACL_H +#define crypto_auth_PRIMITIVE "hmacsha512256" +#define crypto_auth crypto_auth_hmacsha512256 +#define crypto_auth_verify crypto_auth_hmacsha512256_verify +#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES +#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES +#define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION +#define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION +#define crypto_auth_hmacsha512256_tweet_BYTES 32 +#define crypto_auth_hmacsha512256_tweet_KEYBYTES 32 +extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +#define crypto_auth_hmacsha512256_tweet_VERSION "-" +#define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet +#define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify +#define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES +#define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES +#define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION +#define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet" +#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" +#define crypto_box crypto_box_curve25519xsalsa20poly1305 +#define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open +#define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair +#define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm +#define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm +#define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm +#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES +#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES +#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES +#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES +#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES +#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES +#define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION +#define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION +#define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24 +#define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16 +extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-" +#define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet +#define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open +#define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair +#define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm +#define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm +#define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm +#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES +#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES +#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES +#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES +#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES +#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES +#define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION +#define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet" +#define crypto_core_PRIMITIVE "salsa20" +#define crypto_core crypto_core_salsa20 +#define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES +#define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES +#define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES +#define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES +#define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION +#define crypto_core_VERSION crypto_core_salsa20_VERSION +#define crypto_core_salsa20_tweet_OUTPUTBYTES 64 +#define crypto_core_salsa20_tweet_INPUTBYTES 16 +#define crypto_core_salsa20_tweet_KEYBYTES 32 +#define crypto_core_salsa20_tweet_CONSTBYTES 16 +extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); +#define crypto_core_salsa20_tweet_VERSION "-" +#define crypto_core_salsa20 crypto_core_salsa20_tweet +#define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES +#define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES +#define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES +#define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES +#define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION +#define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet" +#define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32 +#define crypto_core_hsalsa20_tweet_INPUTBYTES 16 +#define crypto_core_hsalsa20_tweet_KEYBYTES 32 +#define crypto_core_hsalsa20_tweet_CONSTBYTES 16 +extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); +#define crypto_core_hsalsa20_tweet_VERSION "-" +#define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet +#define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES +#define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES +#define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES +#define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES +#define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION +#define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet" +#define crypto_hashblocks_PRIMITIVE "sha512" +#define crypto_hashblocks crypto_hashblocks_sha512 +#define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES +#define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES +#define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION +#define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION +#define crypto_hashblocks_sha512_tweet_STATEBYTES 64 +#define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128 +extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hashblocks_sha512_tweet_VERSION "-" +#define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet +#define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES +#define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES +#define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION +#define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet" +#define crypto_hashblocks_sha256_tweet_STATEBYTES 32 +#define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64 +extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hashblocks_sha256_tweet_VERSION "-" +#define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet +#define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES +#define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES +#define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION +#define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet" +#define crypto_hash_PRIMITIVE "sha512" +#define crypto_hash crypto_hash_sha512 +#define crypto_hash_BYTES crypto_hash_sha512_BYTES +#define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION +#define crypto_hash_VERSION crypto_hash_sha512_VERSION +#define crypto_hash_sha512_tweet_BYTES 64 +extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hash_sha512_tweet_VERSION "-" +#define crypto_hash_sha512 crypto_hash_sha512_tweet +#define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES +#define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION +#define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet" +#define crypto_hash_sha256_tweet_BYTES 32 +extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hash_sha256_tweet_VERSION "-" +#define crypto_hash_sha256 crypto_hash_sha256_tweet +#define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES +#define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION +#define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet" +#define crypto_onetimeauth_PRIMITIVE "poly1305" +#define crypto_onetimeauth crypto_onetimeauth_poly1305 +#define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify +#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES +#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES +#define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION +#define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION +#define crypto_onetimeauth_poly1305_tweet_BYTES 16 +#define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32 +extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +#define crypto_onetimeauth_poly1305_tweet_VERSION "-" +#define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet +#define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify +#define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES +#define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES +#define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION +#define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet" +#define crypto_scalarmult_PRIMITIVE "curve25519" +#define crypto_scalarmult crypto_scalarmult_curve25519 +#define crypto_scalarmult_base crypto_scalarmult_curve25519_base +#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES +#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES +#define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION +#define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION +#define crypto_scalarmult_curve25519_tweet_BYTES 32 +#define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32 +extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *); +#define crypto_scalarmult_curve25519_tweet_VERSION "-" +#define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet +#define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base +#define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES +#define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES +#define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION +#define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet" +#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" +#define crypto_secretbox crypto_secretbox_xsalsa20poly1305 +#define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open +#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES +#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES +#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES +#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES +#define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION +#define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION +#define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32 +#define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24 +#define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32 +#define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16 +extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-" +#define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet +#define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open +#define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES +#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES +#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES +#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES +#define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION +#define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet" +#define crypto_sign_PRIMITIVE "ed25519" +#define crypto_sign crypto_sign_ed25519 +#define crypto_sign_open crypto_sign_ed25519_open +#define crypto_sign_keypair crypto_sign_ed25519_keypair +#define crypto_sign_BYTES crypto_sign_ed25519_BYTES +#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES +#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES +#define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION +#define crypto_sign_VERSION crypto_sign_ed25519_VERSION +#define crypto_sign_ed25519_tweet_BYTES 64 +#define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32 +#define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64 +extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *); +#define crypto_sign_ed25519_tweet_VERSION "-" +#define crypto_sign_ed25519 crypto_sign_ed25519_tweet +#define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open +#define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair +#define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES +#define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES +#define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES +#define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION +#define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet" +#define crypto_stream_PRIMITIVE "xsalsa20" +#define crypto_stream crypto_stream_xsalsa20 +#define crypto_stream_xor crypto_stream_xsalsa20_xor +#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES +#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES +#define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION +#define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION +#define crypto_stream_xsalsa20_tweet_KEYBYTES 32 +#define crypto_stream_xsalsa20_tweet_NONCEBYTES 24 +extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_stream_xsalsa20_tweet_VERSION "-" +#define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet +#define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor +#define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES +#define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES +#define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION +#define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet" +#define crypto_stream_salsa20_tweet_KEYBYTES 32 +#define crypto_stream_salsa20_tweet_NONCEBYTES 8 +extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_stream_salsa20_tweet_VERSION "-" +#define crypto_stream_salsa20 crypto_stream_salsa20_tweet +#define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor +#define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES +#define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES +#define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION +#define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet" +#define crypto_verify_PRIMITIVE "16" +#define crypto_verify crypto_verify_16 +#define crypto_verify_BYTES crypto_verify_16_BYTES +#define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION +#define crypto_verify_VERSION crypto_verify_16_VERSION +#define crypto_verify_16_tweet_BYTES 16 +extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *); +#define crypto_verify_16_tweet_VERSION "-" +#define crypto_verify_16 crypto_verify_16_tweet +#define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES +#define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION +#define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet" +#define crypto_verify_32_tweet_BYTES 32 +extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *); +#define crypto_verify_32_tweet_VERSION "-" +#define crypto_verify_32 crypto_verify_32_tweet +#define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES +#define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION +#define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet" +#endif diff --git a/include/cryptlib/twofish.h b/include/cryptlib/twofish.h new file mode 100644 index 0000000..cf28902 --- /dev/null +++ b/include/cryptlib/twofish.h @@ -0,0 +1,64 @@ +// twofish.h - originally written and placed in the public domain by Wei Dai + +/// \file twofish.h +/// \brief Classes for the Twofish block cipher + +#ifndef CRYPTOPP_TWOFISH_H +#define CRYPTOPP_TWOFISH_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Twofish block cipher information +/// \since Crypto++ 3.1 +struct Twofish_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Twofish";} +}; + +/// \brief Twofish block cipher +/// \sa Twofish +/// \since Crypto++ 3.1 +class Twofish : public Twofish_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static word32 h0(word32 x, const word32 *key, unsigned int kLen); + static word32 h(word32 x, const word32 *key, unsigned int kLen); + + static const byte q[2][256]; + static const word32 mds[4][256]; + + FixedSizeSecBlock m_k; + FixedSizeSecBlock m_s; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Twofish::Encryption TwofishEncryption; +typedef Twofish::Decryption TwofishDecryption; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/validate.h b/include/cryptlib/validate.h new file mode 100644 index 0000000..6b7c4bd --- /dev/null +++ b/include/cryptlib/validate.h @@ -0,0 +1,268 @@ +// validate.h - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#ifndef CRYPTOPP_VALIDATE_H +#define CRYPTOPP_VALIDATE_H + +#include "cryptlib.h" +#include "integer.h" +#include "misc.h" + +#include +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +bool ValidateAll(bool thorough); +bool TestSettings(); +bool TestOS_RNG(); +// bool TestSecRandom(); +bool TestRandomPool(); +#if !defined(NO_OS_DEPENDENCE) +bool TestAutoSeededX917(); +#endif +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +bool TestRDRAND(); +bool TestRDSEED(); +bool TestPadlockRNG(); +#endif +bool ValidateBaseCode(); +bool ValidateEncoder(); +bool ValidateCRC32(); +bool ValidateCRC32C(); +bool ValidateAdler32(); +bool ValidateMD2(); +bool ValidateMD4(); +bool ValidateMD5(); +bool ValidateSHA(); +bool ValidateSHA2(); +bool ValidateTiger(); +bool ValidateRIPEMD(); +bool ValidatePanama(); +bool ValidateWhirlpool(); + +bool ValidateSM3(); +bool ValidateBLAKE2s(); +bool ValidateBLAKE2b(); +bool ValidatePoly1305(); +bool ValidateSipHash(); + +bool ValidateHMAC(); +bool ValidateTTMAC(); + +bool ValidateCipherModes(); +bool ValidatePBKDF(); +bool ValidateHKDF(); +bool ValidateScrypt(); + +bool ValidateDES(); +bool ValidateIDEA(); +bool ValidateSAFER(); +bool ValidateRC2(); +bool ValidateARC4(); + +bool ValidateRC5(); +bool ValidateBlowfish(); +bool ValidateThreeWay(); +bool ValidateGOST(); +bool ValidateSHARK(); +bool ValidateSEAL(); +bool ValidateCAST(); +bool ValidateSquare(); +bool ValidateSKIPJACK(); +bool ValidateRC6(); +bool ValidateMARS(); +bool ValidateRijndael(); +bool ValidateTwofish(); +bool ValidateSerpent(); +bool ValidateSHACAL2(); +bool ValidateARIA(); +bool ValidateCamellia(); +bool ValidateSalsa(); +bool ValidateSosemanuk(); +bool ValidateVMAC(); +bool ValidateCCM(); +bool ValidateGCM(); +bool ValidateCMAC(); + +bool ValidateBBS(); +bool ValidateDH(); +bool ValidateMQV(); +bool ValidateHMQV(); +bool ValidateFHMQV(); +bool ValidateRSA(); +bool ValidateElGamal(); +bool ValidateDLIES(); +bool ValidateNR(); +bool ValidateDSA(bool thorough); +bool ValidateLUC(); +bool ValidateLUC_DL(); +bool ValidateLUC_DH(); +bool ValidateXTR_DH(); +bool ValidateRabin(); +bool ValidateRW(); +bool ValidateECP(); +bool ValidateEC2N(); +bool ValidateECDSA(); +bool ValidateECDSA_RFC6979(); +bool ValidateECGDSA(bool thorough); +bool ValidateESIGN(); + +bool ValidateHashDRBG(); +bool ValidateHmacDRBG(); + +bool ValidateNaCl(); + +// If CRYPTOPP_DEBUG or CRYPTOPP_COVERAGE is in effect, then perform additional tests +#if (defined(CRYPTOPP_DEBUG) || defined(CRYPTOPP_COVERAGE) || defined(CRYPTOPP_VALGRIND)) && !defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_EXTENDED_VALIDATION 1 +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +// http://github.com/weidai11/cryptopp/issues/92 +bool TestSecBlock(); +// http://github.com/weidai11/cryptopp/issues/64 +bool TestPolynomialMod2(); +// http://github.com/weidai11/cryptopp/issues/336 +bool TestIntegerBitops(); +// http://github.com/weidai11/cryptopp/issues/602 +bool TestIntegerOps(); +// http://github.com/weidai11/cryptopp/issues/360 +bool TestRounding(); +// http://github.com/weidai11/cryptopp/issues/242 +bool TestHuffmanCodes(); +// http://github.com/weidai11/cryptopp/issues/346 +bool TestASN1Parse(); +// Additional tests due to no coverage +bool TestCompressors(); +bool TestEncryptors(); +bool TestMersenne(); +bool TestSharing(); +#endif + +#if 1 +// Coverity findings in benchmark and validation routines +class StreamState +{ +public: + StreamState(std::ostream& out) + : m_out(out), m_prec(out.precision()), m_width(out.width()), m_fmt(out.flags()), m_fill(out.fill()) + { + } + + ~StreamState() + { + m_out.fill(m_fill); + m_out.flags(m_fmt); + m_out.width(m_width); + m_out.precision(m_prec); + } + +private: + std::ostream& m_out; + std::streamsize m_prec; + std::streamsize m_width; + std::ios_base::fmtflags m_fmt; + std::ostream::char_type m_fill; +}; +#endif + +#if 0 +class StreamState +{ +public: + StreamState(std::ostream& out) + : m_out(out), m_state(NULLPTR) + { + m_state.copyfmt(m_out); + } + + ~StreamState() + { + m_out.copyfmt(m_state); + } + +private: + std::ostream& m_out; + std::ios m_state; +}; +#endif + +// Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 +inline std::string TimeToString(const time_t& t) +{ +#if (CRYPTOPP_MSC_VERSION >= 1400) + tm localTime = {}; + char timeBuf[64]; + errno_t err; + + err = ::localtime_s(&localTime, &t); + CRYPTOPP_ASSERT(err == 0); + err = ::asctime_s(timeBuf, sizeof(timeBuf), &localTime); + CRYPTOPP_ASSERT(err == 0); + + std::string str(timeBuf); +#else + std::string str(::asctime(::localtime(&t))); +#endif + + // Cleanup whitespace + std::string::size_type pos = 0; + while (!str.empty() && std::isspace(*(str.end()-1))) + {str.erase(str.end()-1);} + while (!str.empty() && std::string::npos != (pos = str.find(" ", pos))) + { str.erase(pos, 1); } + + return str; +} + +// Coverity finding +template +inline T StringToValue(const std::string& str) +{ + std::istringstream iss(str); + + // Arbitrary, but we need to clear a Coverity finding TAINTED_SCALAR + if (iss.str().length() > 25) + throw InvalidArgument(str + "' is too long"); + + T value; + iss >> std::noskipws >> value; + + // Use fail(), not bad() + if (iss.fail() || !iss.eof()) + throw InvalidArgument(str + "' is not a value"); + + if (NON_NEGATIVE && value < 0) + throw InvalidArgument(str + "' is negative"); + + return value; +} + +// Coverity finding +template<> +inline int StringToValue(const std::string& str) +{ + Integer n(str.c_str()); + long l = n.ConvertToLong(); + + int r; + if (!SafeConvert(l, r)) + throw InvalidArgument(str + "' is not an integer value"); + + return r; +} + +// Functions that need a RNG; uses AES inf CFB mode with Seed. +CryptoPP::RandomNumberGenerator & GlobalRNG(); + +bool RunTestDataFile(const char *filename, const CryptoPP::NameValuePairs &overrideParameters=CryptoPP::g_nullNameValuePairs, bool thorough=true); + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +#endif diff --git a/include/cryptlib/vmac.h b/include/cryptlib/vmac.h new file mode 100644 index 0000000..dded6dc --- /dev/null +++ b/include/cryptlib/vmac.h @@ -0,0 +1,90 @@ +// vmac.h - originally written and placed in the public domain by Wei Dai + +/// \file vmac.h +/// \brief Classes for the VMAC message authentication code +/// \since Crypto++ 5.5 + +#ifndef CRYPTOPP_VMAC_H +#define CRYPTOPP_VMAC_H + +#include "cryptlib.h" +#include "iterhash.h" +#include "seckey.h" + +// Clang 3.3 integrated assembler crash on Linux +// http://github.com/weidai11/cryptopp/issues/264 +#if (defined(CRYPTOPP_LLVM_CLANG_VERSION) && (CRYPTOPP_LLVM_CLANG_VERSION < 30400)) || CRYPTOPP_BOOL_X32 +# define CRYPTOPP_DISABLE_VMAC_ASM +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief VMAC message authentication code base class +/// \since Crypto++ 5.5 +class VMAC_Base : public IteratedHashBase +{ +public: + std::string AlgorithmName() const {return std::string("VMAC(") + GetCipher().AlgorithmName() + ")-" + IntToString(DigestSize()*8);} + unsigned int IVSize() const {return GetCipher().BlockSize();} + unsigned int MinIVLength() const {return 1;} + void Resynchronize(const byte *nonce, int length=-1); + void GetNextIV(RandomNumberGenerator &rng, byte *IV); + unsigned int DigestSize() const {return m_is128 ? 16 : 8;}; + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + void TruncatedFinal(byte *mac, size_t size); + unsigned int BlockSize() const {return m_L1KeyLength;} + ByteOrder GetByteOrder() const {return LITTLE_ENDIAN_ORDER;} + unsigned int OptimalDataAlignment() const; + +protected: + virtual BlockCipher & AccessCipher() =0; + virtual int DefaultDigestSize() const =0; + const BlockCipher & GetCipher() const {return const_cast(this)->AccessCipher();} + void HashEndianCorrectedBlock(const word64 *data); + size_t HashMultipleBlocks(const word64 *input, size_t length); + void Init() {} + word64* StateBuf() {return NULLPTR;} + word64* DataBuf() {return (word64 *)(void*)m_data();} + + void VHASH_Update_SSE2(const word64 *data, size_t blocksRemainingInWord64, int tagPart); + template + void VHASH_Update_Template(const word64 *data, size_t blockRemainingInWord128); + void VHASH_Update(const word64 *data, size_t blocksRemainingInWord128); + + CRYPTOPP_BLOCK_1(polyState, word64, 4*(m_is128+1)) + CRYPTOPP_BLOCK_2(nhKey, word64, m_L1KeyLength/sizeof(word64) + 2*m_is128) + CRYPTOPP_BLOCK_3(data, byte, m_L1KeyLength) + CRYPTOPP_BLOCK_4(l3Key, word64, 2*(m_is128+1)) + CRYPTOPP_BLOCK_5(nonce, byte, IVSize()) + CRYPTOPP_BLOCK_6(pad, byte, IVSize()) + CRYPTOPP_BLOCKS_END(6) + + bool m_is128, m_padCached, m_isFirstBlock; + unsigned int m_L1KeyLength; +}; + +/// \brief VMAC message authentication code +/// \tparam T_BlockCipher block cipher +/// \tparam T_DigestBitSize digest size, in bits +/// \details VMAC is a block cipher-based message authentication code algorithm +/// using a universal hash proposed by Ted Krovetz and Wei Dai in April 2007. The +/// algorithm was designed for high performance backed by a formal analysis. +/// \details The implementation is based on Ted Krovetz's public domain vmac.c +/// and draft-krovetz-vmac-01.txt. +/// \sa VMAC. +/// \since Crypto++ 5.5 +template +class VMAC : public SimpleKeyingInterfaceImpl > +{ +public: + static std::string StaticAlgorithmName() {return std::string("VMAC(") + T_BlockCipher::StaticAlgorithmName() + ")-" + IntToString(T_DigestBitSize);} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + int DefaultDigestSize() const {return T_DigestBitSize/8;} + typename T_BlockCipher::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/wait.h b/include/cryptlib/wait.h new file mode 100644 index 0000000..8deb0b1 --- /dev/null +++ b/include/cryptlib/wait.h @@ -0,0 +1,235 @@ +// wait.h - originally written and placed in the public domain by Wei Dai + +#ifndef CRYPTOPP_WAIT_H +#define CRYPTOPP_WAIT_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && (defined(SOCKETS_AVAILABLE) || defined(WINDOWS_PIPES_AVAILABLE)) + +#include "cryptlib.h" +#include "misc.h" +#include "stdcpp.h" + +#ifdef USE_WINDOWS_STYLE_SOCKETS +#include +#else +#include +#include +#endif + +// For definitions of VOID, PVOID, HANDLE, PHANDLE, etc. +#if defined(CRYPTOPP_WIN32_AVAILABLE) +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "hrtimer.h" + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define CRYPTOPP_MSAN 1 +# endif +#endif + +// http://connect.microsoft.com/VisualStudio/feedback/details/1581706 +// and http://github.com/weidai11/cryptopp/issues/214 +#if (CRYPTOPP_MSC_VERSION >= 1900) +# pragma warning(push) +# pragma warning(disable: 4589) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +class Tracer +{ +public: + Tracer(unsigned int level) : m_level(level) {} + virtual ~Tracer() {} + +protected: + /// Override this in your most-derived tracer to do the actual tracing. + virtual void Trace(unsigned int n, std::string const& s) = 0; + + /*! By default, tracers will decide which trace messages to trace according to a trace level + mechanism. If your most-derived tracer uses a different mechanism, override this to + return false. If this method returns false, the default TraceXxxx(void) methods will all + return 0 and must be overridden explicitly by your tracer for trace messages you want. */ + virtual bool UsingDefaults() const { return true; } + +protected: + unsigned int m_level; + + void TraceIf(unsigned int n, std::string const&s) + { if (n) Trace(n, s); } + + /*! Returns nr if, according to the default log settings mechanism (using log levels), + the message should be traced. Returns 0 if the default trace level mechanism is not + in use, or if it is in use but the event should not be traced. Provided as a utility + method for easier and shorter coding of default TraceXxxx(void) implementations. */ + unsigned int Tracing(unsigned int nr, unsigned int minLevel) const + { return (UsingDefaults() && m_level >= minLevel) ? nr : 0; } +}; + +// Your Tracer-derived class should inherit as virtual public from Tracer or another +// Tracer-derived class, and should pass the log level in its constructor. You can use the +// following methods to begin and end your Tracer definition. + +// This constructor macro initializes Tracer directly even if not derived directly from it; +// this is intended, virtual base classes are always initialized by the most derived class. +#define CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED) \ + public: DERIVED(unsigned int level = 0) : Tracer(level) {} + +#define CRYPTOPP_BEGIN_TRACER_CLASS_1(DERIVED, BASE1) \ + class DERIVED : virtual public BASE1, public NotCopyable { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED) + +#define CRYPTOPP_BEGIN_TRACER_CLASS_2(DERIVED, BASE1, BASE2) \ + class DERIVED : virtual public BASE1, virtual public BASE2, public NotCopyable { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED) + +#define CRYPTOPP_END_TRACER_CLASS }; + +// In your Tracer-derived class, you should define a globally unique event number for each +// new event defined. This can be done using the following macros. + +#define CRYPTOPP_BEGIN_TRACER_EVENTS(UNIQUENR) enum { EVENTBASE = UNIQUENR, +#define CRYPTOPP_TRACER_EVENT(EVENTNAME) EventNr_##EVENTNAME, +#define CRYPTOPP_END_TRACER_EVENTS }; + +// In your own Tracer-derived class, you must define two methods per new trace event type: +// - unsigned int TraceXxxx() const +// Your default implementation of this method should return the event number if according +// to the default trace level system the event should be traced, or 0 if it should not. +// - void TraceXxxx(string const& s) +// This method should call TraceIf(TraceXxxx(), s); to do the tracing. +// For your convenience, a macro to define these two types of methods are defined below. +// If you use this macro, you should also use the TRACER_EVENTS macros above to associate +// event names with numbers. + +#define CRYPTOPP_TRACER_EVENT_METHODS(EVENTNAME, LOGLEVEL) \ + virtual unsigned int Trace##EVENTNAME() const { return Tracing(EventNr_##EVENTNAME, LOGLEVEL); } \ + virtual void Trace##EVENTNAME(std::string const& s) { TraceIf(Trace##EVENTNAME(), s); } + + +/*! A simple unidirectional linked list with m_prev == 0 to indicate the final entry. + The aim of this implementation is to provide a very lightweight and practical + tracing mechanism with a low performance impact. Functions and methods supporting + this call-stack mechanism would take a parameter of the form "CallStack const& callStack", + and would pass this parameter to subsequent functions they call using the construct: + + SubFunc(arg1, arg2, CallStack("my func at place such and such", &callStack)); + + The advantage of this approach is that it is easy to use and should be very efficient, + involving no allocation from the heap, just a linked list of stack objects containing + pointers to static ASCIIZ strings (or possibly additional but simple data if derived). */ +class CallStack +{ +public: + CallStack(char const* i, CallStack const* p) : m_info(i), m_prev(p) {} + CallStack const* Prev() const { return m_prev; } + virtual std::string Format() const; + +protected: + char const* m_info; + CallStack const* m_prev; +}; + +/*! An extended CallStack entry type with an additional numeric parameter. */ +class CallStackWithNr : public CallStack +{ +public: + CallStackWithNr(char const* i, word32 n, CallStack const* p) : CallStack(i, p), m_nr(n) {} + std::string Format() const; + +protected: + word32 m_nr; +}; + +/*! An extended CallStack entry type with an additional string parameter. */ +class CallStackWithStr : public CallStack +{ +public: + CallStackWithStr(char const* i, char const* z, CallStack const* p) : CallStack(i, p), m_z(z) {} + std::string Format() const; + +protected: + char const* m_z; +}; + +// Thanks to Maximilian Zamorsky for help with http://connect.microsoft.com/VisualStudio/feedback/details/1570496/ +CRYPTOPP_BEGIN_TRACER_CLASS_1(WaitObjectsTracer, Tracer) + CRYPTOPP_BEGIN_TRACER_EVENTS(0x48752841) + CRYPTOPP_TRACER_EVENT(NoWaitLoop) + CRYPTOPP_END_TRACER_EVENTS + CRYPTOPP_TRACER_EVENT_METHODS(NoWaitLoop, 1) +CRYPTOPP_END_TRACER_CLASS + +struct WaitingThreadData; + +/// container of wait objects +class WaitObjectContainer : public NotCopyable +{ +public: + /// exception thrown by WaitObjectContainer + class Err : public Exception + { + public: + Err(const std::string& s) : Exception(IO_ERROR, s) {} + }; + + static unsigned int MaxWaitObjects(); + + WaitObjectContainer(WaitObjectsTracer* tracer = NULLPTR); + + void Clear(); + void SetNoWait(CallStack const& callStack); + void ScheduleEvent(double milliseconds, CallStack const& callStack); + // returns false if timed out + bool Wait(unsigned long milliseconds); + +#ifdef USE_WINDOWS_STYLE_SOCKETS + virtual ~WaitObjectContainer(); + void AddHandle(HANDLE handle, CallStack const& callStack); +#else + void AddReadFd(int fd, CallStack const& callStack); + void AddWriteFd(int fd, CallStack const& callStack); +#endif + +private: + WaitObjectsTracer* m_tracer; + +#ifdef USE_WINDOWS_STYLE_SOCKETS + void CreateThreads(unsigned int count); + std::vector m_handles; + std::vector m_threads; + HANDLE m_startWaiting; + HANDLE m_stopWaiting; +#else + fd_set m_readfds, m_writefds; + int m_maxFd; +#endif + double m_firstEventTime; + Timer m_eventTimer; + bool m_noWait; + +#ifdef USE_WINDOWS_STYLE_SOCKETS + typedef size_t LastResultType; +#else + typedef int LastResultType; +#endif + enum { LASTRESULT_NOWAIT = -1, LASTRESULT_SCHEDULED = -2, LASTRESULT_TIMEOUT = -3 }; + LastResultType m_lastResult; + unsigned int m_sameResultCount; + Timer m_noWaitTimer; + void SetLastResult(LastResultType result); + void DetectNoWait(LastResultType result, CallStack const& callStack); +}; + +NAMESPACE_END + +#if (CRYPTOPP_MSC_VERSION >= 1900) +# pragma warning(pop) +#endif + +#endif // NO_OS_DEPENDENCE + +#endif // CRYPTOPP_WAIT_H diff --git a/include/cryptlib/wake.h b/include/cryptlib/wake.h new file mode 100644 index 0000000..2b62023 --- /dev/null +++ b/include/cryptlib/wake.h @@ -0,0 +1,75 @@ +// wake.h - originally written and placed in the public domain by Wei Dai + +/// \file wake.h +/// \brief Classes for WAKE stream cipher + +#ifndef CRYPTOPP_WAKE_H +#define CRYPTOPP_WAKE_H + +#include "seckey.h" +#include "secblock.h" +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief WAKE stream cipher information +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +struct WAKE_OFB_Info : public FixedKeyLength<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "WAKE-OFB-LE" : "WAKE-OFB-BE";} +}; + +class CRYPTOPP_NO_VTABLE WAKE_Base +{ +protected: + word32 M(word32 x, word32 y); + void GenKey(word32 k0, word32 k1, word32 k2, word32 k3); + + word32 t[257]; + word32 r3, r4, r5, r6; +}; + +/// \brief WAKE stream cipher operation +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +class CRYPTOPP_NO_VTABLE WAKE_Policy : public AdditiveCipherConcretePolicy, protected WAKE_Base +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + // OFB + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CipherIsRandomAccess() const {return false;} +}; + +/// \brief WAKE stream cipher +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +struct WAKE_OFB : public WAKE_OFB_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, WAKE_OFB_Info > Encryption; + typedef Encryption Decryption; +}; + +/* +template +class WAKE_ROFB_Policy : public WAKE_Policy +{ +protected: + void Iterate(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount); +}; + +template +struct WAKE_ROFB : public WAKE_Info +{ + typedef SymmetricCipherTemplate, WAKE_ROFB_Policy > > Encryption; + typedef Encryption Decryption; +}; +*/ + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/whrlpool.h b/include/cryptlib/whrlpool.h new file mode 100644 index 0000000..737b72a --- /dev/null +++ b/include/cryptlib/whrlpool.h @@ -0,0 +1,34 @@ +// whrlpool.h - originally modified by Kevin Springle from Paulo Barreto and Vincent Rijmen's +// public domain code, whirlpool.c. Updated to Whirlpool version 3.0, optimized +// and SSE version added by WD. All modifications are placed in the public domain. + +#ifndef CRYPTOPP_WHIRLPOOL_H +#define CRYPTOPP_WHIRLPOOL_H + +/// \file whrlpool.h +/// \brief Classes for the Whirlpool message digest +/// \details Crypto++ provides version 3.0 of the Whirlpool algorithm. +/// This version of the algorithm was submitted for ISO standardization. + +#include "config.h" +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Whirlpool message digest +/// \details Crypto++ provides version 3.0 of the Whirlpool algorithm. +/// This version of the algorithm was submitted for ISO standardization. +/// \since Crypto++ 5.2 +/// \sa Whirlpool +class Whirlpool : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word64 *digest, const word64 *data); + void TruncatedFinal(byte *hash, size_t size); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Whirlpool";} +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/winpipes.h b/include/cryptlib/winpipes.h new file mode 100644 index 0000000..5fcf376 --- /dev/null +++ b/include/cryptlib/winpipes.h @@ -0,0 +1,146 @@ +#ifndef CRYPTOPP_WINPIPES_H +#define CRYPTOPP_WINPIPES_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(WINDOWS_PIPES_AVAILABLE) + +#include "cryptlib.h" +#include "network.h" +#include "queue.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Windows Handle +class WindowsHandle +{ +public: + virtual ~WindowsHandle(); + + WindowsHandle(HANDLE h = INVALID_HANDLE_VALUE, bool own=false); + WindowsHandle(const WindowsHandle &h) : m_h(h.m_h), m_own(false) {} + + bool GetOwnership() const {return m_own;} + void SetOwnership(bool own) {m_own = own;} + + operator HANDLE() const {return m_h;} + HANDLE GetHandle() const {return m_h;} + bool HandleValid() const; + void AttachHandle(HANDLE h, bool own=false); + HANDLE DetachHandle(); + void CloseHandle(); + +protected: + virtual void HandleChanged() {} + + HANDLE m_h; + bool m_own; +}; + +/// \brief Windows Pipe +class WindowsPipe +{ +public: + class Err : public OS_Error + { + public: + Err(HANDLE h, const std::string& operation, int error); + HANDLE GetHandle() const {return m_h;} + + private: + HANDLE m_h; + }; + +protected: + virtual HANDLE GetHandle() const =0; + virtual void HandleError(const char *operation) const; + void CheckAndHandleError(const char *operation, BOOL result) const + {if (!result) HandleError(operation);} +}; + +/// \brief Pipe-based implementation of NetworkReceiver +class WindowsPipeReceiver : public WindowsPipe, public NetworkReceiver +{ +public: + WindowsPipeReceiver(); + + bool MustWaitForResult() {return true;} + bool Receive(byte* buf, size_t bufLen); + unsigned int GetReceiveResult(); + bool EofReceived() const {return m_eofReceived;} + + HANDLE GetHandle() const {return m_event;} + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + +private: + WindowsHandle m_event; + OVERLAPPED m_overlapped; + DWORD m_lastResult; + bool m_resultPending; + bool m_eofReceived; +}; + +/// \brief Pipe-based implementation of NetworkSender +class WindowsPipeSender : public WindowsPipe, public NetworkSender +{ +public: + WindowsPipeSender(); + + bool MustWaitForResult() {return true;} + void Send(const byte* buf, size_t bufLen); + unsigned int GetSendResult(); + bool MustWaitForEof() { return false; } + void SendEof() {} + + HANDLE GetHandle() const {return m_event;} + unsigned int GetMaxWaitObjectCount() const {return 1;} + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + +private: + WindowsHandle m_event; + OVERLAPPED m_overlapped; + DWORD m_lastResult; + bool m_resultPending; +}; + +/// \brief Windows Pipe Source +class WindowsPipeSource : public WindowsHandle, public NetworkSource, public WindowsPipeReceiver +{ +public: + WindowsPipeSource(HANDLE h=INVALID_HANDLE_VALUE, bool pumpAll=false, BufferedTransformation *attachment=NULLPTR) + : WindowsHandle(h), NetworkSource(attachment) + { + if (pumpAll) + PumpAll(); + } + + using NetworkSource::GetMaxWaitObjectCount; + using NetworkSource::GetWaitObjects; + +private: + HANDLE GetHandle() const {return WindowsHandle::GetHandle();} + NetworkReceiver & AccessReceiver() {return *this;} +}; + +/// \brief Windows Pipe Sink +class WindowsPipeSink : public WindowsHandle, public NetworkSink, public WindowsPipeSender +{ +public: + WindowsPipeSink(HANDLE h=INVALID_HANDLE_VALUE, unsigned int maxBufferSize=0, unsigned int autoFlushBound=16*1024) + : WindowsHandle(h), NetworkSink(maxBufferSize, autoFlushBound) {} + + using NetworkSink::GetMaxWaitObjectCount; + using NetworkSink::GetWaitObjects; + +private: + HANDLE GetHandle() const {return WindowsHandle::GetHandle();} + NetworkSender & AccessSender() {return *this;} +}; + +NAMESPACE_END + +#endif // WINDOWS_PIPES_AVAILABLE + +#endif diff --git a/include/cryptlib/words.h b/include/cryptlib/words.h new file mode 100644 index 0000000..1880dce --- /dev/null +++ b/include/cryptlib/words.h @@ -0,0 +1,120 @@ +#ifndef CRYPTOPP_WORDS_H +#define CRYPTOPP_WORDS_H + +#include "config.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +inline size_t CountWords(const word *X, size_t N) +{ + while (N && X[N-1]==0) + N--; + return N; +} + +inline void SetWords(word *r, word a, size_t n) +{ + for (size_t i=0; i> (WORD_BITS-shiftBits); + } + return carry; +} + +inline word ShiftWordsRightByBits(word *r, size_t n, unsigned int shiftBits) +{ + CRYPTOPP_ASSERT (shiftBits0; i--) + { + u = r[i-1]; + r[i-1] = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + } + return carry; +} + +inline void ShiftWordsLeftByWords(word *r, size_t n, size_t shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (size_t i=n-1; i>=shiftWords; i--) + r[i] = r[i-shiftWords]; + SetWords(r, 0, shiftWords); + } +} + +inline void ShiftWordsRightByWords(word *r, size_t n, size_t shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (size_t i=0; i+shiftWords +class GFP2_ONB : public AbstractRing +{ +public: + typedef F BaseField; + + GFP2_ONB(const Integer &p) : modp(p) + { + if (p%3 != 2) + throw InvalidArgument("GFP2_ONB: modulus must be equivalent to 2 mod 3"); + } + + const Integer& GetModulus() const {return modp.GetModulus();} + + GFP2Element ConvertIn(const Integer &a) const + { + t = modp.Inverse(modp.ConvertIn(a)); + return GFP2Element(t, t); + } + + GFP2Element ConvertIn(const GFP2Element &a) const + {return GFP2Element(modp.ConvertIn(a.c1), modp.ConvertIn(a.c2));} + + GFP2Element ConvertOut(const GFP2Element &a) const + {return GFP2Element(modp.ConvertOut(a.c1), modp.ConvertOut(a.c2));} + + bool Equal(const GFP2Element &a, const GFP2Element &b) const + { + return modp.Equal(a.c1, b.c1) && modp.Equal(a.c2, b.c2); + } + + const Element& Identity() const + { + return GFP2Element::Zero(); + } + + const Element& Add(const Element &a, const Element &b) const + { + result.c1 = modp.Add(a.c1, b.c1); + result.c2 = modp.Add(a.c2, b.c2); + return result; + } + + const Element& Inverse(const Element &a) const + { + result.c1 = modp.Inverse(a.c1); + result.c2 = modp.Inverse(a.c2); + return result; + } + + const Element& Double(const Element &a) const + { + result.c1 = modp.Double(a.c1); + result.c2 = modp.Double(a.c2); + return result; + } + + const Element& Subtract(const Element &a, const Element &b) const + { + result.c1 = modp.Subtract(a.c1, b.c1); + result.c2 = modp.Subtract(a.c2, b.c2); + return result; + } + + Element& Accumulate(Element &a, const Element &b) const + { + modp.Accumulate(a.c1, b.c1); + modp.Accumulate(a.c2, b.c2); + return a; + } + + Element& Reduce(Element &a, const Element &b) const + { + modp.Reduce(a.c1, b.c1); + modp.Reduce(a.c2, b.c2); + return a; + } + + bool IsUnit(const Element &a) const + { + return a.c1.NotZero() || a.c2.NotZero(); + } + + const Element& MultiplicativeIdentity() const + { + result.c1 = result.c2 = modp.Inverse(modp.MultiplicativeIdentity()); + return result; + } + + const Element& Multiply(const Element &a, const Element &b) const + { + t = modp.Add(a.c1, a.c2); + t = modp.Multiply(t, modp.Add(b.c1, b.c2)); + result.c1 = modp.Multiply(a.c1, b.c1); + result.c2 = modp.Multiply(a.c2, b.c2); + result.c1.swap(result.c2); + modp.Reduce(t, result.c1); + modp.Reduce(t, result.c2); + modp.Reduce(result.c1, t); + modp.Reduce(result.c2, t); + return result; + } + + const Element& MultiplicativeInverse(const Element &a) const + { + return result = Exponentiate(a, modp.GetModulus()-2); + } + + const Element& Square(const Element &a) const + { + const Integer &ac1 = (&a == &result) ? (t = a.c1) : a.c1; + result.c1 = modp.Multiply(modp.Subtract(modp.Subtract(a.c2, a.c1), a.c1), a.c2); + result.c2 = modp.Multiply(modp.Subtract(modp.Subtract(ac1, a.c2), a.c2), ac1); + return result; + } + + Element Exponentiate(const Element &a, const Integer &e) const + { + Integer edivp, emodp; + Integer::Divide(emodp, edivp, e, modp.GetModulus()); + Element b = PthPower(a); + return AbstractRing::CascadeExponentiate(a, emodp, b, edivp); + } + + const Element & PthPower(const Element &a) const + { + result = a; + result.c1.swap(result.c2); + return result; + } + + void RaiseToPthPower(Element &a) const + { + a.c1.swap(a.c2); + } + + // a^2 - 2a^p + const Element & SpecialOperation1(const Element &a) const + { + CRYPTOPP_ASSERT(&a != &result); + result = Square(a); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c2, a.c1); + modp.Reduce(result.c2, a.c1); + return result; + } + + // x * z - y * z^p + const Element & SpecialOperation2(const Element &x, const Element &y, const Element &z) const + { + CRYPTOPP_ASSERT(&x != &result && &y != &result && &z != &result); + t = modp.Add(x.c2, y.c2); + result.c1 = modp.Multiply(z.c1, modp.Subtract(y.c1, t)); + modp.Accumulate(result.c1, modp.Multiply(z.c2, modp.Subtract(t, x.c1))); + t = modp.Add(x.c1, y.c1); + result.c2 = modp.Multiply(z.c2, modp.Subtract(y.c2, t)); + modp.Accumulate(result.c2, modp.Multiply(z.c1, modp.Subtract(t, x.c2))); + return result; + } + +protected: + BaseField modp; + mutable GFP2Element result; + mutable Integer t; +}; + +/// \brief Creates primes p,q and generator g for XTR +void XTR_FindPrimesAndGenerator(RandomNumberGenerator &rng, Integer &p, Integer &q, GFP2Element &g, unsigned int pbits, unsigned int qbits); + +GFP2Element XTR_Exponentiate(const GFP2Element &b, const Integer &e, const Integer &p); + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/xtrcrypt.h b/include/cryptlib/xtrcrypt.h new file mode 100644 index 0000000..0248788 --- /dev/null +++ b/include/cryptlib/xtrcrypt.h @@ -0,0 +1,55 @@ +#ifndef CRYPTOPP_XTRCRYPT_H +#define CRYPTOPP_XTRCRYPT_H + +/// \file +/// \brief XTR public key system +/// \sa "The XTR public key system" by Arjen K. Lenstra and Eric R. Verheul + +#include "cryptlib.h" +#include "xtr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief XTR-DH with key validation +class XTR_DH : public SimpleKeyAgreementDomain, public CryptoParameters +{ + typedef XTR_DH ThisClass; + +public: + XTR_DH(const Integer &p, const Integer &q, const GFP2Element &g); + XTR_DH(RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits); + XTR_DH(BufferedTransformation &domainParams); + + void DEREncode(BufferedTransformation &domainParams) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + CryptoParameters & AccessCryptoParameters() {return *this;} + unsigned int AgreedValueLength() const {return 2*m_p.ByteCount();} + unsigned int PrivateKeyLength() const {return m_q.ByteCount();} + unsigned int PublicKeyLength() const {return 2*m_p.ByteCount();} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const; + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const; + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const; + + const Integer &GetModulus() const {return m_p;} + const Integer &GetSubgroupOrder() const {return m_q;} + const GFP2Element &GetSubgroupGenerator() const {return m_g;} + + void SetModulus(const Integer &p) {m_p = p;} + void SetSubgroupOrder(const Integer &q) {m_q = q;} + void SetSubgroupGenerator(const GFP2Element &g) {m_g = g;} + +private: + unsigned int ExponentBitLength() const; + + Integer m_p, m_q; + GFP2Element m_g; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/zdeflate.h b/include/cryptlib/zdeflate.h new file mode 100644 index 0000000..a64a6e6 --- /dev/null +++ b/include/cryptlib/zdeflate.h @@ -0,0 +1,174 @@ +// zdeflate.h - originally written and placed in the public domain by Wei Dai + +/// \file zdeflate.h +/// \brief DEFLATE compression and decompression (RFC 1951) + +#ifndef CRYPTOPP_ZDEFLATE_H +#define CRYPTOPP_ZDEFLATE_H + +#include "cryptlib.h" +#include "filters.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Encoding table writer +/// \since Crypto++ 1.0 +class LowFirstBitWriter : public Filter +{ +public: + /// \brief Construct a LowFirstBitWriter + /// \param attachment an attached transformation + LowFirstBitWriter(BufferedTransformation *attachment); + + void PutBits(unsigned long value, unsigned int length); + void FlushBitBuffer(); + void ClearBitBuffer(); + + void StartCounting(); + unsigned long FinishCounting(); + +protected: + bool m_counting; + unsigned long m_bitCount; + unsigned long m_buffer; + unsigned int m_bitsBuffered, m_bytesBuffered; + FixedSizeSecBlock m_outputBuffer; +}; + +/// \brief Huffman Encoder +/// \since Crypto++ 1.0 +class HuffmanEncoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + + /// \brief Construct a HuffmanEncoder + HuffmanEncoder() {} + + /// \brief Construct a HuffmanEncoder + /// \param codeBits a table of code bits + /// \param nCodes the number of codes in the table + HuffmanEncoder(const unsigned int *codeBits, unsigned int nCodes); + + /// \brief Initialize or reinitialize this object + /// \param codeBits a table of code bits + /// \param nCodes the number of codes in the table + void Initialize(const unsigned int *codeBits, unsigned int nCodes); + + static void GenerateCodeLengths(unsigned int *codeBits, unsigned int maxCodeBits, const unsigned int *codeCounts, size_t nCodes); + + void Encode(LowFirstBitWriter &writer, value_t value) const; + + struct Code + { + unsigned int code; + unsigned int len; + }; + + SecBlock m_valueToCode; +}; + +/// \brief DEFLATE compressor (RFC 1951) +/// \since Crypto++ 1.0 +class Deflator : public LowFirstBitWriter +{ +public: + /// \brief Deflate level as enumerated values. + enum { + /// \brief Minimum deflation level, fastest speed (0) + MIN_DEFLATE_LEVEL = 0, + /// \brief Default deflation level, compromise between speed (6) + DEFAULT_DEFLATE_LEVEL = 6, + /// \brief Minimum deflation level, slowest speed (9) + MAX_DEFLATE_LEVEL = 9}; + + /// \brief Windows size as enumerated values. + enum { + /// \brief Minimum window size, smallest table (9) + MIN_LOG2_WINDOW_SIZE = 9, + /// \brief Default window size (15) + DEFAULT_LOG2_WINDOW_SIZE = 15, + /// \brief Maximum window size, largest table (15) + MAX_LOG2_WINDOW_SIZE = 15}; + + /// \brief Construct a Deflator compressor + /// \param attachment an attached transformation + /// \param deflateLevel the deflate level + /// \param log2WindowSize the window size + /// \param detectUncompressible flag to detect if data is compressible + /// \details detectUncompressible makes it faster to process uncompressible files, but + /// if a file has both compressible and uncompressible parts, it may fail to compress + /// some of the compressible parts. + Deflator(BufferedTransformation *attachment=NULLPTR, int deflateLevel=DEFAULT_DEFLATE_LEVEL, int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true); + /// \brief Construct a Deflator compressor + /// \param parameters a set of NameValuePairs to initialize this object + /// \param attachment an attached transformation + /// \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible + Deflator(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR); + + /// \brief Sets the deflation level + /// \param deflateLevel the level of deflation + /// \details SetDeflateLevel can be used to set the deflate level in the middle of compression + void SetDeflateLevel(int deflateLevel); + + /// \brief Retrieves the deflation level + /// \returns the level of deflation + int GetDeflateLevel() const {return m_deflateLevel;} + + /// \brief Retrieves the window size + /// \returns the windows size + int GetLog2WindowSize() const {return m_log2WindowSize;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +protected: + virtual void WritePrestreamHeader() {} + virtual void ProcessUncompressedData(const byte *string, size_t length) + {CRYPTOPP_UNUSED(string), CRYPTOPP_UNUSED(length);} + virtual void WritePoststreamTail() {} + + enum {STORED = 0, STATIC = 1, DYNAMIC = 2}; + enum {MIN_MATCH = 3, MAX_MATCH = 258}; + + void InitializeStaticEncoders(); + void Reset(bool forceReset = false); + unsigned int FillWindow(const byte *str, size_t length); + unsigned int ComputeHash(const byte *str) const; + unsigned int LongestMatch(unsigned int &bestMatch) const; + void InsertString(unsigned int start); + void ProcessBuffer(); + + void LiteralByte(byte b); + void MatchFound(unsigned int distance, unsigned int length); + void EncodeBlock(bool eof, unsigned int blockType); + void EndBlock(bool eof); + + struct EncodedMatch + { + unsigned literalCode : 9; + unsigned literalExtra : 5; + unsigned distanceCode : 5; + unsigned distanceExtra : 13; + }; + + int m_deflateLevel, m_log2WindowSize, m_compressibleDeflateLevel; + unsigned int m_detectSkip, m_detectCount; + unsigned int DSIZE, DMASK, HSIZE, HMASK, GOOD_MATCH, MAX_LAZYLENGTH, MAX_CHAIN_LENGTH; + bool m_headerWritten, m_matchAvailable; + unsigned int m_dictionaryEnd, m_stringStart, m_lookahead, m_minLookahead, m_previousMatch, m_previousLength; + HuffmanEncoder m_staticLiteralEncoder, m_staticDistanceEncoder, m_dynamicLiteralEncoder, m_dynamicDistanceEncoder; + SecByteBlock m_byteBuffer; + SecBlock m_head, m_prev; + FixedSizeSecBlock m_literalCounts; + FixedSizeSecBlock m_distanceCounts; + SecBlock m_matchBuffer; + unsigned int m_matchBufferEnd, m_blockStart, m_blockLength; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/zinflate.h b/include/cryptlib/zinflate.h new file mode 100644 index 0000000..6707952 --- /dev/null +++ b/include/cryptlib/zinflate.h @@ -0,0 +1,159 @@ +#ifndef CRYPTOPP_ZINFLATE_H +#define CRYPTOPP_ZINFLATE_H + +#include "cryptlib.h" +#include "secblock.h" +#include "filters.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \since Crypto++ 1.0 +class LowFirstBitReader +{ +public: + LowFirstBitReader(BufferedTransformation &store) + : m_store(store), m_buffer(0), m_bitsBuffered(0) {} + unsigned int BitsBuffered() const {return m_bitsBuffered;} + unsigned long PeekBuffer() const {return m_buffer;} + bool FillBuffer(unsigned int length); + unsigned long PeekBits(unsigned int length); + void SkipBits(unsigned int length); + unsigned long GetBits(unsigned int length); + +private: + BufferedTransformation &m_store; + unsigned long m_buffer; + unsigned int m_bitsBuffered; +}; + +struct CodeLessThan; + +/// \brief Huffman Decoder +/// \since Crypto++ 1.0 +class HuffmanDecoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + enum {MAX_CODE_BITS = sizeof(code_t)*8}; + + class Err : public Exception {public: Err(const std::string &what) : Exception(INVALID_DATA_FORMAT, "HuffmanDecoder: " + what) {}}; + + HuffmanDecoder() : m_maxCodeBits(0), m_cacheBits(0), m_cacheMask(0), m_normalizedCacheMask(0) {} + HuffmanDecoder(const unsigned int *codeBitLengths, unsigned int nCodes) + : m_maxCodeBits(0), m_cacheBits(0), m_cacheMask(0), m_normalizedCacheMask(0) + {Initialize(codeBitLengths, nCodes);} + + void Initialize(const unsigned int *codeBitLengths, unsigned int nCodes); + unsigned int Decode(code_t code, /* out */ value_t &value) const; + bool Decode(LowFirstBitReader &reader, value_t &value) const; + +private: + friend struct CodeLessThan; + + struct CodeInfo + { + CodeInfo(code_t code=0, unsigned int len=0, value_t value=0) : code(code), len(len), value(value) {} + inline bool operator<(const CodeInfo &rhs) const {return code < rhs.code;} + code_t code; + unsigned int len; + value_t value; + }; + + struct LookupEntry + { + unsigned int type; + union + { + value_t value; + const CodeInfo *begin; + }; + union + { + unsigned int len; + const CodeInfo *end; + }; + }; + + static code_t NormalizeCode(code_t code, unsigned int codeBits); + void FillCacheEntry(LookupEntry &entry, code_t normalizedCode) const; + + unsigned int m_maxCodeBits, m_cacheBits, m_cacheMask, m_normalizedCacheMask; + std::vector > m_codeToValue; + mutable std::vector > m_cache; +}; + +/// \brief DEFLATE decompressor (RFC 1951) +/// \since Crypto++ 1.0 +class Inflator : public AutoSignaling +{ +public: + class Err : public Exception + { + public: + Err(ErrorType e, const std::string &s) + : Exception(e, s) {} + }; + /// \brief Exception thrown when a truncated stream is encountered + class UnexpectedEndErr : public Err {public: UnexpectedEndErr() : Err(INVALID_DATA_FORMAT, "Inflator: unexpected end of compressed block") {}}; + /// \brief Exception thrown when a bad block is encountered + class BadBlockErr : public Err {public: BadBlockErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in compressed block") {}}; + /// \brief Exception thrown when an invalid distance is encountered + class BadDistanceErr : public Err {public: BadDistanceErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in bit distance") {}}; + + /// \brief RFC 1951 Decompressor + /// \param attachment the filter's attached transformation + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + Inflator(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + + virtual unsigned int GetLog2WindowSize() const {return 15;} + +protected: + ByteQueue m_inQueue; + +private: + virtual unsigned int MaxPrestreamHeaderSize() const {return 0;} + virtual void ProcessPrestreamHeader() {} + virtual void ProcessDecompressedData(const byte *string, size_t length) + {AttachedTransformation()->Put(string, length);} + virtual unsigned int MaxPoststreamTailSize() const {return 0;} + virtual void ProcessPoststreamTail() {} + + void ProcessInput(bool flush); + void DecodeHeader(); + bool DecodeBody(); + void FlushOutput(); + void OutputByte(byte b); + void OutputString(const byte *string, size_t length); + void OutputPast(unsigned int length, unsigned int distance); + + void CreateFixedDistanceDecoder(); + void CreateFixedLiteralDecoder(); + + const HuffmanDecoder& GetLiteralDecoder(); + const HuffmanDecoder& GetDistanceDecoder(); + + enum State {PRE_STREAM, WAIT_HEADER, DECODING_BODY, POST_STREAM, AFTER_END}; + State m_state; + bool m_repeat, m_eof, m_wrappedAround; + byte m_blockType; + word16 m_storedLen; + enum NextDecode {LITERAL, LENGTH_BITS, DISTANCE, DISTANCE_BITS}; + NextDecode m_nextDecode; + unsigned int m_literal, m_distance; // for LENGTH_BITS or DISTANCE_BITS + HuffmanDecoder m_dynamicLiteralDecoder, m_dynamicDistanceDecoder; + member_ptr m_fixedLiteralDecoder, m_fixedDistanceDecoder; + LowFirstBitReader m_reader; + SecByteBlock m_window; + size_t m_current, m_lastFlush; +}; + +NAMESPACE_END + +#endif diff --git a/include/cryptlib/zlib.h b/include/cryptlib/zlib.h new file mode 100644 index 0000000..8c635cf --- /dev/null +++ b/include/cryptlib/zlib.h @@ -0,0 +1,60 @@ +#ifndef CRYPTOPP_ZLIB_H +#define CRYPTOPP_ZLIB_H + +#include "cryptlib.h" +#include "adler32.h" +#include "zdeflate.h" +#include "zinflate.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ZLIB Compressor (RFC 1950) +class ZlibCompressor : public Deflator +{ +public: + ZlibCompressor(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible) {} + ZlibCompressor(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) + : Deflator(parameters, attachment) {} + + unsigned int GetCompressionLevel() const; + +protected: + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, size_t length); + void WritePoststreamTail(); + + Adler32 m_adler32; +}; + +/// ZLIB Decompressor (RFC 1950) +class ZlibDecompressor : public Inflator +{ +public: + typedef Inflator::Err Err; + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: header decoding error") {}}; + class Adler32Err : public Err {public: Adler32Err() : Err(DATA_INTEGRITY_CHECK_FAILED, "ZlibDecompressor: ADLER32 check error") {}}; + class UnsupportedAlgorithm : public Err {public: UnsupportedAlgorithm() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported algorithm") {}}; + class UnsupportedPresetDictionary : public Err {public: UnsupportedPresetDictionary() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported preset dictionary") {}}; + + /// \brief Construct a ZlibDecompressor + /// \param attachment a \ BufferedTransformation to attach to this object + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + ZlibDecompressor(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + unsigned int GetLog2WindowSize() const {return m_log2WindowSize;} + +private: + unsigned int MaxPrestreamHeaderSize() const {return 2;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, size_t length); + unsigned int MaxPoststreamTailSize() const {return 4;} + void ProcessPoststreamTail(); + + unsigned int m_log2WindowSize; + Adler32 m_adler32; +}; + +NAMESPACE_END + +#endif diff --git a/include/mysql/CMakeLists.txt b/include/mysql/CMakeLists.txt new file mode 100644 index 0000000..1fca99e --- /dev/null +++ b/include/mysql/CMakeLists.txt @@ -0,0 +1,40 @@ +SET(MARIADB_CLIENT_INCLUDES ${CC_SOURCE_DIR}/include/mariadb_com.h + ${CC_SOURCE_DIR}/include/mysql.h + ${CC_SOURCE_DIR}/include/mariadb_stmt.h + ${CC_SOURCE_DIR}/include/ma_pvio.h + ${CC_SOURCE_DIR}/include/ma_tls.h + ${CC_BINARY_DIR}/include/mariadb_version.h + ${CC_SOURCE_DIR}/include/ma_list.h + ${CC_SOURCE_DIR}/include/errmsg.h + ${CC_SOURCE_DIR}/include/mariadb_dyncol.h + ${CC_SOURCE_DIR}/include/mariadb_ctype.h + ) +IF(NOT IS_SUBPROJECT) + SET(MARIADB_CLIENT_INCLUDES ${MARIADB_CLIENT_INCLUDES} + ${CC_SOURCE_DIR}/include/mysqld_error.h + ) +ENDIF() +SET(MYSQL_ADDITIONAL_INCLUDES + ${CC_SOURCE_DIR}/include/mysql/client_plugin.h + ${CC_SOURCE_DIR}/include/mysql/plugin_auth_common.h + ${CC_SOURCE_DIR}/include/mysql/plugin_auth.h + ) +SET(MARIADB_ADDITIONAL_INCLUDES + ${CC_SOURCE_DIR}/include/mariadb/ma_io.h + ) +IF(WIN32) + SET(WIX_INCLUDES ${MARIADB_CLIENT_INCLUDES} ${MARIADB_ADDITIONAL_INCLUDES} ${MYSQL_ADDITIONAL_INCLUDES} PARENT_SCOPE) +ENDIF() + +INSTALL(FILES + ${MARIADB_CLIENT_INCLUDES} + DESTINATION ${INSTALL_INCLUDEDIR} + COMPONENT Development) +INSTALL(FILES + ${MYSQL_ADDITIONAL_INCLUDES} + DESTINATION ${INSTALL_INCLUDEDIR}/mysql + COMPONENT Development) +INSTALL(FILES + ${MARIADB_ADDITIONAL_INCLUDES} + DESTINATION ${INSTALL_INCLUDEDIR}/mariadb + COMPONENT Development) diff --git a/include/mysql/errmsg.h b/include/mysql/errmsg.h index 16e30f1..481b0a6 100644 --- a/include/mysql/errmsg.h +++ b/include/mysql/errmsg.h @@ -1,4 +1,5 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + 2012-2016 SkySQL AB, MariaDB Corporation AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -25,34 +26,35 @@ extern "C" { #endif void init_client_errs(void); extern const char *client_errors[]; /* Error messages */ +extern const char *mariadb_client_errors[]; /* Error messages */ #ifdef __cplusplus } #endif + #define CR_MIN_ERROR 2000 /* For easier client code */ #define CR_MAX_ERROR 2999 -#if defined(OS2) && defined( MYSQL_SERVER) -#define CER(X) client_errors[(X)-CR_MIN_ERROR] -#else +#define CER_MIN_ERROR 5000 +#define CER_MAX_ERROR 5999 +#define CER(X) mariadb_client_errors[(X)-CER_MIN_ERROR] #define ER(X) client_errors[(X)-CR_MIN_ERROR] -#endif -#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */ +#define CLIENT_ERRMAP 2 /* Errormap used by ma_error() */ #define CR_UNKNOWN_ERROR 2000 #define CR_SOCKET_CREATE_ERROR 2001 #define CR_CONNECTION_ERROR 2002 -#define CR_CONN_HOST_ERROR 2003 +#define CR_CONN_HOST_ERROR 2003 /* never sent to a client, message only */ #define CR_IPSOCK_ERROR 2004 #define CR_UNKNOWN_HOST 2005 -#define CR_SERVER_GONE_ERROR 2006 +#define CR_SERVER_GONE_ERROR 2006 /* disappeared _between_ queries */ #define CR_VERSION_ERROR 2007 #define CR_OUT_OF_MEMORY 2008 #define CR_WRONG_HOST_INFO 2009 #define CR_LOCALHOST_CONNECTION 2010 #define CR_TCP_CONNECTION 2011 #define CR_SERVER_HANDSHAKE_ERR 2012 -#define CR_SERVER_LOST 2013 +#define CR_SERVER_LOST 2013 /* disappeared _during_ a query */ #define CR_COMMANDS_OUT_OF_SYNC 2014 #define CR_NAMEDPIPE_CONNECTION 2015 #define CR_NAMEDPIPEWAIT_ERROR 2016 @@ -65,17 +67,40 @@ extern const char *client_errors[]; /* Error messages */ #define CR_NO_PREPARE_STMT 2030 #define CR_PARAMS_NOT_BOUND 2031 #define CR_INVALID_PARAMETER_NO 2034 +#define CR_INVALID_BUFFER_USE 2035 #define CR_UNSUPPORTED_PARAM_TYPE 2036 + +#define CR_SHARED_MEMORY_CONNECTION 2037 +#define CR_SHARED_MEMORY_CONNECT_ERROR 2038 + +#define CR_CONN_UNKNOWN_PROTOCOL 2047 #define CR_SECURE_AUTH 2049 #define CR_NO_DATA 2051 #define CR_NO_STMT_METADATA 2052 #define CR_NOT_IMPLEMENTED 2054 -#define CR_SERVER_LOST_EXTENDED 2055 +#define CR_SERVER_LOST_EXTENDED 2055 /* never sent to a client, message only */ +#define CR_STMT_CLOSED 2056 #define CR_NEW_STMT_METADATA 2057 -#define CR_AUTH_PLUGIN_CANNOT_LOAD 2058 -#define CR_ALREADY_CONNECTED 2059 -#define CR_PLUGIN_FUNCTION_NOT_SUPPORTED 2060 - -#define SQLSTATE_UNKNOWN "HY000" +#define CR_ALREADY_CONNECTED 2058 +#define CR_AUTH_PLUGIN_CANNOT_LOAD 2059 +#define CR_DUPLICATE_CONNECTION_ATTR 2060 +#define CR_AUTH_PLUGIN_ERR 2061 +/* Always last, if you add new error codes please update the + value for CR_MYSQL_LAST_ERROR */ +#define CR_MYSQL_LAST_ERROR CR_AUTH_PLUGIN_ERR +/* + * MariaDB Connector/C errors: + */ +#define CR_EVENT_CREATE_FAILED 5000 +#define CR_BIND_ADDR_FAILED 5001 +#define CR_ASYNC_NOT_SUPPORTED 5002 +#define CR_FUNCTION_NOT_SUPPORTED 5003 +#define CR_FILE_NOT_FOUND 5004 +#define CR_FILE_READ 5005 +#define CR_BULK_WITHOUT_PARAMETERS 5006 +#define CR_INVALID_STMT 5007 +/* Always last, if you add new error codes please update the + value for CR_MARIADB_LAST_ERROR */ +#define CR_MARIADB_LAST_ERROR CR_INVALID_STMT #endif diff --git a/include/mysql/ma_common.h b/include/mysql/ma_common.h index bcf5caa..b0229a2 100644 --- a/include/mysql/ma_common.h +++ b/include/mysql/ma_common.h @@ -21,8 +21,22 @@ #define _ma_common_h #include -#include +#include +enum enum_multi_status { + COM_MULTI_OFF= 0, + COM_MULTI_CANCEL, + COM_MULTI_ENABLED, + COM_MULTI_DISABLED, + COM_MULTI_END +}; + + +typedef enum { + ALWAYS_ACCEPT, /* heuristics is disabled, use CLIENT_LOCAL_FILES */ + WAIT_FOR_QUERY, /* heuristics is enabled, not sending files */ + ACCEPT_FILE_REQUEST /* heuristics is enabled, ready to send a file */ +} auto_local_infile_state; typedef struct st_mariadb_db_driver { @@ -48,11 +62,52 @@ struct st_mysql_options_extension { double progress, const char *proc_info, unsigned int proc_info_length); - MARIADB_DB_DRIVER *db_driver; - char *ssl_fp; /* finger print of server certificate */ - char *ssl_fp_list; /* white list of finger prints */ - int (*verify_local_infile)(void *data, const char *filename); + MARIADB_DB_DRIVER *db_driver; + char *tls_fp; /* finger print of server certificate */ + char *tls_fp_list; /* white list of finger prints */ + char *tls_pw; /* password for encrypted certificates */ + my_bool multi_command; /* indicates if client wants to send multiple + commands in one packet */ + char *url; /* for connection handler we need to save URL for reconnect */ + unsigned int tls_cipher_strength; + char *tls_version; + my_bool read_only; + char *connection_handler; + my_bool (*set_option)(MYSQL *mysql, const char *config_option, const char *config_value); + HASH userdata; + char *server_public_key; + char *proxy_header; + size_t proxy_header_len; +}; + +typedef struct st_connection_handler +{ + struct st_ma_connection_plugin *plugin; + void *data; + my_bool active; + my_bool free_data; +} MA_CONNECTION_HANDLER; + +struct st_mariadb_net_extension { + enum enum_multi_status multi_status; +}; + +struct st_mariadb_session_state +{ + LIST *list, + *current; +}; + +struct st_mariadb_extension { + MA_CONNECTION_HANDLER *conn_hdlr; + struct st_mariadb_session_state session_state[SESSION_TRACK_TYPES]; + unsigned long mariadb_client_flag; /* MariaDB specific client flags */ + unsigned long mariadb_server_capabilities; /* MariaDB specific server capabilities */ + my_bool auto_local_infile; }; +#define OPT_EXT_VAL(a,key) \ + ((a)->options.extension && (a)->options.extension->key) ?\ + (a)->options.extension->key : 0 #endif diff --git a/include/mysql/ma_config.h.in b/include/mysql/ma_config.h.in new file mode 100644 index 0000000..8f12ee6 --- /dev/null +++ b/include/mysql/ma_config.h.in @@ -0,0 +1,140 @@ + +/* + * Include file constants (processed in LibmysqlIncludeFiles.txt 1 + */ +#cmakedefine HAVE_ALLOCA_H 1 +#cmakedefine HAVE_BIGENDIAN 1 +#cmakedefine HAVE_SETLOCALE 1 +#cmakedefine HAVE_NL_LANGINFO 1 +#cmakedefine HAVE_DLFCN_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE_FLOAT_H 1 +#cmakedefine HAVE_LIMITS_H 1 +#cmakedefine HAVE_PWD_H 1 +#cmakedefine HAVE_SELECT_H 1 +#cmakedefine HAVE_STDDEF_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_STDLIB_H 1 +#cmakedefine HAVE_STRING_H 1 +#cmakedefine HAVE_SYS_IOCTL_H 1 +#cmakedefine HAVE_SYS_SELECT_H 1 +#cmakedefine HAVE_SYS_SOCKET_H 1 +#cmakedefine HAVE_SYS_STREAM_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 +#cmakedefine HAVE_SYS_UN_H 1 +#cmakedefine HAVE_UNISTD_H 1 +#cmakedefine HAVE_UCONTEXT_H 1 + +/* + * function definitions - processed in LibmysqlFunctions.txt + */ + +#cmakedefine HAVE_DLERROR 1 +#cmakedefine HAVE_DLOPEN 1 +#cmakedefine HAVE_GETPWUID 1 +#cmakedefine HAVE_MEMCPY 1 +#cmakedefine HAVE_POLL 1 +#cmakedefine HAVE_STRTOK_R 1 +#cmakedefine HAVE_STRTOL 1 +#cmakedefine HAVE_STRTOLL 1 +#cmakedefine HAVE_STRTOUL 1 +#cmakedefine HAVE_STRTOULL 1 +#cmakedefine HAVE_TELL 1 +#cmakedefine HAVE_THR_SETCONCURRENCY 1 +#cmakedefine HAVE_THR_YIELD 1 +#cmakedefine HAVE_VASPRINTF 1 +#cmakedefine HAVE_VSNPRINTF 1 + +/* + * types and sizes + */ + + +#cmakedefine SIZEOF_CHARP @SIZEOF_CHARP@ +#if defined(SIZEOF_CHARP) +# define HAVE_CHARP 1 +#endif + + +#cmakedefine SIZEOF_INT @SIZEOF_INT@ +#if defined(SIZEOF_INT) +# define HAVE_INT 1 +#endif + +#cmakedefine SIZEOF_LONG @SIZEOF_LONG@ +#if defined(SIZEOF_LONG) +# define HAVE_LONG 1 +#endif + +#cmakedefine SIZEOF_LONG_LONG @SIZEOF_LONG_LONG@ +#if defined(SIZEOF_LONG_LONG) +# define HAVE_LONG_LONG 1 +#endif + + +#cmakedefine SIZEOF_SIZE_T @SIZEOF_SIZE_T@ +#if defined(SIZEOF_SIZE_T) +# define HAVE_SIZE_T 1 +#endif + + +#cmakedefine SIZEOF_UINT @SIZEOF_UINT@ +#if defined(SIZEOF_UINT) +# define HAVE_UINT 1 +#endif + +#cmakedefine SIZEOF_ULONG @SIZEOF_ULONG@ +#if defined(SIZEOF_ULONG) +# define HAVE_ULONG 1 +#endif + +#cmakedefine SIZEOF_INT8 @SIZEOF_INT8@ +#if defined(SIZEOF_INT8) +# define HAVE_INT8 1 +#endif +#cmakedefine SIZEOF_UINT8 @SIZEOF_UINT8@ +#if defined(SIZEOF_UINT8) +# define HAVE_UINT8 1 +#endif + +#cmakedefine SIZEOF_INT16 @SIZEOF_INT16@ +#if defined(SIZEOF_INT16) +# define HAVE_INT16 1 +#endif +#cmakedefine SIZEOF_UINT16 @SIZEOF_UINT16@ +#if defined(SIZEOF_UINT16) +# define HAVE_UINT16 1 +#endif + +#cmakedefine SIZEOF_INT32 @SIZEOF_INT32@ +#if defined(SIZEOF_INT32) +# define HAVE_INT32 1 +#endif +#cmakedefine SIZEOF_UINT32 @SIZEOF_UINT32@ +#if defined(SIZEOF_UINT32) +# define HAVE_UINT32 1 +#endif + +#cmakedefine SIZEOF_INT64 @SIZEOF_INT64@ +#if defined(SIZEOF_INT64) +# define HAVE_INT64 1 +#endif +#cmakedefine SIZEOF_UINT64 @SIZEOF_UINT64@ +#if defined(SIZEOF_UINT64) +# define HAVE_UINT64 1 +#endif + +#cmakedefine SIZEOF_SOCKLEN_T @SIZEOF_SOCKLEN_T@ +#if defined(SIZEOF_SOCKLEN_T) +# define HAVE_SOCKLEN_T 1 +#endif + +#cmakedefine SOCKET_SIZE_TYPE @SOCKET_SIZE_TYPE@ + +#define LOCAL_INFILE_MODE_OFF 0 +#define LOCAL_INFILE_MODE_ON 1 +#define LOCAL_INFILE_MODE_AUTO 2 +#define ENABLED_LOCAL_INFILE LOCAL_INFILE_MODE_@ENABLED_LOCAL_INFILE@ + +#define MARIADB_DEFAULT_CHARSET "@DEFAULT_CHARSET@" + diff --git a/include/mysql/ma_context.h b/include/mysql/ma_context.h new file mode 100644 index 0000000..2cc40d2 --- /dev/null +++ b/include/mysql/ma_context.h @@ -0,0 +1,233 @@ +/* + Copyright 2011 Kristian Nielsen and Monty Program Ab + + This file is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this. If not, see . +*/ + +/* + Simple API for spawning a co-routine, to be used for async libmysqlclient. + + Idea is that by implementing this interface using whatever facilities are + available for given platform, we can use the same code for the generic + libmysqlclient-async code. + + (This particular implementation uses Posix ucontext swapcontext().) +*/ + +#ifdef _WIN32 +#define MY_CONTEXT_USE_WIN32_FIBERS 1 +#elif defined(__GNUC__) && __GNUC__ >= 3 && defined(__x86_64__) && !defined(__ILP32__) +#define MY_CONTEXT_USE_X86_64_GCC_ASM +#elif defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__) +#define MY_CONTEXT_USE_I386_GCC_ASM +#elif defined(HAVE_UCONTEXT_H) +#define MY_CONTEXT_USE_UCONTEXT +#else +#define MY_CONTEXT_DISABLE +#endif + +#ifdef MY_CONTEXT_USE_WIN32_FIBERS +struct my_context { + void (*user_func)(void *); + void *user_arg; + void *app_fiber; + void *lib_fiber; + int return_value; +#ifndef DBUG_OFF + void *dbug_state; +#endif +}; +#endif + + +#ifdef MY_CONTEXT_USE_UCONTEXT +#include + +struct my_context { + void (*user_func)(void *); + void *user_data; + void *stack; + size_t stack_size; + ucontext_t base_context; + ucontext_t spawned_context; + int active; +#ifdef HAVE_VALGRIND + unsigned int valgrind_stack_id; +#endif +#ifndef DBUG_OFF + void *dbug_state; +#endif +}; +#endif + + +#ifdef MY_CONTEXT_USE_X86_64_GCC_ASM +#include + +struct my_context { + uint64_t save[9]; + void *stack_top; + void *stack_bot; +#ifdef HAVE_VALGRIND + unsigned int valgrind_stack_id; +#endif +#ifndef DBUG_OFF + void *dbug_state; +#endif +}; +#endif + + +#ifdef MY_CONTEXT_USE_I386_GCC_ASM +#include + +struct my_context { + uint64_t save[7]; + void *stack_top; + void *stack_bot; +#ifdef HAVE_VALGRIND + unsigned int valgrind_stack_id; +#endif +#ifndef DBUG_OFF + void *dbug_state; +#endif +}; +#endif + + +#ifdef MY_CONTEXT_DISABLE +struct my_context { + int dummy; +}; +#endif + +/* + Initialize an asynchroneous context object. + Returns 0 on success, non-zero on failure. +*/ +extern int my_context_init(struct my_context *c, size_t stack_size); + +/* Free an asynchroneous context object, deallocating any resources used. */ +extern void my_context_destroy(struct my_context *c); + +/* + Spawn an asynchroneous context. The context will run the supplied user + function, passing the supplied user data pointer. + + The context must have been initialised with my_context_init() prior to + this call. + + The user function may call my_context_yield(), which will cause this + function to return 1. Then later my_context_continue() may be called, which + will resume the asynchroneous context by returning from the previous + my_context_yield() call. + + When the user function returns, this function returns 0. + + In case of error, -1 is returned. +*/ +extern int my_context_spawn(struct my_context *c, void (*f)(void *), void *d); + +/* + Suspend an asynchroneous context started with my_context_spawn. + + When my_context_yield() is called, execution immediately returns from the + last my_context_spawn() or my_context_continue() call. Then when later + my_context_continue() is called, execution resumes by returning from this + my_context_yield() call. + + Returns 0 if ok, -1 in case of error. +*/ +extern int my_context_yield(struct my_context *c); + +/* + Resume an asynchroneous context. The context was spawned by + my_context_spawn(), and later suspended inside my_context_yield(). + + The asynchroneous context may be repeatedly suspended with + my_context_yield() and resumed with my_context_continue(). + + Each time it is suspended, this function returns 1. When the originally + spawned user function returns, this function returns 0. + + In case of error, -1 is returned. +*/ +extern int my_context_continue(struct my_context *c); + +struct st_ma_pvio; + +struct mysql_async_context { + /* + This is set to the value that should be returned from foo_start() or + foo_cont() when a call is suspended. + */ + unsigned int events_to_wait_for; + /* + It is also set to the event(s) that triggered when a suspended call is + resumed, eg. whether we woke up due to connection completed or timeout + in mysql_real_connect_cont(). + */ + unsigned int events_occured; + /* + This is set to the result of the whole asynchronous operation when it + completes. It uses a union, as different calls have different return + types. + */ + union { + void *r_ptr; + const void *r_const_ptr; + int r_int; + my_bool r_my_bool; + } ret_result; + /* + The timeout value (in millisecods), for suspended calls that need to wake + up on a timeout (eg. mysql_real_connect_start(). + */ + unsigned int timeout_value; + /* + This flag is set when we are executing inside some asynchronous call + foo_start() or foo_cont(). It is used to decide whether to use the + synchronous or asynchronous version of calls that may block such as + recv(). + + Note that this flag is not set when a call is suspended, eg. after + returning from foo_start() and before re-entering foo_cont(). + */ + my_bool active; + /* + This flag is set when an asynchronous operation is in progress, but + suspended. Ie. it is set when foo_start() or foo_cont() returns because + the operation needs to block, suspending the operation. + + It is used to give an error (rather than crash) if the application + attempts to call some foo_cont() method when no suspended operation foo is + in progress. + */ + my_bool suspended; + /* + If non-NULL, this is a pointer to a callback hook that will be invoked with + the user data argument just before the context is suspended, and just after + it is resumed. + */ + struct st_ma_pvio *pvio; + void (*suspend_resume_hook)(my_bool suspend, void *user_data); + void *suspend_resume_hook_user_data; + /* + This is used to save the execution contexts so that we can suspend an + operation and switch back to the application context, to resume the + suspended context later when the application re-invokes us with + foo_cont(). + */ + struct my_context async_context; +}; diff --git a/include/mysql/ma_crypt.h b/include/mysql/ma_crypt.h new file mode 100644 index 0000000..18fcd6c --- /dev/null +++ b/include/mysql/ma_crypt.h @@ -0,0 +1,166 @@ +/* + Copyright (C) 2018 MariaDB Corporation AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA +*/ + +#ifndef _ma_hash_h_ +#define _ma_hash_h_ + +#include +#include + +/*! Hash algorithms */ +#define MA_HASH_MD5 1 +#define MA_HASH_SHA1 2 +#define MA_HASH_SHA224 3 +#define MA_HASH_SHA256 4 +#define MA_HASH_SHA384 5 +#define MA_HASH_SHA512 6 +#define MA_HASH_RIPEMD160 7 + +/*! Hash digest sizes */ +#define MA_MD5_HASH_SIZE 16 +#define MA_SHA1_HASH_SIZE 20 +#define MA_SHA224_HASH_SIZE 28 +#define MA_SHA256_HASH_SIZE 32 +#define MA_SHA384_HASH_SIZE 48 +#define MA_SHA512_HASH_SIZE 64 +#define MA_RIPEMD160_HASH_SIZE 20 + +#define MA_MAX_HASH_SIZE 64 +/** \typedef MRL hash context */ + +#if defined(HAVE_OPENSSL) +typedef void MA_HASH_CTX; +#elif defined(HAVE_GNUTLS) +typedef struct { + void *ctx; + const struct nettle_hash *hash; +} MA_HASH_CTX; +#elif defined(HAVE_SCHANNEL) +#include +#include +typedef struct { + char free_me; + BCRYPT_ALG_HANDLE hAlg; + BCRYPT_HASH_HANDLE hHash; + PBYTE hashObject; + DWORD digest_len; +} MA_HASH_CTX; +#endif + +/** + @brief acquire and initialize new hash context + + @param[in] algorithm hash algorithm + @param[in] ctx pointer to a crypto context + + @return hash context on success, NULL on error +*/ +MA_HASH_CTX *ma_hash_new(unsigned int algorithm, MA_HASH_CTX *ctx); + +/** + @brief release and deinitializes a hash context + + @param[in] hash context + + @return void +*/ +void ma_hash_free(MA_HASH_CTX *ctx); + +/** + @brief hashes len bytes of data into the hash context. + This function can be called several times on same context to + hash additional data. + + @param[in] ctx hash context + @param[in] buffer data buffer + @param[in] len size of buffer + + @return void +*/ +void ma_hash_input(MA_HASH_CTX *ctx, + const unsigned char *buffer, + size_t len); + +/** + @brief retrieves the hash value from hash context + + @param[in] ctx hash context + @param[out] digest digest containing hash value + + @return void + */ +void ma_hash_result(MA_HASH_CTX *ctx, unsigned char *digest); + + +/** + @brief returns digest size for a given hash algorithm + + @param[in] hash algorithm + + @retuns digest size or 0 on error +*/ +static inline size_t ma_hash_digest_size(unsigned int hash_alg) +{ + switch(hash_alg) { + case MA_HASH_MD5: + return MA_MD5_HASH_SIZE; + case MA_HASH_SHA1: + return MA_SHA1_HASH_SIZE; + case MA_HASH_SHA224: + return MA_SHA224_HASH_SIZE; + case MA_HASH_SHA256: + return MA_SHA256_HASH_SIZE; + case MA_HASH_SHA384: + return MA_SHA384_HASH_SIZE; + case MA_HASH_SHA512: + return MA_SHA512_HASH_SIZE; + case MA_HASH_RIPEMD160: + return MA_RIPEMD160_HASH_SIZE; + default: + return 0; + } +} + +/** + @brief function to compute hash from buffer. + + @param[in] hash_alg hash algorithm + @param[in] buffer buffer + @param[in] buffer_leng length of buffer + @param[out] digest computed hash digest + + @return void +*/ +static inline void ma_hash(unsigned int algorithm, + const unsigned char *buffer, + size_t buffer_length, + unsigned char *digest) +{ + MA_HASH_CTX *ctx= NULL; +#ifdef HAVE_SCHANNEL + MA_HASH_CTX dctx; + ctx= &dctx; +#endif + ctx= ma_hash_new(algorithm, ctx); + ma_hash_input(ctx, buffer, buffer_length); + ma_hash_result(ctx, digest); + ma_hash_free(ctx); +} + +#endif /* _ma_hash_h_ */ diff --git a/include/mysql/ma_global.h b/include/mysql/ma_global.h new file mode 100644 index 0000000..d1fec39 --- /dev/null +++ b/include/mysql/ma_global.h @@ -0,0 +1,1103 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +/* This is the main include file that should included 'first' in every + C file. */ + +#ifndef _global_h +#define _global_h + +#ifdef _WIN32 +#include +#include +#include +#define strcasecmp _stricmp +#define sleep(x) Sleep(1000*(x)) +#ifdef _MSC_VER +#define inline __inline +#if _MSC_VER < 1900 +#define snprintf _snprintf +#endif +#endif +#define STDCALL __stdcall +#endif + +#include +#include +#ifndef __GNUC__ +#define __attribute(A) +#endif + +/* Fix problem with S_ISLNK() on Linux */ +#if defined(HAVE_LINUXTHREADS) +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +/* The client defines this to avoid all thread code */ +#if defined(UNDEF_THREADS_HACK) +#undef THREAD +#undef HAVE_mit_thread +#undef HAVE_LINUXTHREADS +#undef HAVE_UNIXWARE7_THREADS +#endif + +#ifdef HAVE_THREADS_WITHOUT_SOCKETS +/* MIT pthreads does not work with unix sockets */ +#undef HAVE_SYS_UN_H +#endif + +#define __EXTENSIONS__ 1 /* We want some extension */ +#ifndef __STDC_EXT__ +#define __STDC_EXT__ 1 /* To get large file support on hpux */ +#endif + +#if defined(THREAD) && !defined(_WIN32) +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */ +#endif +/* was #if defined(HAVE_LINUXTHREADS) || defined(HAVE_DEC_THREADS) || defined(HPUX) */ +#if !defined(SCO) +#define _REENTRANT 1 /* Some thread libraries require this */ +#endif +#if !defined(_THREAD_SAFE) && !defined(_AIX) +#define _THREAD_SAFE /* Required for OSF1 */ +#endif +#ifndef HAVE_mit_thread +#ifdef HAVE_UNIXWARE7_THREADS +#include +#else +#include /* AIX must have this included first */ +#endif /* HAVE_UNIXWARE7_THREADS */ +#endif /* HAVE_mit_thread */ +#if !defined(SCO) && !defined(_REENTRANT) +#define _REENTRANT 1 /* Threads requires reentrant code */ +#endif +#endif /* THREAD */ + +/* Go around some bugs in different OS and compilers */ +#ifdef _AIX /* By soren@t.dk */ +#define _H_STRINGS +#define _SYS_STREAM_H +#define _AIX32_CURSES +#define ulonglong2double(A) my_ulonglong2double(A) +#define my_off_t2double(A) my_ulonglong2double(A) +#ifdef __cplusplus +extern "C" { +#endif +double my_ulonglong2double(unsigned long long A); +#ifdef __cplusplus +} +#endif +#endif /* _AIX */ + +#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */ +#undef HAVE_SNPRINTF +#endif +#if defined(HAVE_BROKEN_INLINE) && !defined(__cplusplus) +#undef inline +#define inline +#endif + +#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */ +#undef HAVE_GETHOSTBYNAME_R +#endif +#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */ +#undef HAVE_INITGROUPS +#endif + +/* Fix a bug in gcc 2.8.0 on IRIX 6.2 */ +#if SIZEOF_LONG == 4 && defined(__LONG_MAX__) +#undef __LONG_MAX__ /* Is a longlong value in gcc 2.8.0 ??? */ +#define __LONG_MAX__ 2147483647 +#endif + +/* Fix problem when linking c++ programs with gcc 3.x */ +#ifdef DEFINE_CXA_PURE_VIRTUAL +#define FIX_GCC_LINKING_PROBLEM extern "C" { int __cxa_pure_virtual() {return 0;} } +#else +#define FIX_GCC_LINKING_PROBLEM +#endif + +/* egcs 1.1.2 has a problem with memcpy on Alpha */ +#if defined(__GNUC__) && defined(__alpha__) && ! (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) +#define BAD_MEMCPY +#endif + +/* In Linux-alpha we have atomic.h if we are using gcc */ +#if defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && defined(__alpha__) && (__GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95)) && !defined(HAVE_ATOMIC_ADD) +#define HAVE_ATOMIC_ADD +#define HAVE_ATOMIC_SUB +#endif + +/* In Linux-ia64 including atomic.h will give us an error */ +#if (defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && (defined(__ia64__) || defined(__powerpc64__))) || !defined(THREAD) +#undef HAVE_ATOMIC_ADD +#undef HAVE_ATOMIC_SUB +#endif + +#if defined(_lint) && !defined(lint) +#define lint +#endif +#if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG) +#define _LONG_LONG 1 /* For AIX string library */ +#endif + +#ifndef stdin +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDDEF_H +#include +#endif + +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#if defined(TIME_WITH_SYS_TIME) +# include +# include +#else +# if defined(HAVE_SYS_TIME_H) +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA) +#undef HAVE_ALLOCA +#undef HAVE_ALLOCA_H +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif +#ifdef HAVE_ATOMIC_ADD +#define __SMP__ +#define CONFIG_SMP +#include +#endif +#include /* Recommended by debian */ +#include + +/* Go around some bugs in different OS and compilers */ +#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) +#include /* HPUX 10.20 defines ulong here. UGLY !!! */ +#define HAVE_ULONG +#endif +#ifdef DONT_USE_FINITE /* HPUX 11.x has is_finite() */ +#undef HAVE_FINITE +#endif +#if defined(HPUX) && defined(_LARGEFILE64_SOURCE) && defined(THREAD) +/* Fix bug in setrlimit */ +#undef setrlimit +#define setrlimit cma_setrlimit64 +#endif + +/* We can not live without these */ + +#define USE_MYFUNC 1 /* Must use syscall indirection */ +#define MASTER 1 /* Compile without unireg */ +#define ENGLISH 1 /* Messages in English */ +#define POSIX_MISTAKE 1 /* regexp: Fix stupid spec error */ +#define USE_REGEX 1 /* We want the use the regex library */ +/* Do not define for ultra sparcs */ +#define USE_BMOVE512 1 /* Use this unless the system bmove is faster */ + +/* Paranoid settings. Define I_AM_PARANOID if you are paranoid */ +#ifdef I_AM_PARANOID +#define DONT_ALLOW_USER_CHANGE 1 +#define DONT_USE_MYSQL_PWD 1 +#endif + +/* #define USE_some_charset 1 was deprecated by changes to configure */ +/* my_ctype my_to_upper, my_to_lower, my_sort_order gain theit right value */ +/* automagically during configuration */ + +/* Does the system remember a signal handler after a signal ? */ +#ifndef HAVE_BSD_SIGNALS +#define DONT_REMEMBER_SIGNAL +#endif + + +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) +#define LINT_INIT(var) var=0 /* No uninitialize-warning */ +#define LINT_INIT_STRUCT(var) memset(&var, 0, sizeof(var)) /* No uninitialize-warning */ +#else +#define LINT_INIT(var) +#define LINT_INIT_STRUCT(var) +#endif + +/* Define some useful general macros */ +#if defined(__cplusplus) && defined(__GNUC__) +#define max(a, b) ((a) >? (b)) +#define min(a, b) ((a) (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#if defined(__EMX__) || !defined(HAVE_UINT) +typedef unsigned int uint; +typedef unsigned short ushort; +#endif + +#define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0) +#define swap(t,a,b) { register t dummy; dummy = a; a = b; b = dummy; } +#define test(a) ((a) ? 1 : 0) +#define set_if_bigger(a,b) { if ((a) < (b)) (a)=(b); } +#define set_if_smaller(a,b) { if ((a) > (b)) (a)=(b); } +#define test_all_bits(a,b) (((a) & (b)) == (b)) +#define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) +#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) +#ifndef HAVE_RINT +#define rint(A) floor((A)+0.5) +#endif + +/* Define some general constants */ +#ifndef TRUE +#define TRUE (1) /* Logical true */ +#define FALSE (0) /* Logical false */ +#endif + +#if defined(__GNUC__) +#define function_volatile volatile +#ifndef my_reinterpret_cast +#define my_reinterpret_cast(A) reinterpret_cast +#endif +#define my_const_cast(A) const_cast +#elif !defined(my_reinterpret_cast) +#define my_reinterpret_cast(A) (A) +#define my_const_cast(A) (A) +#endif +#if !defined(__GNUC__) && !defined(__clang__) +#define __attribute__(A) +#endif + +/* From old s-system.h */ + +/* + Support macros for non ansi & other old compilers. Since such + things are no longer supported we do nothing. We keep then since + some of our code may still be needed to upgrade old customers. +*/ +#define _VARARGS(X) X +#define _STATIC_VARARGS(X) X + +#if defined(DBUG_ON) && defined(DBUG_OFF) +#undef DBUG_OFF +#endif + +#if defined(_lint) && !defined(DBUG_OFF) +#define DBUG_OFF +#endif + +#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/ +#define ASCII_BITS_USED 8 /* Bit char used */ +#define NEAR_F /* No near function handling */ + +/* Some types that is different between systems */ + +typedef int File; /* File descriptor */ +#ifndef my_socket_defined +#define my_socket_defined +#if defined(_WIN64) +#define my_socket unsigned long long +#elif defined(_WIN32) +#define my_socket unsigned int +#else +typedef int my_socket; +#endif +#define my_socket_defined +#endif +#ifndef INVALID_SOCKET +#define INVALID_SOCKET -1 +#endif + +#if defined(__GNUC__) && !defined(_lint) +typedef char pchar; /* Mixed prototypes can take char */ +typedef char puchar; /* Mixed prototypes can take char */ +typedef char pbool; /* Mixed prototypes can take char */ +typedef short pshort; /* Mixed prototypes can take short int */ +typedef float pfloat; /* Mixed prototypes can take float */ +#else +typedef int pchar; /* Mixed prototypes can't take char */ +typedef uint puchar; /* Mixed prototypes can't take char */ +typedef int pbool; /* Mixed prototypes can't take char */ +typedef int pshort; /* Mixed prototypes can't take short int */ +typedef double pfloat; /* Mixed prototypes can't take float */ +#endif +typedef int (*qsort_cmp)(const void *,const void *); +#ifdef HAVE_mit_thread +#define qsort_t void +#undef QSORT_TYPE_IS_VOID +#define QSORT_TYPE_IS_VOID +#else +#define qsort_t RETQSORTTYPE /* Broken GCC can't handle typedef !!!! */ +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +typedef SOCKET_SIZE_TYPE size_socket; + +#ifndef SOCKOPT_OPTLEN_TYPE +#define SOCKOPT_OPTLEN_TYPE size_socket +#endif + +/* file create flags */ + +#ifndef O_SHARE +#define O_SHARE 0 /* Flag to my_open for shared files */ +#ifndef O_BINARY +#define O_BINARY 0 /* Flag to my_open for binary files */ +#endif +#define FILE_BINARY 0 /* Flag to my_fopen for binary streams */ +#ifdef HAVE_FCNTL +#define HAVE_FCNTL_LOCK +#define F_TO_EOF 0L /* Param to lockf() to lock rest of file */ +#endif +#endif /* O_SHARE */ +#ifndef O_TEMPORARY +#define O_TEMPORARY 0 +#endif +#ifndef O_SHORT_LIVED +#define O_SHORT_LIVED 0 +#endif + +/* #define USE_RECORD_LOCK */ + + /* Unsigned types supported by the compiler */ +#define UNSINT8 /* unsigned int8 (char) */ +#define UNSINT16 /* unsigned int16 */ +#define UNSINT32 /* unsigned int32 */ + + /* General constants */ +#define SC_MAXWIDTH 256 /* Max width of screen (for error messages) */ +#define FN_LEN 256 /* Max file name len */ +#define FN_HEADLEN 253 /* Max length of filepart of file name */ +#define FN_EXTLEN 20 /* Max length of extension (part of FN_LEN) */ +#define FN_REFLEN 512 /* Max length of full path-name */ +#define FN_EXTCHAR '.' +#define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ +#define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ +#define FN_PARENTDIR ".." /* Parentdirectory; Must be a string */ +#define FN_DEVCHAR ':' + +#ifndef FN_LIBCHAR +#ifdef _WIN32 +#define FN_LIBCHAR '\\' +#define FN_ROOTDIR "\\" +#else +#define FN_LIBCHAR '/' +#define FN_ROOTDIR "/" +#endif +#define MY_NFILE 1024 /* This is only used to save filenames */ +#endif + +/* #define EXT_IN_LIBNAME */ +/* #define FN_NO_CASE_SENCE */ +/* #define FN_UPPER_CASE TRUE */ + +/* + Io buffer size; Must be a power of 2 and a multiple of 512. May be + smaller what the disk page size. This influences the speed of the + isam btree library. eg to big to slow. +*/ +#define IO_SIZE 4096 +/* + How much overhead does malloc have. The code often allocates + something like 1024-MALLOC_OVERHEAD bytes +*/ +#define MALLOC_OVERHEAD 8 + /* get memory in huncs */ +#define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD) + /* Typical record cash */ +#define RECORD_CACHE_SIZE (uint) (64*1024-MALLOC_OVERHEAD) + /* Typical key cash */ +#define KEY_CACHE_SIZE (uint) (8*1024*1024-MALLOC_OVERHEAD) + + /* Some things that this system doesn't have */ + +#define ONLY_OWN_DATABASES /* We are using only databases by monty */ +#define NO_PISAM /* Not needed anymore */ +#define NO_MISAM /* Not needed anymore */ +#define NO_HASH /* Not needed anymore */ +#ifdef _WIN32 +#define NO_DIR_LIBRARY /* Not standard dir-library */ +#define USE_MY_STAT_STRUCT /* For my_lib */ +#ifdef _MSC_VER +typedef SSIZE_T ssize_t; +#endif +#endif + +/* Some things that this system does have */ + +#ifndef HAVE_ITOA +#define USE_MY_ITOA /* There is no itoa */ +#endif + +/* Some defines of functions for portability */ + +#ifndef HAVE_ATOD +#define atod atof +#endif +#ifdef USE_MY_ATOF +#define atof my_atof +extern void init_my_atof(void); +extern double my_atof(const char*); +#endif +#undef remove /* Crashes MySQL on SCO 5.0.0 */ +#ifndef _WIN32 +#define closesocket(A) close(A) +#endif +#ifndef ulonglong2double +#define ulonglong2double(A) ((double) (A)) +#define my_off_t2double(A) ((double) (A)) +#endif + + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#define ulong_to_double(X) ((double) (ulong) (X)) +#define SET_STACK_SIZE(X) /* Not needed on real machines */ + + +#ifdef HAVE_LINUXTHREADS +/* #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) */ +/* #define sigset(A,B) signal((A),(B)) */ +#endif + +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \ + defined(__cplusplus) || !defined(__GNUC__) +#define UNINIT_VAR(x) x= 0 +#else +/* GCC specific self-initialization which inhibits the warning. */ +#define UNINIT_VAR(x) x= x +#endif + + +/* This is from the old m-machine.h file */ + +#if SIZEOF_LONG_LONG > 4 +#define HAVE_LONG_LONG 1 +#endif + +#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) +#define LONGLONG_MIN ((long long) 0x8000000000000000LL) +#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) +#endif + + +#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL) +#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL +#define INT_MIN32 (~0x7FFFFFFFL) +#define INT_MAX32 0x7FFFFFFFL +#define UINT_MAX32 0xFFFFFFFFL +#define INT_MIN24 (~0x007FFFFF) +#define INT_MAX24 0x007FFFFF +#define UINT_MAX24 0x00FFFFFF +#define INT_MIN16 (~0x7FFF) +#define INT_MAX16 0x7FFF +#define UINT_MAX16 0xFFFF +#define INT_MIN8 (~0x7F) +#define INT_MAX8 0x7F +#define UINT_MAX8 0xFF + +#ifndef ULL +#ifdef HAVE_LONG_LONG +#define ULL(A) A ## ULL +#else +#define ULL(A) A ## UL +#endif +#endif + +#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) +/* First check for ANSI C99 definition: */ +#ifdef ULLONG_MAX +#define ULONGLONG_MAX ULLONG_MAX +#else +#define ULONGLONG_MAX ((unsigned long long)(~0ULL)) +#endif +#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ + +/* From limits.h instead */ +#ifndef DBL_MIN +#define DBL_MIN 4.94065645841246544e-324 +#define FLT_MIN ((float)1.40129846432481707e-45) +#endif +#ifndef DBL_MAX +#define DBL_MAX 1.79769313486231470e+308 +#define FLT_MAX ((float)3.40282346638528860e+38) +#endif + +/* + Max size that must be added to a so that we know Size to make + addressable obj. +*/ +typedef long my_ptrdiff_t; +#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) +#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) +/* Size to make addressable obj. */ +#define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A),sizeof(t))) + /* Offset of filed f in structure t */ +#define OFFSET(t, f) ((size_t)(char *)&((t *)0)->f) +#define ADD_TO_PTR(ptr,size,type) (type) ((unsigned char*) (ptr)+size) +#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((unsigned char*) (A) - (unsigned char*) (B)) + +#define NullS (char *) 0 +/* Nowadays we do not support MessyDos */ +#ifndef NEAR +#define NEAR /* Who needs segments ? */ +#define FAR /* On a good machine */ +#ifndef HUGE_PTR +#define HUGE_PTR +#endif +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +#define STDCALL _System _Export +#elif !defined( STDCALL) +#define STDCALL +#endif + +/* Typdefs for easyier portability */ + +#if defined(VOIDTYPE) +typedef void *gptr; /* Generic pointer */ +#else +typedef char *gptr; /* Generic pointer */ +#endif +#ifndef HAVE_INT_8_16_32 +typedef char int8; /* Signed integer >= 8 bits */ +typedef short int16; /* Signed integer >= 16 bits */ +#endif +#ifndef HAVE_UCHAR +typedef unsigned char uchar; /* Short for unsigned char */ +#endif +typedef unsigned char uint8; /* Short for unsigned integer >= 8 bits */ +typedef unsigned short uint16; /* Short for unsigned integer >= 16 bits */ + +#if SIZEOF_INT == 4 +#ifndef HAVE_INT_8_16_32 +typedef int int32; +#endif +typedef unsigned int uint32; /* Short for unsigned integer >= 32 bits */ +#elif SIZEOF_LONG == 4 +#ifndef HAVE_INT_8_16_32 +typedef long int32; +#endif +typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */ +#else +#error "Neither int or long is of 4 bytes width" +#endif + +#if !defined(HAVE_ULONG) && !defined(HAVE_LINUXTHREADS) && !defined(__USE_MISC) +typedef unsigned long ulong; /* Short for unsigned long */ +#endif +#ifndef longlong_defined +#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8 +typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ +typedef long long int longlong; +#else +typedef unsigned long ulonglong; /* ulong or unsigned long long */ +typedef long longlong; +#endif +#define longlong_defined +#endif + +#ifndef HAVE_INT64 +typedef longlong int64; +#endif +#ifndef HAVE_UINT64 +typedef ulonglong uint64; +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1) +#ifdef USE_RAID +/* + The following is done with a if to not get problems with pre-processors + with late define evaluation +*/ +#if defined(SIZEOF_OFF_T) && SIZEOF_OFF_T == 4 +#define SYSTEM_SIZEOF_OFF_T 4 +#else +#define SYSTEM_SIZEOF_OFF_T 8 +#endif +#undef SIZEOF_OFF_T +#define SIZEOF_OFF_T 8 +#else +#define SYSTEM_SIZEOF_OFF_T SIZEOF_OFF_T +#endif /* USE_RAID */ + +#if defined(SIZEOF_OFF_T) && SIZEOF_OFF_T > 4 +typedef ulonglong my_off_t; +#else +typedef unsigned long my_off_t; +#endif +#define MY_FILEPOS_ERROR (~(my_off_t) 0) +#ifndef _WIN32 +typedef off_t os_off_t; +#endif + +#if defined(_WIN32) +#define socket_errno WSAGetLastError() +#define SOCKET_EINTR WSAEINTR +#define SOCKET_EAGAIN WSAEWOULDBLOCK +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK +#else /* Unix */ +#define socket_errno errno +#define closesocket(A) close(A) +#define SOCKET_EINTR EINTR +#define SOCKET_EAGAIN EAGAIN +#define SOCKET_EWOULDBLOCK EWOULDBLOCK +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#endif + +typedef uint8 int7; /* Most effective integer 0 <= x <= 127 */ +typedef short int15; /* Most effective integer 0 <= x <= 32767 */ +typedef char *my_string; /* String of characters */ +typedef unsigned long size_s; /* Size of strings (In string-funcs) */ +typedef int myf; /* Type of MyFlags in my_funcs */ +typedef char my_bool; /* Small bool */ +typedef unsigned long long my_ulonglong; +#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus)) +typedef char bool; /* Ordinary boolean values 0 1 */ +#endif + /* Macros for converting *constants* to the right type */ +#define INT8(v) (int8) (v) +#define INT16(v) (int16) (v) +#define INT32(v) (int32) (v) +#define MYF(v) (myf) (v) + +/* + Defines to make it possible to prioritize register assignments. No + longer that important with modern compilers. +*/ +#ifndef USING_X +#define reg1 register +#define reg2 register +#define reg3 register +#define reg4 register +#define reg5 register +#define reg6 register +#define reg7 register +#define reg8 register +#define reg9 register +#define reg10 register +#define reg11 register +#define reg12 register +#define reg13 register +#define reg14 register +#define reg15 register +#define reg16 register +#endif + +/* Defines for time function */ +#define SCALE_SEC 100 +#define SCALE_USEC 10000 +#define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */ +#define MY_HOW_OFTEN_TO_WRITE 1000 /* How often we want info on screen */ + +#define NOT_FIXED_DEC 31 + +#if defined(_WIN32) && defined(_MSVC) +#define MYSQLND_LLU_SPEC "%I64u" +#define MYSQLND_LL_SPEC "%I64d" +#ifndef L64 +#define L64(x) x##i64 +#endif +#else +#define MYSQLND_LLU_SPEC "%llu" +#define MYSQLND_LL_SPEC "%lld" +#ifndef L64 +#define L64(x) x##LL +#endif /* L64 */ +#endif /* _WIN32 */ +/* +** Define-funktions for reading and storing in machine independent format +** (low byte first) +*/ + +/* Optimized store functions for Intel x86 */ +#define int1store(T,A) *((int8*) (T)) = (A) +#define uint1korr(A) (*(((uint8*)(A)))) +#if defined(__i386__) || defined(_WIN32) +#define sint2korr(A) (*((int16 *) (A))) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (*((long *) (A))) +#define uint2korr(A) (*((uint16 *) (A))) +#if defined(HAVE_purify) && !defined(_WIN32) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#else +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) +#endif /* HAVE_purify && !_WIN32 */ +#define uint4korr(A) (*((uint32 *) (A))) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) + \ + (((uint32) ((uchar) (A)[1])) << 8) + \ + (((uint32) ((uchar) (A)[2])) << 16) + \ + (((uint32) ((uchar) (A)[3])) << 24)) + \ + (((ulonglong) ((uchar) (A)[4])) << 32) + \ + (((ulonglong) ((uchar) (A)[5])) << 40)) +#define uint8korr(A) (*((ulonglong *) (A))) +#define sint8korr(A) (*((longlong *) (A))) +#define int2store(T,A) *((uint16*) (T))= (uint16) (A) +#define int3store(T,A) do { *(T)= (uchar) ((A));\ + *(T+1)=(uchar) (((uint) (A) >> 8));\ + *(T+2)=(uchar) (((A) >> 16)); } while (0) +#define int4store(T,A) *((long *) (T))= (long) (A) +#define int5store(T,A) do { *(T)= (uchar)((A));\ + *((T)+1)=(uchar) (((A) >> 8));\ + *((T)+2)=(uchar) (((A) >> 16));\ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); } while(0) +#define int6store(T,A) do { *(T)= (uchar)((A)); \ + *((T)+1)=(uchar) (((A) >> 8)); \ + *((T)+2)=(uchar) (((A) >> 16)); \ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); \ + *((T)+5)=(uchar) (((A) >> 40)); } while(0) +#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) + +typedef union { + double v; + long m[2]; +} doubleget_union; +#define doubleget(V,M) \ +do { doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } while(0) +#define doublestore(T,V) do { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ + *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; \ + } while (0) +#define float4get(V,M) do { *((float *) &(V)) = *((float*) (M)); } while(0) +#define float8get(V,M) doubleget((V),(M)) +#define float4store(V,M) memcpy((uchar*) V,(uchar*) (&M),sizeof(float)) +#define floatstore(T,V) memcpy((uchar*)(T), (uchar*)(&V),sizeof(float)) +#define floatget(V,M) memcpy((uchar*) &V,(uchar*) (M),sizeof(float)) +#define float8store(V,M) doublestore((V),(M)) +#else + +/* + We're here if it's not a IA-32 architecture (Win32 and UNIX IA-32 defines + were done before) +*/ +#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\ + ((int16) ((int16) (A)[1]) << 8)) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\ + (((int32) ((uchar) (A)[1]) << 8)) +\ + (((int32) ((uchar) (A)[2]) << 16)) +\ + (((int32) ((int16) (A)[3]) << 24))) +#define sint8korr(A) (longlong) uint8korr(A) +#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\ + ((uint16) ((uchar) (A)[1]) << 8)) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) + \ + (((uint32) ((uchar) (A)[1])) << 8) + \ + (((uint32) ((uchar) (A)[2])) << 16) + \ + (((uint32) ((uchar) (A)[3])) << 24)) + \ + (((ulonglong) ((uchar) (A)[4])) << 32) + \ + (((ulonglong) ((uchar) (A)[5])) << 40)) +#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) (((uint32) ((uchar) (A)[4])) +\ + (((uint32) ((uchar) (A)[5])) << 8) +\ + (((uint32) ((uchar) (A)[6])) << 16) +\ + (((uint32) ((uchar) (A)[7])) << 24))) <<\ + 32)) +#define int2store(T,A) do { uint def_temp= (uint) (A) ;\ + *((uchar*) (T))= (uchar)(def_temp); \ + *((uchar*) (T)+1)=(uchar)((def_temp >> 8)); \ + } while(0) +#define int3store(T,A) do { /*lint -save -e734 */\ + *((uchar*)(T))=(uchar) ((A));\ + *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ + *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ + /*lint -restore */} while(0) +#define int4store(T,A) do { *((char *)(T))=(char) ((A));\ + *(((char *)(T))+1)=(char) (((A) >> 8));\ + *(((char *)(T))+2)=(char) (((A) >> 16));\ + *(((char *)(T))+3)=(char) (((A) >> 24)); } while(0) +#define int5store(T,A) do { *((char *)(T))= (char)((A)); \ + *(((char *)(T))+1)= (char)(((A) >> 8)); \ + *(((char *)(T))+2)= (char)(((A) >> 16)); \ + *(((char *)(T))+3)= (char)(((A) >> 24)); \ + *(((char *)(T))+4)= (char)(((A) >> 32)); \ + } while(0) +#define int6store(T,A) do { *((char *)(T))= (char)((A)); \ + *(((char *)(T))+1)= (char)(((A) >> 8)); \ + *(((char *)(T))+2)= (char)(((A) >> 16)); \ + *(((char *)(T))+3)= (char)(((A) >> 24)); \ + *(((char *)(T))+4)= (char)(((A) >> 32)); \ + *(((char *)(T))+5)= (char)(((A) >> 40)); \ + } while(0) +#define int8store(T,A) do { uint def_temp= (uint) (A), def_temp2= (uint) ((A) >> 32); \ + int4store((T),def_temp); \ + int4store((T+4),def_temp2); } while(0) +#ifdef HAVE_BIGENDIAN +#define float4store(T,A) do { *(T)= ((uchar *) &A)[3];\ + *((T)+1)=(char) ((uchar *) &A)[2];\ + *((T)+2)=(char) ((uchar *) &A)[1];\ + *((T)+3)=(char) ((uchar *) &A)[0]; } while(0) + +#define float4get(V,M) do { float def_temp;\ + ((uchar*) &def_temp)[0]=(M)[3];\ + ((uchar*) &def_temp)[1]=(M)[2];\ + ((uchar*) &def_temp)[2]=(M)[1];\ + ((uchar*) &def_temp)[3]=(M)[0];\ + (V)=def_temp; } while(0) +#define float8store(T,V) do { *(T)= ((uchar *) &V)[7];\ + *((T)+1)=(char) ((uchar *) &V)[6];\ + *((T)+2)=(char) ((uchar *) &V)[5];\ + *((T)+3)=(char) ((uchar *) &V)[4];\ + *((T)+4)=(char) ((uchar *) &V)[3];\ + *((T)+5)=(char) ((uchar *) &V)[2];\ + *((T)+6)=(char) ((uchar *) &V)[1];\ + *((T)+7)=(char) ((uchar *) &V)[0]; } while(0) + +#define float8get(V,M) do { double def_temp;\ + ((uchar*) &def_temp)[0]=(M)[7];\ + ((uchar*) &def_temp)[1]=(M)[6];\ + ((uchar*) &def_temp)[2]=(M)[5];\ + ((uchar*) &def_temp)[3]=(M)[4];\ + ((uchar*) &def_temp)[4]=(M)[3];\ + ((uchar*) &def_temp)[5]=(M)[2];\ + ((uchar*) &def_temp)[6]=(M)[1];\ + ((uchar*) &def_temp)[7]=(M)[0];\ + (V) = def_temp; } while(0) +#else +#define float4get(V,M) memcpy(&V, (M), sizeof(float)) +#define float4store(V,M) memcpy(V, (&M), sizeof(float)) + +#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) +#define doublestore(T,V) do { *(((char*)T)+0)=(char) ((uchar *) &V)[4];\ + *(((char*)T)+1)=(char) ((uchar *) &V)[5];\ + *(((char*)T)+2)=(char) ((uchar *) &V)[6];\ + *(((char*)T)+3)=(char) ((uchar *) &V)[7];\ + *(((char*)T)+4)=(char) ((uchar *) &V)[0];\ + *(((char*)T)+5)=(char) ((uchar *) &V)[1];\ + *(((char*)T)+6)=(char) ((uchar *) &V)[2];\ + *(((char*)T)+7)=(char) ((uchar *) &V)[3]; }\ + while(0) +#define doubleget(V,M) do { double def_temp;\ + ((uchar*) &def_temp)[0]=(M)[4];\ + ((uchar*) &def_temp)[1]=(M)[5];\ + ((uchar*) &def_temp)[2]=(M)[6];\ + ((uchar*) &def_temp)[3]=(M)[7];\ + ((uchar*) &def_temp)[4]=(M)[0];\ + ((uchar*) &def_temp)[5]=(M)[1];\ + ((uchar*) &def_temp)[6]=(M)[2];\ + ((uchar*) &def_temp)[7]=(M)[3];\ + (V) = def_temp; } while(0) +#endif /* __FLOAT_WORD_ORDER */ + +#define float8get(V,M) doubleget((V),(M)) +#define float8store(V,M) doublestore((V),(M)) +#endif /* WORDS_BIGENDIAN */ + +#endif /* __i386__ OR _WIN32 */ + +/* + Macro for reading 32-bit integer from network byte order (big-endian) + from unaligned memory location. +*/ +#define int4net(A) (int32) (((uint32) ((uchar) (A)[3])) |\ + (((uint32) ((uchar) (A)[2])) << 8) |\ + (((uint32) ((uchar) (A)[1])) << 16) |\ + (((uint32) ((uchar) (A)[0])) << 24)) +/* + Define-funktions for reading and storing in machine format from/to + short/long to/from some place in memory V should be a (not + register) variable, M is a pointer to byte +*/ + +#ifdef HAVE_BIGENDIAN + +#define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\ + ((uint16) ((uint16) (M)[0]) << 8)); } while(0) +#define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\ + ((short) ((short) (M)[0]) << 8)); } while(0) +#define longget(V,M) do { int32 def_temp;\ + ((uchar*) &def_temp)[0]=(M)[0];\ + ((uchar*) &def_temp)[1]=(M)[1];\ + ((uchar*) &def_temp)[2]=(M)[2];\ + ((uchar*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define ulongget(V,M) do { uint32 def_temp;\ + ((uchar*) &def_temp)[0]=(M)[0];\ + ((uchar*) &def_temp)[1]=(M)[1];\ + ((uchar*) &def_temp)[2]=(M)[2];\ + ((uchar*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define shortstore(T,A) do { uint def_temp=(uint) (A) ;\ + *(((char*)T)+1)=(char)(def_temp); \ + *(((char*)T)+0)=(char)(def_temp >> 8); } while(0) +#define longstore(T,A) do { *(((char*)T)+3)=((A));\ + *(((char*)T)+2)=(((A) >> 8));\ + *(((char*)T)+1)=(((A) >> 16));\ + *(((char*)T)+0)=(((A) >> 24)); } while(0) + +#define floatget(V,M) memcpy(&V, (M), sizeof(float)) +#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) +#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) +#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) +#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) + +#else + +#define ushortget(V,M) do { V = uint2korr(M); } while(0) +#define shortget(V,M) do { V = sint2korr(M); } while(0) +#define longget(V,M) do { V = sint4korr(M); } while(0) +#define ulongget(V,M) do { V = uint4korr(M); } while(0) +#define shortstore(T,V) int2store(T,V) +#define longstore(T,V) int4store(T,V) +#ifndef floatstore +#define floatstore(T,V) memcpy((T), (void *) (&V), sizeof(float)) +#define floatget(V,M) memcpy(&V, (M), sizeof(float)) +#endif +#ifndef doubleget +#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) +#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) +#endif /* doubleget */ +#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) + +#endif /* WORDS_BIGENDIAN */ + +#ifndef THREAD +#define thread_safe_increment(V,L) (V)++ +#define thread_safe_add(V,C,L) (V)+=(C) +#define thread_safe_sub(V,C,L) (V)-=(C) +#define statistic_increment(V,L) (V)++ +#define statistic_add(V,C,L) (V)+=(C) +#endif + +#ifdef _WIN32 +#define SO_EXT ".dll" +#else +#define SO_EXT ".so" +#endif + +#ifndef DBUG_OFF +#define dbug_assert(A) assert(A) +#define DBUG_ASSERT(A) assert(A) +#else +#define dbug_assert(A) +#define DBUG_ASSERT(A) +#endif + +#ifdef HAVE_DLOPEN +#ifdef _WIN32 +#define dlsym(lib, name) GetProcAddress((HMODULE)lib, name) +#define dlopen(libname, unused) LoadLibraryEx(libname, NULL, 0) +#define dlclose(lib) FreeLibrary((HMODULE)lib) +#elif defined(HAVE_DLFCN_H) +#include +#endif +#ifndef HAVE_DLERROR +#define dlerror() "" +#endif +#endif + +#if SIZEOF_CHARP == SIZEOF_INT +typedef unsigned int intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG +typedef unsigned long intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG_LONG +typedef unsigned long long intptr; +#else +#error sizeof(void *) is not sizeof(int, long or long long) +#endif + +#ifdef _WIN32 +#define IF_WIN(A,B) A +#else +#define IF_WIN(A,B) B +#endif + +#ifndef RTLD_NOW +#define RTLD_NOW 1 +#endif + +#endif /* _global_h */ diff --git a/include/mysql/ma_hash.h b/include/mysql/ma_hash.h new file mode 100644 index 0000000..163f182 --- /dev/null +++ b/include/mysql/ma_hash.h @@ -0,0 +1,70 @@ +/************************************************************************************ + Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB, + Monty Program AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA + + Part of this code includes code from the PHP project which + is freely available from http://www.php.net +*************************************************************************************/ + +#ifndef _ma_hash_h +#define _ma_hash_h +#ifdef __cplusplus +extern "C" { +#endif + +typedef uchar *(*hash_get_key)(const uchar *,uint*,my_bool); +typedef void (*hash_free_key)(void *); + + /* flags for hash_init */ +#define HASH_CASE_INSENSITIVE 1 + +typedef struct st_hash_info { + uint next; /* index to next key */ + uchar *data; /* data for current entry */ +} HASH_LINK; + +typedef struct st_hash { + uint key_offset,key_length; /* Length of key if const length */ + uint records,blength,current_record; + uint flags; + DYNAMIC_ARRAY array; /* Place for hash_keys */ + hash_get_key get_key; + void (*free)(void *); + uint (*calc_hashnr)(const uchar *key,uint length); +} HASH; + +#define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,C,D,E,F,G CALLER_INFO) +my_bool _hash_init(HASH *hash,uint default_array_elements, uint key_offset, + uint key_length, hash_get_key get_key, + void (*free_element)(void*), uint flags CALLER_INFO_PROTO); +void hash_free(HASH *tree); +uchar *hash_element(HASH *hash,uint idx); +void * hash_search(HASH *info,const uchar *key,uint length); +void * hash_next(HASH *info,const uchar *key,uint length); +my_bool hash_insert(HASH *info,const uchar *data); +my_bool hash_delete(HASH *hash,uchar *record); +my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,uint old_key_length); +my_bool hash_check(HASH *hash); /* Only in debug library */ + +#define hash_clear(H) memset((char*) (H), 0,sizeof(*(H))) +#define hash_inited(H) ((H)->array.buffer != 0) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/mysql/ma_list.h b/include/mysql/ma_list.h new file mode 100644 index 0000000..549280d --- /dev/null +++ b/include/mysql/ma_list.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +#ifndef _list_h_ +#define _list_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_list { + struct st_list *prev,*next; + void *data; +} LIST; + +typedef int (*list_walk_action)(void *,void *); + +extern LIST *list_add(LIST *root,LIST *element); +extern LIST *list_delete(LIST *root,LIST *element); +extern LIST *list_cons(void *data,LIST *root); +extern LIST *list_reverse(LIST *root); +extern void list_free(LIST *root,unsigned int free_data); +extern unsigned int list_length(LIST *list); +extern int list_walk(LIST *list,list_walk_action action,char * argument); + +#define list_rest(a) ((a)->next) +#define list_push(a,b) (a)=list_cons((b),(a)) +#define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old) ; ma_free((char *) old,MYF(MY_FAE)); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/mysql/ma_pthread.h b/include/mysql/ma_pthread.h new file mode 100644 index 0000000..c01242f --- /dev/null +++ b/include/mysql/ma_pthread.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + 2016 MariaDB Corporation AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +/* Defines to make different thread packages compatible */ + +#ifndef _my_pthread_h +#define _my_pthread_h + +#if defined(_WIN32) +#include +typedef CRITICAL_SECTION pthread_mutex_t; +#define pthread_mutex_init(A,B) InitializeCriticalSection(A) +#define pthread_mutex_lock(A) (EnterCriticalSection(A),0) +#define pthread_mutex_unlock(A) LeaveCriticalSection(A) +#define pthread_mutex_destroy(A) DeleteCriticalSection(A) +#define pthread_self() GetCurrentThreadId() +#endif /* defined(_WIN32) */ + +#endif /* _my_ptread_h */ diff --git a/include/mysql/ma_pvio.h b/include/mysql/ma_pvio.h new file mode 100644 index 0000000..7e300fe --- /dev/null +++ b/include/mysql/ma_pvio.h @@ -0,0 +1,133 @@ +#ifndef _ma_pvio_h_ +#define _ma_pvio_h_ +#define cio_defined + +#ifdef HAVE_TLS +#include +#else +#define MARIADB_TLS void +#endif + +#define PVIO_SET_ERROR if (pvio->set_error) \ + pvio->set_error + +#define PVIO_READ_AHEAD_CACHE_SIZE 16384 +#define PVIO_READ_AHEAD_CACHE_MIN_SIZE 2048 +#define PVIO_EINTR_TRIES 2 + +struct st_ma_pvio_methods; +typedef struct st_ma_pvio_methods PVIO_METHODS; + +#define IS_PVIO_ASYNC(a) \ + ((a)->mysql && (a)->mysql->options.extension && (a)->mysql->options.extension->async_context) + +#define IS_PVIO_ASYNC_ACTIVE(a) \ + (IS_PVIO_ASYNC(a)&& (a)->mysql->options.extension->async_context->active) + +#define IS_MYSQL_ASYNC(a) \ + ((a)->options.extension && (a)->options.extension->async_context) + +#define IS_MYSQL_ASYNC_ACTIVE(a) \ + (IS_MYSQL_ASYNC(a)&& (a)->options.extension->async_context->active) + +enum enum_pvio_timeout { + PVIO_CONNECT_TIMEOUT= 0, + PVIO_READ_TIMEOUT, + PVIO_WRITE_TIMEOUT +}; + +enum enum_pvio_io_event +{ + VIO_IO_EVENT_READ, + VIO_IO_EVENT_WRITE, + VIO_IO_EVENT_CONNECT +}; + +enum enum_pvio_type { + PVIO_TYPE_UNIXSOCKET= 0, + PVIO_TYPE_SOCKET, + PVIO_TYPE_NAMEDPIPE, + PVIO_TYPE_SHAREDMEM, +}; + +enum enum_pvio_operation { + PVIO_READ= 0, + PVIO_WRITE=1 +}; + +#define SHM_DEFAULT_NAME "MYSQL" + +struct st_pvio_callback; + +typedef struct st_pvio_callback { + void (*callback)(MYSQL *mysql, uchar *buffer, size_t size); + struct st_pvio_callback *next; +} PVIO_CALLBACK; + +struct st_ma_pvio { + void *data; + /* read ahead cache */ + uchar *cache; + uchar *cache_pos; + size_t cache_size; + enum enum_pvio_type type; + int timeout[3]; + int ssl_type; /* todo: change to enum (ssl plugins) */ + MARIADB_TLS *ctls; + MYSQL *mysql; + PVIO_METHODS *methods; + void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...); + void (*callback)(MARIADB_PVIO *pvio, my_bool is_read, const uchar *buffer, size_t length); +}; + +typedef struct st_ma_pvio_cinfo +{ + const char *host; + const char *unix_socket; + int port; + enum enum_pvio_type type; + MYSQL *mysql; +} MA_PVIO_CINFO; + +struct st_ma_pvio_methods +{ + my_bool (*set_timeout)(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout); + int (*get_timeout)(MARIADB_PVIO *pvio, enum enum_pvio_timeout type); + ssize_t (*read)(MARIADB_PVIO *pvio, uchar *buffer, size_t length); + ssize_t (*async_read)(MARIADB_PVIO *pvio, uchar *buffer, size_t length); + ssize_t (*write)(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); + ssize_t (*async_write)(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); + int (*wait_io_or_timeout)(MARIADB_PVIO *pvio, my_bool is_read, int timeout); + int (*blocking)(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); + my_bool (*connect)(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); + my_bool (*close)(MARIADB_PVIO *pvio); + int (*fast_send)(MARIADB_PVIO *pvio); + int (*keepalive)(MARIADB_PVIO *pvio); + my_bool (*get_handle)(MARIADB_PVIO *pvio, void *handle); + my_bool (*is_blocking)(MARIADB_PVIO *pvio); + my_bool (*is_alive)(MARIADB_PVIO *pvio); + my_bool (*has_data)(MARIADB_PVIO *pvio, ssize_t *data_len); + int(*shutdown)(MARIADB_PVIO *pvio); +}; + +/* Function prototypes */ +MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo); +void ma_pvio_close(MARIADB_PVIO *pvio); +ssize_t ma_pvio_cache_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); +ssize_t ma_pvio_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); +ssize_t ma_pvio_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); +int ma_pvio_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type); +my_bool ma_pvio_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout); +int ma_pvio_fast_send(MARIADB_PVIO *pvio); +int ma_pvio_keepalive(MARIADB_PVIO *pvio); +my_socket ma_pvio_get_socket(MARIADB_PVIO *pvio); +my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio); +my_bool ma_pvio_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode); +my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio); +int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout); +my_bool ma_pvio_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); +my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio); +my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle); +my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *length); + +#endif /* _ma_pvio_h_ */ diff --git a/include/mysql/ma_server_error.h b/include/mysql/ma_server_error.h new file mode 100644 index 0000000..6e77663 --- /dev/null +++ b/include/mysql/ma_server_error.h @@ -0,0 +1,2 @@ +/* This file exists for compatibility only */ +#include "mysqld_error.h" diff --git a/include/mysql/ma_sha1.h b/include/mysql/ma_sha1.h new file mode 100644 index 0000000..2748f11 --- /dev/null +++ b/include/mysql/ma_sha1.h @@ -0,0 +1,42 @@ +/**************************************************************************** + Copyright (C) 2012 Monty Program AB + 2016 MariaDB Corporation AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA +*****************************************************************************/ + +/* This code came from the PHP project, initially written by + Stefan Esser */ + +#ifndef SHA1_H +#define SHA1_H + +#define SHA1_MAX_LENGTH 20 +#define SCRAMBLE_LENGTH 20 +#define SCRAMBLE_LENGTH_323 8 + +/* SHA1 context. */ +typedef struct { + uint32 state[5]; /* state (ABCD) */ + uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} _MA_SHA1_CTX; + +void ma_SHA1Init(_MA_SHA1_CTX *); +void ma_SHA1Update(_MA_SHA1_CTX *, const unsigned char *, size_t); +void ma_SHA1Final(unsigned char[20], _MA_SHA1_CTX *); + +#endif diff --git a/include/mysql/ma_string.h b/include/mysql/ma_string.h new file mode 100644 index 0000000..1032538 --- /dev/null +++ b/include/mysql/ma_string.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + 2012 by MontyProgram AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +/* defines for the libmariadb library */ + +#ifndef _ma_string_h_ +#define _ma_string_h_ + +#include + +typedef enum { + MY_GCVT_ARG_FLOAT, + MY_GCVT_ARG_DOUBLE +} my_gcvt_arg_type; + +size_t ma_fcvt(double x, int precision, char *to, my_bool *error); +size_t ma_gcvt(double x, my_gcvt_arg_type type, int width, char *to, + my_bool *error); +char *ma_ll2str(long long val,char *dst, int radix); + +#define MAX_ENV_SIZE 1024 + +static inline my_bool ma_check_env_str(const char *env) +{ + unsigned int i; + + if (!env) + return 1; + + for (i=0; i < MAX_ENV_SIZE; i++) + { + if (env[i] == 0) + break; + } + if (i >= MAX_ENV_SIZE) + return 1; + return 0; +} + +#endif diff --git a/include/mysql/ma_sys.h b/include/mysql/ma_sys.h new file mode 100644 index 0000000..45654b3 --- /dev/null +++ b/include/mysql/ma_sys.h @@ -0,0 +1,546 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +#ifndef _my_sys_h +#define _my_sys_h +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_AIOWAIT +#include /* Used by record-cache */ +typedef struct my_aio_result { + aio_result_t result; + int pending; +} my_aio_result; +#endif + +#ifndef _mariadb_ctype_h +#include /* for MARIADB_CHARSET_INFO */ +#endif + +#include + +#define MYSYS_PROGRAM_USES_CURSES() { ma_error_handler_hook = ma_message_curses; mysys_uses_curses=1; } +#define MYSYS_PROGRAM_DONT_USE_CURSES() { ma_error_handler_hook = ma_message_no_curses; mysys_uses_curses=0;} +#define MY_INIT(name); { ma_progname= name; ma_init(); } + +#define MAXMAPS (4) /* Number of error message maps */ +#define ERRMOD (1000) /* Max number of errors in a map */ +#define ERRMSGSIZE (SC_MAXWIDTH) /* Max length of a error message */ +#define NRERRBUFFS (2) /* Buffers for parameters */ +#define MY_FILE_ERROR ((uint) ~0) + + /* General bitmaps for my_func's */ +#define MY_FFNF 1 /* Fatal if file not found */ +#define MY_FNABP 2 /* Fatal if not all bytes read/written */ +#define MY_NABP 4 /* Error if not all bytes read/written */ +#define MY_FAE 8 /* Fatal if any error */ +#define MY_WME 16 /* Write message on error */ +#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */ +#define MY_RAID 64 /* Support for RAID (not the "Johnson&Johnson"-s one ;) */ +#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */ +#define MY_LINK_WARNING 32 /* my_redel() gives warning if links */ +#define MY_COPYTIME 64 /* my_redel() copies time */ +#define MY_DELETE_OLD 256 /* my_create_with_symlink() */ +#define MY_RESOLVE_LINK 128 /* my_realpath(); Only resolve links */ +#define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */ +#define MY_REDEL_MAKE_BACKUP 256 +#define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */ +#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */ +#define MY_ZEROFILL 32 /* ma_malloc(), fill array with zero */ +#define MY_ALLOW_ZERO_PTR 64 /* ma_realloc() ; zero ptr -> malloc */ +#define MY_FREE_ON_ERROR 128 /* ma_realloc() ; Free old ptr on error */ +#define MY_HOLD_ON_ERROR 256 /* ma_realloc() ; Return old ptr on error */ +#define MY_THREADSAFE 128 /* pread/pwrite: Don't allow interrupts */ +#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy; Don't overwrite file */ + +#define MY_CHECK_ERROR 1 /* Params to ma_end; Check open-close */ +#define MY_GIVE_INFO 2 /* Give time info about process*/ + +#define ME_HIGHBYTE 8 /* Shift for colours */ +#define ME_NOCUR 1 /* Don't use curses message */ +#define ME_OLDWIN 2 /* Use old window */ +#define ME_BELL 4 /* Ring bell then printing message */ +#define ME_HOLDTANG 8 /* Don't delete last keys */ +#define ME_WAITTOT 16 /* Wait for errtime secs of for a action */ +#define ME_WAITTANG 32 /* Wait for a user action */ +#define ME_NOREFRESH 64 /* Don't refresh screen */ +#define ME_NOINPUT 128 /* Don't use the input library */ +#define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */ +#define ME_COLOUR2 ((2 << ME_HIGHBYTE)) +#define ME_COLOUR3 ((3 << ME_HIGHBYTE)) + + /* My seek flags */ +#define MY_SEEK_SET 0 +#define MY_SEEK_CUR 1 +#define MY_SEEK_END 2 + + /* My charsets_list flags */ +#define MY_NO_SETS 0 +#define MY_COMPILED_SETS 1 /* show compiled-in sets */ +#define MY_CONFIG_SETS 2 /* sets that have a *.conf file */ +#define MY_INDEX_SETS 4 /* all sets listed in the Index file */ +#define MY_LOADED_SETS 8 /* the sets that are currently loaded */ + + /* Some constants */ +#define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */ +#define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */ +#define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */ +#define KEYCACHE_BLOCK_SIZE 1024 + + /* root_alloc flags */ +#define MY_KEEP_PREALLOC 1 + + /* defines when allocating data */ + +#define my_checkmalloc() (0) +#undef TERMINATE +#define TERMINATE(A) {} +#define QUICK_SAFEMALLOC +#define NORMAL_SAFEMALLOC +#define ma_malloc_ci(SZ,FLAG) ma_malloc( SZ, FLAG ) +#define CALLER_INFO_PROTO /* nothing */ +#define CALLER_INFO /* nothing */ +#define ORIG_CALLER_INFO /* nothing */ + +#ifdef HAVE_ALLOCA +#if defined(_AIX) && !defined(__GNUC__) +#pragma alloca +#endif /* _AIX */ +#if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) +#ifndef alloca +#define alloca __builtin_alloca +#endif +#endif /* GNUC */ +#define my_alloca(SZ) alloca((size_t) (SZ)) +#define my_afree(PTR) {} +#else +#define my_alloca(SZ) ma_malloc(SZ,MYF(0)) +#define my_afree(PTR) ma_free(PTR) +#endif /* HAVE_ALLOCA */ + +#ifdef MSDOS +#ifdef __ZTC__ +void * __CDECL halloc(long count,size_t length); +void __CDECL hfree(void *ptr); +#endif +#if defined(USE_HALLOC) +#if defined(_VCM_) || defined(M_IC80386) +#undef USE_HALLOC +#endif +#endif +#ifdef USE_HALLOC +#define malloc(a) halloc((long) (a),1) +#define free(a) hfree(a) +#endif +#endif /* MSDOS */ + +#ifndef errno +#ifdef HAVE_ERRNO_AS_DEFINE +#include /* errno is a define */ +#else +extern int errno; /* declare errno */ +#endif +#endif +extern const char ** NEAR my_errmsg[]; +extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; +/* tbr +extern int (*ma_error_handler_hook)(uint my_err, const char *str,myf MyFlags); +extern int (*fatal_ma_error_handler_hook)(uint my_err, const char *str, + myf MyFlags); +*/ + +/* charsets */ +/* tbr +extern uint get_charset_number(const char *cs_name); +extern const char *get_charset_name(uint cs_number); +extern my_bool set_default_charset(uint cs, myf flags); +extern my_bool set_default_charset_by_name(const char *cs_name, myf flags); +extern void free_charsets(void); +extern char *list_charsets(myf want_flags); +extern char *get_charsets_dir(char *buf); +*/ +extern MARIADB_CHARSET_INFO *get_charset(uint cs_number, myf flags); +extern MARIADB_CHARSET_INFO *get_charset_by_name(const char *cs_name); +extern MARIADB_CHARSET_INFO *get_charset_by_nr(uint cs_number); + +/* string functions */ +char *ma_strmake(register char *dst, register const char *src, size_t length); + +/* statistics */ +#ifdef TBR +extern ulong _my_cache_w_requests,_my_cache_write,_my_cache_r_requests, + _my_cache_read; +extern ulong _my_blocks_used,_my_blocks_changed; +extern ulong ma_file_opened,ma_stream_opened, ma_tmp_file_created; +extern my_bool key_cache_inited; + + /* Point to current ma_message() */ +extern void (*my_sigtstp_cleanup)(void), + /* Executed before jump to shell */ + (*my_sigtstp_restart)(void), + (*my_abort_hook)(int); + /* Executed when coming from shell */ +extern int NEAR ma_umask, /* Default creation mask */ + NEAR ma_umask_dir, + NEAR my_recived_signals, /* Signals we have got */ + NEAR my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ + NEAR ma_dont_interrupt; /* call remember_intr when set */ +extern my_bool NEAR mysys_uses_curses, ma_use_symdir; +extern size_t lCurMemory,lMaxMemory; /* from safemalloc */ + +extern ulong ma_default_record_cache_size; +extern my_bool NEAR ma_disable_locking,NEAR ma_disable_async_io, + NEAR ma_disable_flush_key_blocks, NEAR ma_disable_symlinks; +extern char wild_many,wild_one,wild_prefix; +extern const char *charsets_dir; +extern char *defaults_extra_file; +typedef struct wild_file_pack /* Struct to hold info when selecting files */ +{ + uint wilds; /* How many wildcards */ + uint not_pos; /* Start of not-theese-files */ + my_string *wild; /* Pointer to wildcards */ +} WF_PACK; + +struct my_rnd_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + +#endif +typedef struct st_typelib { /* Different types saved here */ + uint count; /* How many types */ + const char *name; /* Name of typelib */ + const char **type_names; +} TYPELIB; + +enum cache_type {READ_CACHE,WRITE_CACHE,READ_FIFO,READ_NET,WRITE_NET}; +enum flush_type { FLUSH_KEEP, FLUSH_RELEASE, FLUSH_IGNORE_CHANGED, + FLUSH_FORCE_WRITE}; + +typedef struct st_record_cache /* Used when caching records */ +{ + File file; + int rc_seek,error,inited; + uint rc_length,read_length,reclength; + my_off_t rc_record_pos,end_of_file; + unsigned char *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos; +#ifdef HAVE_AIOWAIT + int use_async_io; + my_aio_result aio_result; +#endif + enum cache_type type; +} RECORD_CACHE; + + +typedef struct st_dynamic_array { + char *buffer; + uint elements,max_element; + uint alloc_increment; + uint size_of_element; +} DYNAMIC_ARRAY; + +typedef struct st_dynamic_string { + char *str; + size_t length,max_length,alloc_increment; +} DYNAMIC_STRING; + + +typedef struct st_io_cache /* Used when caching files */ +{ + my_off_t pos_in_file,end_of_file; + unsigned char *rc_pos,*rc_end,*buffer,*rc_request_pos; + int (*read_function)(struct st_io_cache *,unsigned char *,uint); + char *file_name; /* if used with 'open_cached_file' */ + char *dir,*prefix; + File file; + int seek_not_done,error; + uint buffer_length,read_length; + myf myflags; /* Flags used to my_read/my_write */ + enum cache_type type; +#ifdef HAVE_AIOWAIT + uint inited; + my_off_t aio_read_pos; + my_aio_result aio_result; +#endif +} IO_CACHE; + +typedef int (*qsort2_cmp)(const void *, const void *, const void *); + + /* defines for mf_iocache */ + + /* Test if buffer is inited */ +#define my_b_clear(info) (info)->buffer=0 +#define my_b_inited(info) (info)->buffer +#define my_b_EOF INT_MIN + +#define my_b_read(info,Buffer,Count) \ + ((info)->rc_pos + (Count) <= (info)->rc_end ?\ + (memcpy(Buffer,(info)->rc_pos,(size_t) (Count)), \ + ((info)->rc_pos+=(Count)),0) :\ + (*(info)->read_function)((info),Buffer,Count)) + +#define my_b_get(info) \ + ((info)->rc_pos != (info)->rc_end ?\ + ((info)->rc_pos++, (int) (uchar) (info)->rc_pos[-1]) :\ + _my_b_get(info)) + +#define my_b_write(info,Buffer,Count) \ + ((info)->rc_pos + (Count) <= (info)->rc_end ?\ + (memcpy((info)->rc_pos,Buffer,(size_t) (Count)), \ + ((info)->rc_pos+=(Count)),0) :\ + _my_b_write(info,Buffer,Count)) + + /* my_b_write_byte doesn't have any err-check */ +#define my_b_write_byte(info,chr) \ + (((info)->rc_pos < (info)->rc_end) ?\ + ((*(info)->rc_pos++)=(chr)) :\ + (_my_b_write(info,0,0) , ((*(info)->rc_pos++)=(chr)))) + +#define my_b_fill_cache(info) \ + (((info)->rc_end=(info)->rc_pos),(*(info)->read_function)(info,0,0)) + +#define my_b_tell(info) ((info)->pos_in_file + \ + ((info)->rc_pos - (info)->rc_request_pos)) + +#define my_b_bytes_in_cache(info) ((uint) ((info)->rc_end - (info)->rc_pos)) + +typedef struct st_changeable_var { + const char *name; /* Name of variable */ + long *varptr; /* Pointer to variable */ + long def_value, /* Default value */ + min_value, /* Min allowed value */ + max_value, /* Max allowed value */ + sub_size, /* Subtract this from given value */ + block_size; /* Value should be a mult. of this */ +} CHANGEABLE_VAR; + + +/* structs for ma_alloc_root */ + +#ifndef ST_MA_USED_MEM_DEFINED +#define ST_MA_USED_MEM_DEFINED +typedef struct st_ma_used_mem { /* struct for once_alloc */ + struct st_ma_used_mem *next; /* Next block in use */ + size_t left; /* memory left in block */ + size_t size; /* Size of block */ +} MA_USED_MEM; + +typedef struct st_ma_mem_root { + MA_USED_MEM *free; + MA_USED_MEM *used; + MA_USED_MEM *pre_alloc; + size_t min_malloc; + size_t block_size; + unsigned int block_num; + unsigned int first_block_usage; + void (*error_handler)(void); +} MA_MEM_ROOT; +#endif + + /* Prototypes for mysys and my_func functions */ + +extern void * _mymalloc(size_t uSize,const char *sFile, + uint uLine, myf MyFlag); +extern void * _myrealloc(void * pPtr,size_t uSize,const char *sFile, + uint uLine, myf MyFlag); +extern void *ma_multi_malloc(myf MyFlags, ...); +extern void _myfree(void * pPtr,const char *sFile,uint uLine, myf MyFlag); +extern int _sanity(const char *sFile,unsigned int uLine); +#ifndef TERMINATE +extern void TERMINATE(FILE *file); +#endif +extern void ma_init_glob_errs(void); +extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); +extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); +extern int my_fclose(FILE *fd,myf MyFlags); +extern int my_chsize(File fd,my_off_t newlength,myf MyFlags); +extern int ma_error _VARARGS((int nr,myf MyFlags, ...)); +extern int ma_printf_error _VARARGS((uint my_err, const char *format, + myf MyFlags, ...) + __attribute__ ((format (printf, 2, 4)))); +extern int ma_vsnprintf( char *str, size_t n, + const char *format, va_list ap ); +extern int ma_snprintf(char* to, size_t n, const char* fmt, ...); +extern int ma_message(uint my_err, const char *str,myf MyFlags); +extern int _mariadb_stderr_out(unsigned int error, const char *errmsg, myf MyFlags); + +extern void ma_init(void); +extern void ma_end(int infoflag); +extern int my_redel(const char *from, const char *to, int MyFlags); +extern int my_copystat(const char *from, const char *to, int MyFlags); +extern my_string my_filename(File fd); + +#ifndef THREAD +extern void dont_break(void); +extern void allow_break(void); +#else +#define dont_break() +#define allow_break() +#endif + +extern void caseup(my_string str,uint length); +extern void casedn(my_string str,uint length); +extern void caseup_str(my_string str); +extern void casedn_str(my_string str); +extern void case_sort(my_string str,uint length); +extern uint ma_dirname_part(my_string to,const char *name); +extern uint ma_dirname_length(const char *name); +#define base_name(A) (A+dirname_length(A)) +extern int test_if_hard_path(const char *dir_name); +extern char *ma_convert_dirname(my_string name); +extern void to_unix_path(my_string name); +extern my_string ma_fn_ext(const char *name); +extern my_string fn_same(my_string toname,const char *name,int flag); +extern my_string ma_fn_format(my_string to,const char *name,const char *dsk, + const char *form,int flag); +extern size_s ma_strlength(const char *str); +extern void ma_pack_dirname(my_string to,const char *from); +extern uint unma_pack_dirname(my_string to,const char *from); +extern uint ma_cleanup_dirname(my_string to,const char *from); +extern uint ma_system_filename(my_string to,const char *from); +extern my_string ma_unpack_filename(my_string to,const char *from); +extern my_string ma_intern_filename(my_string to,const char *from); +extern my_string directory_file_name(my_string dst, const char *src); +extern int pack_filename(my_string to, const char *name, size_s max_length); +extern my_string my_path(my_string to,const char *progname, + const char *own_pathname_part); +extern my_string my_load_path(my_string to, const char *path, + const char *own_path_prefix); +extern int wild_compare(const char *str,const char *wildstr); +extern my_string my_strcasestr(const char *src,const char *suffix); +extern int my_strcasecmp(const char *s,const char *t); +extern int my_strsortcmp(const char *s,const char *t); +extern int my_casecmp(const char *s,const char *t,uint length); +extern int my_sortcmp(const char *s,const char *t,uint length); +extern int my_sortncmp(const char *s,uint s_len, const char *t,uint t_len); +#ifdef TBR +extern WF_PACK *wf_comp(my_string str); +extern int wf_test(struct wild_file_pack *wf_pack,const char *name); +extern void wf_end(struct wild_file_pack *buffer); +extern size_s strip_sp(my_string str); +extern void get_date(my_string to,int timeflag,time_t use_time); +extern void soundex(my_string out_pntr, my_string in_pntr,pbool remove_garbage); +extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file, + uint reclength,enum cache_type type, + pbool use_async_io); +extern int read_cache_record(RECORD_CACHE *info,unsigned char *to); +extern int end_record_cache(RECORD_CACHE *info); +extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos, + const unsigned char *record,uint length); +extern int flush_write_cache(RECORD_CACHE *info); +extern long my_clock(void); +extern sig_handler sigtstp_handler(int signal_number); +extern void handle_recived_signals(void); +extern int init_key_cache(ulong use_mem,ulong leave_this_much_mem); +extern unsigned char *key_cache_read(File file,my_off_t filepos,unsigned char* buff,uint length, + uint block_length,int return_buffer); +extern int key_cache_write(File file,my_off_t filepos,unsigned char* buff,uint length, + uint block_length,int force_write); +extern int flush_key_blocks(int file, enum flush_type type); +extern void end_key_cache(void); +extern sig_handler my_set_alarm_variable(int signo); +extern void my_string_ptr_sort(void *base,uint items,size_s size); +extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, + size_s size_of_element,uchar *buffer[]); +extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); +extern qsort2_cmp get_ptr_compare(uint); +extern int init_io_cache(IO_CACHE *info,File file,uint cachesize, + enum cache_type type,my_off_t seek_offset, + pbool use_async_io, myf cache_myflags); +extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, + my_off_t seek_offset,pbool use_async_io, + pbool clear_cache); +extern int _my_b_read(IO_CACHE *info,unsigned char *Buffer,uint Count); +extern int _my_b_net_read(IO_CACHE *info,unsigned char *Buffer,uint Count); +extern int _my_b_get(IO_CACHE *info); +extern int _my_b_async_read(IO_CACHE *info,unsigned char *Buffer,uint Count); +extern int _my_b_write(IO_CACHE *info,const unsigned char *Buffer,uint Count); +extern int my_block_write(IO_CACHE *info, const unsigned char *Buffer, + uint Count, my_off_t pos); +extern int flush_io_cache(IO_CACHE *info); +extern int end_io_cache(IO_CACHE *info); +extern uint my_b_fill(IO_CACHE *info); +extern void my_b_seek(IO_CACHE *info,my_off_t pos); +extern uint my_b_gets(IO_CACHE *info, char *to, uint max_length); +extern uint my_b_printf(IO_CACHE *info, const char* fmt, ...); +extern uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); +extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, + const char *prefix, uint cache_size, + myf cache_myflags); +extern my_bool real_open_cached_file(IO_CACHE *cache); +extern void close_cached_file(IO_CACHE *cache); +File create_temp_file(char *to, const char *dir, const char *pfx, + int mode, myf MyFlags); +#define ma_init_dynamic_array(A,B,C,D) init_dynamic_array(A,B,C,D CALLER_INFO) +#endif +extern my_bool ma_init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size, + uint init_alloc,uint alloc_increment CALLER_INFO_PROTO); +#define ma_init_dynamic_array_ci(A,B,C,D) ma_init_dynamic_array(A,B,C,D ORIG_CALLER_INFO) +extern my_bool ma_insert_dynamic(DYNAMIC_ARRAY *array,void * element); +extern unsigned char *ma_alloc_dynamic(DYNAMIC_ARRAY *array); +extern unsigned char *ma_pop_dynamic(DYNAMIC_ARRAY*); +extern my_bool ma_set_dynamic(DYNAMIC_ARRAY *array,void * element,uint array_index); +extern void ma_get_dynamic(DYNAMIC_ARRAY *array,void * element,uint array_index); +extern void ma_delete_dynamic(DYNAMIC_ARRAY *array); +extern void ma_delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index); +extern void ma_freeze_size(DYNAMIC_ARRAY *array); +#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element) +#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) +#define push_dynamic(A,B) ma_insert_dynamic(A,B) + +extern int ma_find_type(my_string x,TYPELIB *typelib,uint full_name); +extern void ma_make_type(my_string to,uint nr,TYPELIB *typelib); +extern const char *ma_get_type(TYPELIB *typelib,uint nr); +extern my_bool ma_init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, + size_t init_alloc, size_t alloc_increment); +extern my_bool ma_dynstr_append(DYNAMIC_STRING *str, const char *append); +extern my_bool ma_dynstr_append_quoted(DYNAMIC_STRING *str, + const char *append, size_t len, + char quote); +my_bool ma_dynstr_append_mem(DYNAMIC_STRING *str, const char *append, + size_t length); +extern my_bool ma_dynstr_set(DYNAMIC_STRING *str, const char *init_str); +extern my_bool ma_dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size); +extern void ma_dynstr_free(DYNAMIC_STRING *str); +void set_all_changeable_vars(CHANGEABLE_VAR *vars); +my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars); +my_bool set_changeable_varval(const char *var, ulong val, + CHANGEABLE_VAR *vars); +#define ma_alloc_root_inited(A) ((A)->min_malloc != 0) +void ma_init_alloc_root(MA_MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size); +void *ma_alloc_root(MA_MEM_ROOT *mem_root, size_t Size); +void ma_free_root(MA_MEM_ROOT *root, myf MyFLAGS); +char *ma_strdup_root(MA_MEM_ROOT *root,const char *str); +char *ma_memdup_root(MA_MEM_ROOT *root,const char *str, size_t len); +void ma_free_defaults(char **argv); +void ma_print_defaults(const char *conf_file, const char **groups); +my_bool _mariadb_compress(unsigned char *, size_t *, size_t *); +my_bool _mariadb_uncompress(unsigned char *, size_t *, size_t *); +unsigned char *_mariadb_compress_alloc(const unsigned char *packet, size_t *len, size_t *complen); +ulong checksum(const unsigned char *mem, uint count); + +#if defined(_MSC_VER) && !defined(_WIN32) +extern void sleep(int sec); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* _my_sys_h */ diff --git a/include/mysql/ma_tls.h b/include/mysql/ma_tls.h new file mode 100644 index 0000000..9ce49e7 --- /dev/null +++ b/include/mysql/ma_tls.h @@ -0,0 +1,161 @@ +#ifndef _ma_tls_h_ +#define _ma_tls_h_ + +enum enum_pvio_tls_type { + SSL_TYPE_DEFAULT=0, +#ifdef _WIN32 + SSL_TYPE_SCHANNEL, +#endif + SSL_TYPE_OPENSSL, + SSL_TYPE_GNUTLS +}; + +#define PROTOCOL_SSLV3 0 +#define PROTOCOL_TLS_1_0 1 +#define PROTOCOL_TLS_1_1 2 +#define PROTOCOL_TLS_1_2 3 +#define PROTOCOL_TLS_1_3 4 +#define PROTOCOL_UNKNOWN 5 +#define PROTOCOL_MAX PROTOCOL_TLS_1_3 + +#define TLS_VERSION_LENGTH 64 +extern char tls_library_version[TLS_VERSION_LENGTH]; + +typedef struct st_ma_pvio_tls { + void *data; + MARIADB_PVIO *pvio; + void *ssl; +} MARIADB_TLS; + +/* Function prototypes */ + +/* ma_tls_start + initializes the ssl library + Parameter: + errmsg pointer to error message buffer + errmsg_len length of error message buffer + Returns: + 0 success + 1 if an error occurred + Notes: + On success the global variable ma_tls_initialized will be set to 1 +*/ +int ma_tls_start(char *errmsg, size_t errmsg_len); + +/* ma_tls_end + unloads/deinitializes ssl library and unsets global variable + ma_tls_initialized +*/ +void ma_tls_end(void); + +/* ma_tls_init + creates a new SSL structure for a SSL connection and loads + client certificates + + Parameters: + MYSQL a mysql structure + Returns: + void * a pointer to internal SSL structure +*/ +void * ma_tls_init(MYSQL *mysql); + +/* ma_tls_connect + performs SSL handshake + Parameters: + MARIADB_TLS MariaDB SSL container + Returns: + 0 success + 1 error +*/ +my_bool ma_tls_connect(MARIADB_TLS *ctls); + +/* ma_tls_read + reads up to length bytes from socket + Parameters: + ctls MariaDB SSL container + buffer read buffer + length buffer length + Returns: + 0-n bytes read + -1 if an error occurred +*/ +ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length); + +/* ma_tls_write + write buffer to socket + Parameters: + ctls MariaDB SSL container + buffer write buffer + length buffer length + Returns: + 0-n bytes written + -1 if an error occurred +*/ +ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length); + +/* ma_tls_close + closes SSL connection and frees SSL structure which was previously + created by ma_tls_init call + Parameters: + MARIADB_TLS MariaDB SSL container + Returns: + 0 success + 1 error +*/ +my_bool ma_tls_close(MARIADB_TLS *ctls); + +/* ma_tls_verify_server_cert + validation check of server certificate + Parameter: + MARIADB_TLS MariaDB SSL container + Returns: + ß success + 1 error +*/ +int ma_tls_verify_server_cert(MARIADB_TLS *ctls); + +/* ma_tls_get_cipher + returns cipher for current ssl connection + Parameter: + MARIADB_TLS MariaDB SSL container + Returns: + cipher in use or + NULL on error +*/ +const char *ma_tls_get_cipher(MARIADB_TLS *ssl); + +/* ma_tls_get_finger_print + returns SHA1 finger print of server certificate + Parameter: + MARIADB_TLS MariaDB SSL container + fp buffer for fingerprint + fp_len buffer length + Returns: + actual size of finger print +*/ +unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int fp_len); + +/* ma_tls_get_protocol_version + returns protocol version number in use + Parameter: + MARIADB_TLS MariaDB SSL container + Returns: + protocol number +*/ +int ma_tls_get_protocol_version(MARIADB_TLS *ctls); +const char *ma_pvio_tls_get_protocol_version(MARIADB_TLS *ctls); +int ma_pvio_tls_get_protocol_version_id(MARIADB_TLS *ctls); + +/* Function prototypes */ +MARIADB_TLS *ma_pvio_tls_init(MYSQL *mysql); +my_bool ma_pvio_tls_connect(MARIADB_TLS *ctls); +ssize_t ma_pvio_tls_read(MARIADB_TLS *ctls, const uchar *buffer, size_t length); +ssize_t ma_pvio_tls_write(MARIADB_TLS *ctls, const uchar *buffer, size_t length); +my_bool ma_pvio_tls_close(MARIADB_TLS *ctls); +int ma_pvio_tls_verify_server_cert(MARIADB_TLS *ctls); +const char *ma_pvio_tls_cipher(MARIADB_TLS *ctls); +my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list); +my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio); +void ma_pvio_tls_end(); + +#endif /* _ma_tls_h_ */ diff --git a/include/mysql/mariadb/ma_io.h b/include/mysql/mariadb/ma_io.h new file mode 100644 index 0000000..d39fc06 --- /dev/null +++ b/include/mysql/mariadb/ma_io.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2015 MariaDB Corporation AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +#ifndef _ma_io_h_ +#define _ma_io_h_ + + +#ifdef HAVE_REMOTEIO +#include +#endif + +enum enum_file_type { + MA_FILE_NONE=0, + MA_FILE_LOCAL=1, + MA_FILE_REMOTE=2 +}; + +typedef struct +{ + enum enum_file_type type; + void *ptr; +} MA_FILE; + +#ifdef HAVE_REMOTEIO +struct st_rio_methods { + MA_FILE *(*mopen)(const char *url, const char *mode); + int (*mclose)(MA_FILE *ptr); + int (*mfeof)(MA_FILE *file); + size_t (*mread)(void *ptr, size_t size, size_t nmemb, MA_FILE *file); + char * (*mgets)(char *ptr, size_t size, MA_FILE *file); +}; +#endif + +/* function prototypes */ +MA_FILE *ma_open(const char *location, const char *mode, MYSQL *mysql); +int ma_close(MA_FILE *file); +int ma_feof(MA_FILE *file); +size_t ma_read(void *ptr, size_t size, size_t nmemb, MA_FILE *file); +char *ma_gets(char *ptr, size_t size, MA_FILE *file); + +#endif diff --git a/include/mysql/mariadb_async.h b/include/mysql/mariadb_async.h new file mode 100644 index 0000000..cd5385b --- /dev/null +++ b/include/mysql/mariadb_async.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2012 MariaDB Services and Kristian Nielsen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +/* Common definitions for MariaDB non-blocking client library. */ + +#ifndef MYSQL_ASYNC_H +#define MYSQL_ASYNC_H + +extern int my_connect_async(MARIADB_PVIO *pvio, + const struct sockaddr *name, uint namelen, + int vio_timeout); +extern ssize_t my_recv_async(MARIADB_PVIO *pvio, + unsigned char *buf, size_t size, int timeout); +extern ssize_t my_send_async(MARIADB_PVIO *pvio, + const unsigned char *buf, size_t size, + int timeout); +extern my_bool my_io_wait_async(struct mysql_async_context *b, + enum enum_pvio_io_event event, int timeout); +#ifdef HAVE_TLS +extern ssize_t ma_tls_read_async(MARIADB_PVIO *pvio, const uchar *buf, size_t size); +extern ssize_t ma_tls_write_async(MARIADB_PVIO *pvio, const uchar *buf, size_t size); +#endif + +#endif /* MYSQL_ASYNC_H */ diff --git a/include/mysql/mariadb_com.h b/include/mysql/mariadb_com.h new file mode 100644 index 0000000..9a5da28 --- /dev/null +++ b/include/mysql/mariadb_com.h @@ -0,0 +1,457 @@ +/************************************************************************************ + Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB, + Monty Program AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA + + Part of this code includes code from the PHP project which + is freely available from http://www.php.net +*************************************************************************************/ + +/* +** Common definition between mysql server & client +*/ + +#ifndef _mysql_com_h +#define _mysql_com_h + + +#define NAME_CHAR_LEN 64 +#define NAME_LEN 256 /* Field/table name length */ +#define HOSTNAME_LENGTH 60 +#define SYSTEM_MB_MAX_CHAR_LENGTH 4 +#define USERNAME_CHAR_LENGTH 128 +#define USERNAME_LENGTH USERNAME_CHAR_LENGTH * SYSTEM_MB_MAX_CHAR_LENGTH +#define SERVER_VERSION_LENGTH 60 +#define SQLSTATE_LENGTH 5 +#define SCRAMBLE_LENGTH 20 +#define SCRAMBLE_LENGTH_323 8 + +#define LOCAL_HOST "localhost" +#define LOCAL_HOST_NAMEDPIPE "." + +#if defined(_WIN32) && !defined( _CUSTOMCONFIG_) +#define MARIADB_NAMEDPIPE "MySQL" +#define MYSQL_SERVICENAME "MySql" +#endif /* _WIN32 */ + +/* for use in mysql client tools only */ +#define MYSQL_AUTODETECT_CHARSET_NAME "auto" +#define BINCMP_FLAG 131072 + +enum mysql_enum_shutdown_level +{ + SHUTDOWN_DEFAULT = 0, + KILL_QUERY= 254, + KILL_CONNECTION= 255 +}; + +enum enum_server_command +{ + COM_SLEEP = 0, + COM_QUIT, + COM_INIT_DB, + COM_QUERY, + COM_FIELD_LIST, + COM_CREATE_DB, + COM_DROP_DB, + COM_REFRESH, + COM_SHUTDOWN, + COM_STATISTICS, + COM_PROCESS_INFO, + COM_CONNECT, + COM_PROCESS_KILL, + COM_DEBUG, + COM_PING, + COM_TIME = 15, + COM_DELAYED_INSERT, + COM_CHANGE_USER, + COM_BINLOG_DUMP, + COM_TABLE_DUMP, + COM_CONNECT_OUT = 20, + COM_REGISTER_SLAVE, + COM_STMT_PREPARE = 22, + COM_STMT_EXECUTE = 23, + COM_STMT_SEND_LONG_DATA = 24, + COM_STMT_CLOSE = 25, + COM_STMT_RESET = 26, + COM_SET_OPTION = 27, + COM_STMT_FETCH = 28, + COM_DAEMON= 29, + COM_UNSUPPORTED= 30, + COM_RESET_CONNECTION = 31, + COM_STMT_BULK_EXECUTE = 250, + COM_MULTI = 254, + COM_END +}; + + +#define NOT_NULL_FLAG 1 /* Field can't be NULL */ +#define PRI_KEY_FLAG 2 /* Field is part of a primary key */ +#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */ +#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */ +#define BLOB_FLAG 16 /* Field is a blob */ +#define UNSIGNED_FLAG 32 /* Field is unsigned */ +#define ZEROFILL_FLAG 64 /* Field is zerofill */ +#define BINARY_FLAG 128 +/* The following are only sent to new clients */ +#define ENUM_FLAG 256 /* field is an enum */ +#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ +#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */ +#define SET_FLAG 2048 /* field is a set */ +/* new since 3.23.58 */ +#define NO_DEFAULT_VALUE_FLAG 4096 /* Field doesn't have default value */ +#define ON_UPDATE_NOW_FLAG 8192 /* Field is set to NOW on UPDATE */ +/* end new */ +#define NUM_FLAG 32768 /* Field is num (for clients) */ +#define PART_KEY_FLAG 16384 /* Intern; Part of some key */ +#define GROUP_FLAG 32768 /* Intern: Group field */ +#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ + +#define REFRESH_GRANT 1 /* Refresh grant tables */ +#define REFRESH_LOG 2 /* Start on new log file */ +#define REFRESH_TABLES 4 /* close all tables */ +#define REFRESH_HOSTS 8 /* Flush host cache */ +#define REFRESH_STATUS 16 /* Flush status variables */ +#define REFRESH_THREADS 32 /* Flush thread cache */ +#define REFRESH_SLAVE 64 /* Reset master info and restart slave + thread */ +#define REFRESH_MASTER 128 /* Remove all bin logs in the index + and truncate the index */ + +/* The following can't be set with mysql_refresh() */ +#define REFRESH_READ_LOCK 16384 /* Lock tables for read */ +#define REFRESH_FAST 32768 /* Intern flag */ + +#define CLIENT_MYSQL 1 +#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ +#define CLIENT_LONG_FLAG 4 /* Get all column flags */ +#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ +#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ +#define CLIENT_COMPRESS 32 /* Can use compression protocol */ +#define CLIENT_ODBC 64 /* Odbc client */ +#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ +#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ +#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ +#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ +#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ +#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ +/* added in 4.x */ +#define CLIENT_PROTOCOL_41 512 +#define CLIENT_RESERVED 16384 +#define CLIENT_SECURE_CONNECTION 32768 +#define CLIENT_MULTI_STATEMENTS (1UL << 16) +#define CLIENT_MULTI_RESULTS (1UL << 17) +#define CLIENT_PS_MULTI_RESULTS (1UL << 18) +#define CLIENT_PLUGIN_AUTH (1UL << 19) +#define CLIENT_CONNECT_ATTRS (1UL << 20) +#define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1UL << 22) +#define CLIENT_SESSION_TRACKING (1UL << 23) +#define CLIENT_PROGRESS (1UL << 29) /* client supports progress indicator */ +#define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS +#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) +#define CLIENT_REMEMBER_OPTIONS (1UL << 31) + +/* MariaDB specific capabilities */ +#define MARIADB_CLIENT_FLAGS 0xFFFFFFFF00000000ULL +#define MARIADB_CLIENT_PROGRESS (1ULL << 32) +#define MARIADB_CLIENT_COM_MULTI (1ULL << 33) +#define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34) + +#define IS_MARIADB_EXTENDED_SERVER(mysql)\ + !(mysql->server_capabilities & CLIENT_MYSQL) + +#define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\ + MARIADB_CLIENT_COM_MULTI |\ + MARIADB_CLIENT_STMT_BULK_OPERATIONS) + +#define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\ + CLIENT_FOUND_ROWS |\ + CLIENT_LONG_FLAG |\ + CLIENT_CONNECT_WITH_DB |\ + CLIENT_NO_SCHEMA |\ + CLIENT_COMPRESS |\ + CLIENT_ODBC |\ + CLIENT_LOCAL_FILES |\ + CLIENT_IGNORE_SPACE |\ + CLIENT_INTERACTIVE |\ + CLIENT_SSL |\ + CLIENT_IGNORE_SIGPIPE |\ + CLIENT_TRANSACTIONS |\ + CLIENT_PROTOCOL_41 |\ + CLIENT_RESERVED |\ + CLIENT_SECURE_CONNECTION |\ + CLIENT_MULTI_STATEMENTS |\ + CLIENT_MULTI_RESULTS |\ + CLIENT_PROGRESS |\ + CLIENT_SSL_VERIFY_SERVER_CERT |\ + CLIENT_REMEMBER_OPTIONS |\ + CLIENT_PLUGIN_AUTH |\ + CLIENT_SESSION_TRACKING |\ + CLIENT_CONNECT_ATTRS) + +#define CLIENT_CAPABILITIES (CLIENT_MYSQL | \ + CLIENT_LONG_FLAG |\ + CLIENT_TRANSACTIONS |\ + CLIENT_SECURE_CONNECTION |\ + CLIENT_MULTI_RESULTS | \ + CLIENT_PS_MULTI_RESULTS |\ + CLIENT_PROTOCOL_41 |\ + CLIENT_PLUGIN_AUTH |\ + CLIENT_SESSION_TRACKING |\ + CLIENT_CONNECT_ATTRS) + +#define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\ + & ~CLIENT_SSL) + +#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ +#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ +#define SERVER_MORE_RESULTS_EXIST 8 +#define SERVER_QUERY_NO_GOOD_INDEX_USED 16 +#define SERVER_QUERY_NO_INDEX_USED 32 +#define SERVER_STATUS_CURSOR_EXISTS 64 +#define SERVER_STATUS_LAST_ROW_SENT 128 +#define SERVER_STATUS_DB_DROPPED 256 +#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 +#define SERVER_STATUS_METADATA_CHANGED 1024 +#define SERVER_QUERY_WAS_SLOW 2048 +#define SERVER_PS_OUT_PARAMS 4096 +#define SERVER_STATUS_IN_TRANS_READONLY 8192 +#define SERVER_SESSION_STATE_CHANGED 16384 +#define SERVER_STATUS_ANSI_QUOTES 32768 + +#define MYSQL_ERRMSG_SIZE 512 +#define NET_READ_TIMEOUT 30 /* Timeout on read */ +#define NET_WRITE_TIMEOUT 60 /* Timeout on write */ +#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ + +/* for server integration (mysqlbinlog) */ +#define LIST_PROCESS_HOST_LEN 64 +#define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" +#define MYSQL50_TABLE_NAME_PREFIX_LENGTH (sizeof(MYSQL50_TABLE_NAME_PREFIX)-1) +#define SAFE_NAME_LEN (NAME_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH) + +struct st_ma_pvio; +typedef struct st_ma_pvio MARIADB_PVIO; + +#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR column */ +#define MAX_BLOB_WIDTH 8192 /* Default width for blob */ + +/* the following defines were added for PHP's mysqli and pdo extensions: + see: CONC-56 +*/ +#define MAX_TINYINT_WIDTH 3 +#define MAX_SMALLINT_WIDTH 5 +#define MAX_MEDIUMINT_WIDTH 8 +#define MAX_INT_WIDTH 10 +#define MAX_BIGINT_WIDTH 20 + +struct st_ma_connection_plugin; + + +typedef struct st_net { + MARIADB_PVIO *pvio; + unsigned char *buff; + unsigned char *buff_end,*write_pos,*read_pos; + my_socket fd; /* For Perl DBI/dbd */ + unsigned long remain_in_buf,length; + unsigned long buf_length, where_b; + unsigned long max_packet, max_packet_size; + unsigned int pkt_nr, compress_pkt_nr; + unsigned int write_timeout, read_timeout, retry_count; + int fcntl; + unsigned int *return_status; + unsigned char reading_or_writing; + char save_char; + char unused_1; + my_bool unused_2; + my_bool compress; + my_bool unused_3; + void *unused_4; + unsigned int last_errno; + unsigned char error; + my_bool unused_5; + my_bool unused_6; + char last_error[MYSQL_ERRMSG_SIZE]; + char sqlstate[SQLSTATE_LENGTH+1]; + struct st_mariadb_net_extension *extension; +} NET; + +#define packet_error ((unsigned int) -1) + +/* used by mysql_set_server_option */ +enum enum_mysql_set_option +{ + MYSQL_OPTION_MULTI_STATEMENTS_ON, + MYSQL_OPTION_MULTI_STATEMENTS_OFF +}; + +enum enum_session_state_type +{ + SESSION_TRACK_SYSTEM_VARIABLES= 0, + SESSION_TRACK_SCHEMA, + SESSION_TRACK_STATE_CHANGE, + /* currently not supported by MariaDB Server */ + SESSION_TRACK_GTIDS, + SESSION_TRACK_TRANSACTION_CHARACTERISTICS, + SESSION_TRACK_TRANSACTION_TYPE /* make sure that SESSION_TRACK_END always points + to last element of enum !! */ +}; + +#define SESSION_TRACK_BEGIN 0 +#define SESSION_TRACK_END SESSION_TRACK_TRANSACTION_TYPE +#define SESSION_TRACK_TYPES SESSION_TRACK_END + 1 + +enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, + MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, + MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, + MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, + MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, + MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, + MYSQL_TYPE_BIT, + /* + the following types are not used by client, + only for mysqlbinlog!! + */ + MYSQL_TYPE_TIMESTAMP2, + MYSQL_TYPE_DATETIME2, + MYSQL_TYPE_TIME2, + /* --------------------------------------------- */ + MYSQL_TYPE_JSON=245, + MYSQL_TYPE_NEWDECIMAL=246, + MYSQL_TYPE_ENUM=247, + MYSQL_TYPE_SET=248, + MYSQL_TYPE_TINY_BLOB=249, + MYSQL_TYPE_MEDIUM_BLOB=250, + MYSQL_TYPE_LONG_BLOB=251, + MYSQL_TYPE_BLOB=252, + MYSQL_TYPE_VAR_STRING=253, + MYSQL_TYPE_STRING=254, + MYSQL_TYPE_GEOMETRY=255, + MAX_NO_FIELD_TYPES }; + +#define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compatibility */ +#define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compatibility */ +#define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL +#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL +#define FIELD_TYPE_TINY MYSQL_TYPE_TINY +#define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT +#define FIELD_TYPE_LONG MYSQL_TYPE_LONG +#define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT +#define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE +#define FIELD_TYPE_NULL MYSQL_TYPE_NULL +#define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP +#define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG +#define FIELD_TYPE_INT24 MYSQL_TYPE_INT24 +#define FIELD_TYPE_DATE MYSQL_TYPE_DATE +#define FIELD_TYPE_TIME MYSQL_TYPE_TIME +#define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME +#define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR +#define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE +#define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM +#define FIELD_TYPE_SET MYSQL_TYPE_SET +#define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB +#define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB +#define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB +#define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB +#define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING +#define FIELD_TYPE_STRING MYSQL_TYPE_STRING +#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY +#define FIELD_TYPE_BIT MYSQL_TYPE_BIT + +extern unsigned long max_allowed_packet; +extern unsigned long net_buffer_length; + +#define net_new_transaction(net) ((net)->pkt_nr=0) + +int ma_net_init(NET *net, MARIADB_PVIO *pvio); +void ma_net_end(NET *net); +void ma_net_clear(NET *net); +int ma_net_flush(NET *net); +int ma_net_write(NET *net,const unsigned char *packet, size_t len); +int ma_net_write_command(NET *net,unsigned char command,const char *packet, + size_t len, my_bool disable_flush); +int ma_net_real_write(NET *net,const char *packet, size_t len); +extern unsigned long ma_net_read(NET *net); + +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + + /* The following is for user defined functions */ + +enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT,ROW_RESULT,DECIMAL_RESULT}; + +typedef struct st_udf_args +{ + unsigned int arg_count; /* Number of arguments */ + enum Item_result *arg_type; /* Pointer to item_results */ + char **args; /* Pointer to argument */ + unsigned long *lengths; /* Length of string arguments */ + char *maybe_null; /* Set to 1 for all maybe_null args */ +} UDF_ARGS; + + /* This holds information about the result */ + +typedef struct st_udf_init +{ + my_bool maybe_null; /* 1 if function can return NULL */ + unsigned int decimals; /* for real functions */ + unsigned int max_length; /* For string functions */ + char *ptr; /* free pointer for function data */ + my_bool const_item; /* 0 if result is independent of arguments */ +} UDF_INIT; + +/* Connection types */ +#define MARIADB_CONNECTION_UNIXSOCKET 0 +#define MARIADB_CONNECTION_TCP 1 +#define MARIADB_CONNECTION_NAMEDPIPE 2 +#define MARIADB_CONNECTION_SHAREDMEM 3 + + /* Constants when using compression */ +#define NET_HEADER_SIZE 4 /* standard header size */ +#define COMP_HEADER_SIZE 3 /* compression header extra size */ + + /* Prototypes to password functions */ +#define native_password_plugin_name "mysql_native_password" +#define old_password_plugin_name "mysql_old_password" + +#ifdef __cplusplus +extern "C" { +#endif + +char *ma_scramble_323(char *to,const char *message,const char *password); +void ma_scramble_41(const unsigned char *buffer, const char *scramble, const char *password); +void ma_hash_password(unsigned long *result, const char *password, size_t len); +void ma_make_scrambled_password(char *to,const char *password); + +/* Some other useful functions */ + +void mariadb_load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv); +my_bool ma_thread_init(void); +void ma_thread_end(void); + +#ifdef __cplusplus +} +#endif + +#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */ + +#endif diff --git a/include/mysql/mariadb_ctype.h b/include/mysql/mariadb_ctype.h new file mode 100644 index 0000000..bc65fcd --- /dev/null +++ b/include/mysql/mariadb_ctype.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ + +/* + A better inplementation of the UNIX ctype(3) library. + Notes: my_global.h should be included before ctype.h +*/ + +#ifndef _mariadb_ctype_h +#define _mariadb_ctype_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CHARSET_DIR "charsets/" +#define MY_CS_NAME_SIZE 32 + +#define MADB_DEFAULT_CHARSET_NAME "latin1" +#define MADB_DEFAULT_COLLATION_NAME "latin1_swedish_ci" +#define MADB_AUTODETECT_CHARSET_NAME "auto" + +/* we use the mysqlnd implementation */ +typedef struct ma_charset_info_st +{ + unsigned int nr; /* so far only 1 byte for charset */ + unsigned int state; + const char *csname; + const char *name; + const char *dir; + unsigned int codepage; + const char *encoding; + unsigned int char_minlen; + unsigned int char_maxlen; + unsigned int (*mb_charlen)(unsigned int c); + unsigned int (*mb_valid)(const char *start, const char *end); +} MARIADB_CHARSET_INFO; + +extern const MARIADB_CHARSET_INFO mariadb_compiled_charsets[]; +extern MARIADB_CHARSET_INFO *ma_default_charset_info; +extern MARIADB_CHARSET_INFO *ma_charset_bin; +extern MARIADB_CHARSET_INFO *ma_charset_latin1; +extern MARIADB_CHARSET_INFO *ma_charset_utf8_general_ci; +extern MARIADB_CHARSET_INFO *ma_charset_utf16le_general_ci; + +MARIADB_CHARSET_INFO *find_compiled_charset(unsigned int cs_number); +MARIADB_CHARSET_INFO *find_compiled_charset_by_name(const char *name); + +size_t mysql_cset_escape_quotes(const MARIADB_CHARSET_INFO *cset, char *newstr, const char *escapestr, size_t escapestr_len); +size_t mysql_cset_escape_slashes(const MARIADB_CHARSET_INFO *cset, char *newstr, const char *escapestr, size_t escapestr_len); +const char* madb_get_os_character_set(void); +#ifdef _WIN32 +int madb_get_windows_cp(const char *charset); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mysql/mariadb_dyncol.h b/include/mysql/mariadb_dyncol.h new file mode 100644 index 0000000..a6084fd --- /dev/null +++ b/include/mysql/mariadb_dyncol.h @@ -0,0 +1,256 @@ +/* Copyright (c) 2011, Monty Program Ab + Copyright (c) 2011, Oleksandr Byelkin + + 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 the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY ``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 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. +*/ + +#ifndef ma_dyncol_h +#define ma_dyncol_h + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LIBMARIADB +#include +#include +#endif +#include + +#ifndef longlong_defined +#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8 +typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ +typedef long long int longlong; +#else +typedef unsigned long ulonglong; /* ulong or unsigned long long */ +typedef long longlong; +#endif +#define longlong_defined +#endif + + +#ifndef _my_sys_h +typedef struct st_dynamic_string +{ + char *str; + size_t length,max_length,alloc_increment; +} DYNAMIC_STRING; +#endif + +struct st_mysql_lex_string +{ + char *str; + size_t length; +}; +typedef struct st_mysql_lex_string MYSQL_LEX_STRING; +typedef struct st_mysql_lex_string LEX_STRING; +/* + Limits of implementation +*/ +#define MAX_TOTAL_NAME_LENGTH 65535 +#define MAX_NAME_LENGTH (MAX_TOTAL_NAME_LENGTH/4) + +/* NO and OK is the same used just to show semantics */ +#define ER_DYNCOL_NO ER_DYNCOL_OK + +enum enum_dyncol_func_result +{ + ER_DYNCOL_OK= 0, + ER_DYNCOL_YES= 1, /* For functions returning 0/1 */ + ER_DYNCOL_FORMAT= -1, /* Wrong format of the encoded string */ + ER_DYNCOL_LIMIT= -2, /* Some limit reached */ + ER_DYNCOL_RESOURCE= -3, /* Out of resourses */ + ER_DYNCOL_DATA= -4, /* Incorrect input data */ + ER_DYNCOL_UNKNOWN_CHARSET= -5, /* Unknown character set */ + ER_DYNCOL_TRUNCATED= 2 /* OK, but data was truncated */ +}; + +typedef DYNAMIC_STRING DYNAMIC_COLUMN; + +enum enum_dynamic_column_type +{ + DYN_COL_NULL= 0, + DYN_COL_INT, + DYN_COL_UINT, + DYN_COL_DOUBLE, + DYN_COL_STRING, + DYN_COL_DECIMAL, + DYN_COL_DATETIME, + DYN_COL_DATE, + DYN_COL_TIME, + DYN_COL_DYNCOL +}; + +typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE; + +struct st_dynamic_column_value +{ + DYNAMIC_COLUMN_TYPE type; + union + { + long long long_value; + unsigned long long ulong_value; + double double_value; + struct { + MYSQL_LEX_STRING value; + MARIADB_CHARSET_INFO *charset; + } string; +#ifndef LIBMARIADB + struct { + decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; + decimal_t value; + } decimal; +#endif + MYSQL_TIME time_value; + } x; +}; + +typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE; + +#ifdef MADYNCOL_DEPRECATED +enum enum_dyncol_func_result +dynamic_column_create(DYNAMIC_COLUMN *str, + uint column_nr, DYNAMIC_COLUMN_VALUE *value); + +enum enum_dyncol_func_result +dynamic_column_create_many(DYNAMIC_COLUMN *str, + uint column_count, + uint *column_numbers, + DYNAMIC_COLUMN_VALUE *values); +enum enum_dyncol_func_result +dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr, + DYNAMIC_COLUMN_VALUE *value); +enum enum_dyncol_func_result +dynamic_column_update_many(DYNAMIC_COLUMN *str, + uint add_column_count, + uint *column_numbers, + DYNAMIC_COLUMN_VALUE *values); + +enum enum_dyncol_func_result +dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr); + +enum enum_dyncol_func_result +dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint); + +enum enum_dyncol_func_result +dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr, + DYNAMIC_COLUMN_VALUE *store_it_here); +#endif + +/* new functions */ +enum enum_dyncol_func_result +mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str, + uint column_count, + uint *column_numbers, + DYNAMIC_COLUMN_VALUE *values, + my_bool new_string); +enum enum_dyncol_func_result +mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str, + uint column_count, + MYSQL_LEX_STRING *column_keys, + DYNAMIC_COLUMN_VALUE *values, + my_bool new_string); + + +enum enum_dyncol_func_result +mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str, + uint add_column_count, + uint *column_keys, + DYNAMIC_COLUMN_VALUE *values); +enum enum_dyncol_func_result +mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str, + uint add_column_count, + MYSQL_LEX_STRING *column_keys, + DYNAMIC_COLUMN_VALUE *values); + + +enum enum_dyncol_func_result +mariadb_dyncol_exists_num(DYNAMIC_COLUMN *org, uint column_nr); +enum enum_dyncol_func_result +mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name); + +/* List of not NULL columns */ +enum enum_dyncol_func_result +mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums); +enum enum_dyncol_func_result +mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count, + MYSQL_LEX_STRING **names); + +/* + if the column do not exists it is NULL +*/ +enum enum_dyncol_func_result +mariadb_dyncol_get_num(DYNAMIC_COLUMN *org, uint column_nr, + DYNAMIC_COLUMN_VALUE *store_it_here); +enum enum_dyncol_func_result +mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name, + DYNAMIC_COLUMN_VALUE *store_it_here); + +my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str); + +enum enum_dyncol_func_result +mariadb_dyncol_check(DYNAMIC_COLUMN *str); + +enum enum_dyncol_func_result +mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json); + +void mariadb_dyncol_free(DYNAMIC_COLUMN *str); + +#define mariadb_dyncol_init(A) memset((A), 0, sizeof(DYNAMIC_COLUMN)) +#define dynamic_column_initialize(A) mariadb_dyncol_init((A)) +#define dynamic_column_column_free(A) mariadb_dyncol_free((A)) + +/* conversion of values to 3 base types */ +enum enum_dyncol_func_result +mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val, + MARIADB_CHARSET_INFO *cs, char quote); +enum enum_dyncol_func_result +mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val); +enum enum_dyncol_func_result +mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val); + +enum enum_dyncol_func_result +mariadb_dyncol_unpack(DYNAMIC_COLUMN *str, + uint *count, + MYSQL_LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals); + +int mariadb_dyncol_column_cmp_named(const MYSQL_LEX_STRING *s1, + const MYSQL_LEX_STRING *s2); + +enum enum_dyncol_func_result +mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count); + +#define mariadb_dyncol_value_init(V) (V)->type= DYN_COL_NULL + +/* + Prepare value for using as decimal +*/ +void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/mysql/mariadb_stmt.h b/include/mysql/mariadb_stmt.h new file mode 100644 index 0000000..40063bc --- /dev/null +++ b/include/mysql/mariadb_stmt.h @@ -0,0 +1,285 @@ +/************************************************************************ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA + + Part of this code includes code from PHP's mysqlnd extension + (written by Andrey Hristov, Georg Richter and Ulf Wendel), freely + available from http://www.php.net/software + +*************************************************************************/ + +#define MYSQL_NO_DATA 100 +#define MYSQL_DATA_TRUNCATED 101 +#define MYSQL_DEFAULT_PREFETCH_ROWS (unsigned long) 1 + +/* Bind flags */ +#define MADB_BIND_DUMMY 1 + +#define MARIADB_STMT_BULK_SUPPORTED(stmt)\ + ((stmt)->mysql && \ + (!((stmt)->mysql->server_capabilities & CLIENT_MYSQL) &&\ + ((stmt)->mysql->extension->mariadb_server_capabilities & \ + (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))) + +#define SET_CLIENT_STMT_ERROR(a, b, c, d) \ +{ \ + (a)->last_errno= (b);\ + strncpy((a)->sqlstate, (c), SQLSTATE_LENGTH);\ + strncpy((a)->last_error, (d) ? (d) : ER((b)), MYSQL_ERRMSG_SIZE - 1);\ +} + +#define CLEAR_CLIENT_STMT_ERROR(a) \ +{ \ + (a)->last_errno= 0;\ + strcpy((a)->sqlstate, "00000");\ + (a)->last_error[0]= 0;\ +} + +#define MYSQL_PS_SKIP_RESULT_W_LEN -1 +#define MYSQL_PS_SKIP_RESULT_STR -2 +#define STMT_ID_LENGTH 4 + + +typedef struct st_mysql_stmt MYSQL_STMT; + +typedef MYSQL_RES* (*mysql_stmt_use_or_store_func)(MYSQL_STMT *); + +enum enum_stmt_attr_type +{ + STMT_ATTR_UPDATE_MAX_LENGTH, + STMT_ATTR_CURSOR_TYPE, + STMT_ATTR_PREFETCH_ROWS, + STMT_ATTR_PREBIND_PARAMS=200, + STMT_ATTR_ARRAY_SIZE, + STMT_ATTR_ROW_SIZE, + STMT_ATTR_STATE +}; + +enum enum_cursor_type +{ + CURSOR_TYPE_NO_CURSOR= 0, + CURSOR_TYPE_READ_ONLY= 1, + CURSOR_TYPE_FOR_UPDATE= 2, + CURSOR_TYPE_SCROLLABLE= 4 +}; + +enum enum_indicator_type +{ + STMT_INDICATOR_NTS=-1, + STMT_INDICATOR_NONE=0, + STMT_INDICATOR_NULL=1, + STMT_INDICATOR_DEFAULT=2, + STMT_INDICATOR_IGNORE=3, + STMT_INDICATOR_IGNORE_ROW=4 +}; + +/* + bulk PS flags +*/ +#define STMT_BULK_FLAG_CLIENT_SEND_TYPES 128 +#define STMT_BULK_FLAG_INSERT_ID_REQUEST 64 + +typedef enum mysql_stmt_state +{ + MYSQL_STMT_INITTED = 0, + MYSQL_STMT_PREPARED, + MYSQL_STMT_EXECUTED, + MYSQL_STMT_WAITING_USE_OR_STORE, + MYSQL_STMT_USE_OR_STORE_CALLED, + MYSQL_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */ + MYSQL_STMT_FETCH_DONE +} enum_mysqlnd_stmt_state; + +typedef struct st_mysql_bind +{ + unsigned long *length; /* output length pointer */ + my_bool *is_null; /* Pointer to null indicator */ + void *buffer; /* buffer to get/put data */ + /* set this if you want to track data truncations happened during fetch */ + my_bool *error; + union { + unsigned char *row_ptr; /* for the current data position */ + char *indicator; /* indicator variable */ + } u; + void (*store_param_func)(NET *net, struct st_mysql_bind *param); + void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + /* output buffer length, must be set when fetching str/binary */ + unsigned long buffer_length; + unsigned long offset; /* offset position for char/binary fetch */ + unsigned long length_value; /* Used if length is 0 */ + unsigned int flags; /* special flags, e.g. for dummy bind */ + unsigned int pack_length; /* Internal length for packed data */ + enum enum_field_types buffer_type; /* buffer type */ + my_bool error_value; /* used if error is 0 */ + my_bool is_unsigned; /* set if integer type is unsigned */ + my_bool long_data_used; /* If used with mysql_send_long_data */ + my_bool is_null_value; /* Used if is_null is 0 */ + void *extension; +} MYSQL_BIND; + +typedef struct st_mysqlnd_upsert_result +{ + unsigned int warning_count; + unsigned int server_status; + unsigned long long affected_rows; + unsigned long long last_insert_id; +} mysql_upsert_status; + +typedef struct st_mysql_cmd_buffer +{ + unsigned char *buffer; + size_t length; +} MYSQL_CMD_BUFFER; + +typedef struct st_mysql_error_info +{ + unsigned int error_no; + char error[MYSQL_ERRMSG_SIZE+1]; + char sqlstate[SQLSTATE_LENGTH + 1]; +} mysql_error_info; + + +struct st_mysqlnd_stmt_methods +{ + my_bool (*prepare)(const MYSQL_STMT * stmt, const char * const query, size_t query_len); + my_bool (*execute)(const MYSQL_STMT * stmt); + MYSQL_RES * (*use_result)(const MYSQL_STMT * stmt); + MYSQL_RES * (*store_result)(const MYSQL_STMT * stmt); + MYSQL_RES * (*get_result)(const MYSQL_STMT * stmt); + my_bool (*free_result)(const MYSQL_STMT * stmt); + my_bool (*seek_data)(const MYSQL_STMT * stmt, unsigned long long row); + my_bool (*reset)(const MYSQL_STMT * stmt); + my_bool (*close)(const MYSQL_STMT * stmt); /* private */ + my_bool (*dtor)(const MYSQL_STMT * stmt); /* use this for mysqlnd_stmt_close */ + + my_bool (*fetch)(const MYSQL_STMT * stmt, my_bool * const fetched_anything); + + my_bool (*bind_param)(const MYSQL_STMT * stmt, const MYSQL_BIND bind); + my_bool (*refresh_bind_param)(const MYSQL_STMT * stmt); + my_bool (*bind_result)(const MYSQL_STMT * stmt, const MYSQL_BIND *bind); + my_bool (*send_long_data)(const MYSQL_STMT * stmt, unsigned int param_num, + const char * const data, size_t length); + MYSQL_RES *(*get_parameter_metadata)(const MYSQL_STMT * stmt); + MYSQL_RES *(*get_result_metadata)(const MYSQL_STMT * stmt); + unsigned long long (*get_last_insert_id)(const MYSQL_STMT * stmt); + unsigned long long (*get_affected_rows)(const MYSQL_STMT * stmt); + unsigned long long (*get_num_rows)(const MYSQL_STMT * stmt); + + unsigned int (*get_param_count)(const MYSQL_STMT * stmt); + unsigned int (*get_field_count)(const MYSQL_STMT * stmt); + unsigned int (*get_warning_count)(const MYSQL_STMT * stmt); + + unsigned int (*get_error_no)(const MYSQL_STMT * stmt); + const char * (*get_error_str)(const MYSQL_STMT * stmt); + const char * (*get_sqlstate)(const MYSQL_STMT * stmt); + + my_bool (*get_attribute)(const MYSQL_STMT * stmt, enum enum_stmt_attr_type attr_type, const void * value); + my_bool (*set_attribute)(const MYSQL_STMT * stmt, enum enum_stmt_attr_type attr_type, const void * value); + void (*set_error)(MYSQL_STMT *stmt, unsigned int error_nr, const char *sqlstate, const char *format, ...); +}; + +typedef int (*mysql_stmt_fetch_row_func)(MYSQL_STMT *stmt, unsigned char **row); + +struct st_mysql_stmt +{ + MA_MEM_ROOT mem_root; + MYSQL *mysql; + unsigned long stmt_id; + unsigned long flags;/* cursor is set here */ + enum_mysqlnd_stmt_state state; + MYSQL_FIELD *fields; + unsigned int field_count; + unsigned int param_count; + unsigned char send_types_to_server; + MYSQL_BIND *params; + MYSQL_BIND *bind; + MYSQL_DATA result; /* we don't use mysqlnd's result set logic */ + MYSQL_ROWS *result_cursor; + my_bool bind_result_done; + my_bool bind_param_done; + + mysql_upsert_status upsert_status; + + unsigned int last_errno; + char last_error[MYSQL_ERRMSG_SIZE+1]; + char sqlstate[SQLSTATE_LENGTH + 1]; + + my_bool update_max_length; + unsigned long prefetch_rows; + LIST list; + + my_bool cursor_exists; + + void *extension; + mysql_stmt_fetch_row_func fetch_row_func; + unsigned int execute_count;/* count how many times the stmt was executed */ + mysql_stmt_use_or_store_func default_rset_handler; + struct st_mysqlnd_stmt_methods *m; + unsigned int array_size; + size_t row_size; + unsigned int prebind_params; +}; + +typedef void (*ps_field_fetch_func)(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row); +typedef struct st_mysql_perm_bind { + ps_field_fetch_func func; + /* should be signed int */ + int pack_len; + unsigned long max_len; +} MYSQL_PS_CONVERSION; + +extern MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1]; +unsigned long ma_net_safe_read(MYSQL *mysql); +void mysql_init_ps_subsystem(void); +unsigned long net_field_length(unsigned char **packet); +int ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, + size_t length, my_bool skipp_check, void *opt_arg); +/* + * function prototypes + */ +MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql); +int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length); +int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, unsigned int column, unsigned long offset); +int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); +unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr); +my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr); +my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); +my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length); +MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt); +MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt); +void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, unsigned long long offset); +unsigned long long STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt); +unsigned long long STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); +unsigned long long STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt); +my_bool STDCALL mysql_stmt_more_results(MYSQL_STMT *stmt); +int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, const char *stmt_str, size_t length); diff --git a/include/mysql/mariadb_version.h b/include/mysql/mariadb_version.h new file mode 100644 index 0000000..be36917 --- /dev/null +++ b/include/mysql/mariadb_version.h @@ -0,0 +1,36 @@ +/* Copyright Abandoned 1996, 1999, 2001 MySQL AB + This file is public domain and comes with NO WARRANTY of any kind */ + +/* Version numbers for protocol & mysqld */ + +#ifndef _mariadb_version_h_ +#define _mariadb_version_h_ + +#ifdef _CUSTOMCONFIG_ +#include +#else +#define PROTOCOL_VERSION 10 +#define MARIADB_CLIENT_VERSION_STR "10.3.6" +#define MARIADB_BASE_VERSION "mariadb-10.3" +#define MARIADB_VERSION_ID 100306 +#define MYSQL_VERSION_ID 100306 +#define MARIADB_PORT 3306 +#define MARIADB_UNIX_ADDR "/tmp/mysql.sock" +#define MYSQL_CONFIG_NAME "my" + +#define MARIADB_PACKAGE_VERSION "3.0.8" +#define MARIADB_PACKAGE_VERSION_ID 30008 +#define MARIADB_SYSTEM_TYPE "Windows" +#define MARIADB_MACHINE_TYPE "AMD64" +#define MARIADB_PLUGINDIR "lib/mariadb/plugin" + +/* mysqld compile time options */ +#ifndef MYSQL_CHARSET +#define MYSQL_CHARSET "" +#endif +#endif + +/* Source information */ +#define CC_SOURCE_REVISION "" + +#endif /* _mariadb_version_h_ */ diff --git a/include/mysql/mariadb_version.h.in b/include/mysql/mariadb_version.h.in new file mode 100644 index 0000000..bab58ce --- /dev/null +++ b/include/mysql/mariadb_version.h.in @@ -0,0 +1,38 @@ +/* Copyright Abandoned 1996, 1999, 2001 MySQL AB + This file is public domain and comes with NO WARRANTY of any kind */ + +/* Version numbers for protocol & mysqld */ + +#ifndef _mariadb_version_h_ +#define _mariadb_version_h_ + +#ifdef _CUSTOMCONFIG_ +#include +#else +#define PROTOCOL_VERSION @PROTOCOL_VERSION@ +#define MARIADB_CLIENT_VERSION_STR "@MARIADB_CLIENT_VERSION@" +#define MARIADB_BASE_VERSION "@MARIADB_BASE_VERSION@" +#define MARIADB_VERSION_ID @MARIADB_VERSION_ID@ +#define MARIADB_PORT @MARIADB_PORT@ +#define MARIADB_UNIX_ADDR "@MARIADB_UNIX_ADDR@" + +#define MYSQL_CONFIG_NAME "my" +#define MYSQL_VERSION_ID @MARIADB_VERSION_ID@ +#define MYSQL_SERVER_VERSION "@MARIADB_CLIENT_VERSION@-MariaDB" + +#define MARIADB_PACKAGE_VERSION "@CPACK_PACKAGE_VERSION@" +#define MARIADB_PACKAGE_VERSION_ID @MARIADB_PACKAGE_VERSION_ID@ +#define MARIADB_SYSTEM_TYPE "@CMAKE_SYSTEM_NAME@" +#define MARIADB_MACHINE_TYPE "@CMAKE_SYSTEM_PROCESSOR@" +#define MARIADB_PLUGINDIR "@PLUGINDIR@" + +/* mysqld compile time options */ +#ifndef MYSQL_CHARSET +#define MYSQL_CHARSET "@default_charset@" +#endif +#endif + +/* Source information */ +#define CC_SOURCE_REVISION "@CC_SOURCE_REVISION@" + +#endif /* _mariadb_version_h_ */ diff --git a/include/mysql/mysql.h b/include/mysql/mysql.h index d930b2c..08525e8 100644 --- a/include/mysql/mysql.h +++ b/include/mysql/mysql.h @@ -28,19 +28,22 @@ extern "C" { #ifndef LIBMARIADB #define LIBMARIADB #endif +#ifndef MYSQL_CLIENT +#define MYSQL_CLIENT +#endif + +#include -#ifndef _global_h /* If not standard header */ +#if !defined (_global_h) && !defined (MY_GLOBAL_INCLUDED) /* If not standard header */ #include typedef char my_bool; +typedef unsigned long long my_ulonglong; #if !defined(_WIN32) #define STDCALL #else #define STDCALL __stdcall #endif -typedef char * gptr; - - #ifndef my_socket_defined #define my_socket_defined @@ -53,29 +56,29 @@ typedef int my_socket; #endif #endif #endif -#include "mysql_com.h" -#include "mysql_version.h" -#include "my_list.h" -#include "m_ctype.h" - -#ifndef ST_USED_MEM_DEFINED -#define ST_USED_MEM_DEFINED - typedef struct st_used_mem { /* struct for once_alloc */ - struct st_used_mem *next; /* Next block in use */ +#include "mariadb_com.h" +#include "mariadb_version.h" +#include "ma_list.h" +#include "mariadb_ctype.h" + +#ifndef ST_MA_USED_MEM_DEFINED +#define ST_MA_USED_MEM_DEFINED + typedef struct st_ma_used_mem { /* struct for once_alloc */ + struct st_ma_used_mem *next; /* Next block in use */ size_t left; /* memory left in block */ size_t size; /* Size of block */ - } USED_MEM; + } MA_USED_MEM; - typedef struct st_mem_root { - USED_MEM *free; - USED_MEM *used; - USED_MEM *pre_alloc; + typedef struct st_ma_mem_root { + MA_USED_MEM *free; + MA_USED_MEM *used; + MA_USED_MEM *pre_alloc; size_t min_malloc; size_t block_size; unsigned int block_num; unsigned int first_block_usage; void (*error_handler)(void); - } MEM_ROOT; + } MA_MEM_ROOT; #endif extern unsigned int mysql_port; @@ -85,7 +88,7 @@ extern unsigned int mariadb_deinitialize_ssl; #define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) #define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) #define IS_BLOB(n) ((n) & BLOB_FLAG) -#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR) +#define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) #define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG) #define INTERNAL_NUM_FIELD(f) (((f)->type <= MYSQL_TYPE_INT24 && ((f)->type != MYSQL_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == MYSQL_TYPE_YEAR || (f)->type == MYSQL_TYPE_NEWDECIMAL || (f)->type == MYSQL_TYPE_DECIMAL) @@ -118,26 +121,16 @@ extern unsigned int mariadb_deinitialize_ssl; typedef char **MYSQL_ROW; /* return data as array of strings */ typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */ -#if defined(NO_CLIENT_LONG_LONG) - typedef unsigned long my_ulonglong; -#elif defined (_WIN32) - typedef unsigned __int64 my_ulonglong; -#else - typedef unsigned long long my_ulonglong; -#endif - -/* mysql compatibility macro */ -#define mysql_options4(A,B,C,D) mysql_optionsv((A),(B),(C),(D)) - #define SET_CLIENT_ERROR(a, b, c, d) \ { \ (a)->net.last_errno= (b);\ - strncpy((a)->net.sqlstate, (c), sizeof((a)->net.sqlstate));\ - strncpy((a)->net.last_error, (d) ? (d) : ER((b)), sizeof((a)->net.last_error));\ + strncpy((a)->net.sqlstate, (c), SQLSTATE_LENGTH);\ + strncpy((a)->net.last_error, (d) ? (d) : ER((b)), MYSQL_ERRMSG_SIZE - 1);\ } /* For mysql_async.c */ -#define set_mysql_error(A,B,C) SET_CLIENT_ERROR((A),(B),(C),0) +#define set_mariadb_error(A,B,C) SET_CLIENT_ERROR((A),(B),(C),0) +extern const char *SQLSTATE_UNKNOWN; #define unknown_sqlstate SQLSTATE_UNKNOWN #define CLEAR_CLIENT_ERROR(a) \ @@ -147,7 +140,7 @@ extern unsigned int mariadb_deinitialize_ssl; (a)->net.last_error[0]= '\0';\ } -#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0) +#define MYSQL_COUNT_ERROR (~(unsigned long long) 0) typedef struct st_mysql_rows { @@ -159,10 +152,12 @@ extern unsigned int mariadb_deinitialize_ssl; typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ typedef struct st_mysql_data { - my_ulonglong rows; - unsigned int fields; MYSQL_ROWS *data; - MEM_ROOT alloc; + void *embedded_info; + MA_MEM_ROOT alloc; + unsigned long long rows; + unsigned int fields; + void *extension; } MYSQL_DATA; enum mysql_option @@ -205,15 +200,77 @@ extern unsigned int mariadb_deinitialize_ssl; MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, + MYSQL_OPT_SSL_ENFORCE, + MYSQL_OPT_MAX_ALLOWED_PACKET, + MYSQL_OPT_NET_BUFFER_LENGTH, + MYSQL_OPT_TLS_VERSION, /* MariaDB specific */ MYSQL_PROGRESS_CALLBACK=5999, MYSQL_OPT_NONBLOCK, /* MariaDB Connector/C specific */ MYSQL_DATABASE_DRIVER=7000, - MARIADB_OPT_SSL_FP, /* single finger print for server certificate verification */ - MARIADB_OPT_SSL_FP_LIST, /* finger print white list for server certificate verification */ - MARIADB_OPT_VERIFY_LOCAL_INFILE_CALLBACK + MARIADB_OPT_SSL_FP, /* deprecated, use MARIADB_OPT_TLS_PEER_FP instead */ + MARIADB_OPT_SSL_FP_LIST, /* deprecated, use MARIADB_OPT_TLS_PEER_FP_LIST instead */ + MARIADB_OPT_TLS_PASSPHRASE, /* passphrase for encrypted certificates */ + MARIADB_OPT_TLS_CIPHER_STRENGTH, + MARIADB_OPT_TLS_VERSION, + MARIADB_OPT_TLS_PEER_FP, /* single finger print for server certificate verification */ + MARIADB_OPT_TLS_PEER_FP_LIST, /* finger print white list for server certificate verification */ + MARIADB_OPT_CONNECTION_READ_ONLY, + MYSQL_OPT_CONNECT_ATTRS, /* for mysql_get_optionv */ + MARIADB_OPT_USERDATA, + MARIADB_OPT_CONNECTION_HANDLER, + MARIADB_OPT_PORT, + MARIADB_OPT_UNIXSOCKET, + MARIADB_OPT_PASSWORD, + MARIADB_OPT_HOST, + MARIADB_OPT_USER, + MARIADB_OPT_SCHEMA, + MARIADB_OPT_DEBUG, + MARIADB_OPT_FOUND_ROWS, + MARIADB_OPT_MULTI_RESULTS, + MARIADB_OPT_MULTI_STATEMENTS, + MARIADB_OPT_INTERACTIVE, + MARIADB_OPT_PROXY_HEADER + }; + + enum mariadb_value { + MARIADB_CHARSET_ID, + MARIADB_CHARSET_NAME, + MARIADB_CLIENT_ERRORS, + MARIADB_CLIENT_VERSION, + MARIADB_CLIENT_VERSION_ID, + MARIADB_CONNECTION_ASYNC_TIMEOUT, + MARIADB_CONNECTION_ASYNC_TIMEOUT_MS, + MARIADB_CONNECTION_MARIADB_CHARSET_INFO, + MARIADB_CONNECTION_ERROR, + MARIADB_CONNECTION_ERROR_ID, + MARIADB_CONNECTION_HOST, + MARIADB_CONNECTION_INFO, + MARIADB_CONNECTION_PORT, + MARIADB_CONNECTION_PROTOCOL_VERSION_ID, + MARIADB_CONNECTION_PVIO_TYPE, + MARIADB_CONNECTION_SCHEMA, + MARIADB_CONNECTION_SERVER_TYPE, + MARIADB_CONNECTION_SERVER_VERSION, + MARIADB_CONNECTION_SERVER_VERSION_ID, + MARIADB_CONNECTION_SOCKET, + MARIADB_CONNECTION_SQLSTATE, + MARIADB_CONNECTION_SSL_CIPHER, + MARIADB_TLS_LIBRARY, + MARIADB_CONNECTION_TLS_VERSION, + MARIADB_CONNECTION_TLS_VERSION_ID, + MARIADB_CONNECTION_TYPE, + MARIADB_CONNECTION_UNIX_SOCKET, + MARIADB_CONNECTION_USER, + MARIADB_MAX_ALLOWED_PACKET, + MARIADB_NET_BUFFER_LENGTH, + MARIADB_CONNECTION_SERVER_STATUS, + MARIADB_CONNECTION_SERVER_CAPABILITIES, + MARIADB_CONNECTION_EXTENDED_SERVER_CAPABILITIES, + MARIADB_CONNECTION_CLIENT_CAPABILITIES }; enum mysql_status { MYSQL_STATUS_READY, @@ -224,6 +281,7 @@ extern unsigned int mariadb_deinitialize_ssl; MYSQL_STATUS_FETCHING_DATA, MYSQL_STATUS_NEXT_RESULT_PENDING, MYSQL_STATUS_QUIT_SENT, /* object is "destroyed" at this stage */ + MYSQL_STATUS_STMT_RESULT }; enum mysql_protocol_type @@ -232,8 +290,6 @@ extern unsigned int mariadb_deinitialize_ssl; MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY }; -struct st_mysql_options_extension; - struct st_mysql_options { unsigned int connect_timeout, read_timeout, write_timeout; unsigned int port, protocol; @@ -250,7 +306,7 @@ struct st_mysql_options { unsigned long max_allowed_packet; my_bool use_ssl; /* if to use SSL or not */ my_bool compress,named_pipe; - my_bool unused_1, unused_2, unused_3, unused_4; + my_bool reconnect, unused_1, unused_2, unused_3; enum mysql_option methods_to_use; char *bind_address; my_bool secure_auth; @@ -260,7 +316,7 @@ struct st_mysql_options { int (*local_infile_read)(void *, char *, unsigned int); void (*local_infile_end)(void *); int (*local_infile_error)(void *, char *, unsigned int); - void *local_infile_userdata[2]; + void *local_infile_userdata; struct st_mysql_options_extension *extension; }; @@ -269,44 +325,45 @@ struct st_mysql_options { void *unused_0; char *host,*user,*passwd,*unix_socket,*server_version,*host_info; char *info,*db; - const struct charset_info_st *charset; /* character set */ + const struct ma_charset_info_st *charset; /* character set */ MYSQL_FIELD *fields; - MEM_ROOT field_alloc; - my_ulonglong affected_rows; - my_ulonglong insert_id; /* id if insert on table with NEXTNR */ - my_ulonglong extra_info; /* Used by mysqlshow */ + MA_MEM_ROOT field_alloc; + unsigned long long affected_rows; + unsigned long long insert_id; /* id if insert on table with NEXTNR */ + unsigned long long extra_info; /* Used by mysqlshow */ unsigned long thread_id; /* Id for connection in server */ unsigned long packet_length; - unsigned int port; - unsigned long client_flag,server_capabilities; /* changed from int to long in 4.1 protocol */ - unsigned int protocol_version; - unsigned int field_count; - unsigned int server_status; - unsigned int server_language; - unsigned int warning_count; /* warning count, added in 4.1 protocol */ + unsigned int port; + unsigned long client_flag; + unsigned long server_capabilities; + unsigned int protocol_version; + unsigned int field_count; + unsigned int server_status; + unsigned int server_language; + unsigned int warning_count; /* warning count, added in 4.1 protocol */ struct st_mysql_options options; enum mysql_status status; my_bool free_me; /* If free in mysql_close */ - my_bool reconnect; /* set to 1 if automatic reconnect */ + my_bool unused_1; char scramble_buff[20+ 1]; /* madded after 3.23.58 */ - my_bool unused_1; - void *unused_2, *unused_3, *unused_4, *unused_5; + my_bool unused_2; + void *unused_3, *unused_4, *unused_5, *unused_6; LIST *stmts; - const struct st_mysql_methods *methods; + const struct st_mariadb_methods *methods; void *thd; my_bool *unbuffered_fetch_owner; char *info_buffer; - void *extension; + struct st_mariadb_extension *extension; } MYSQL; typedef struct st_mysql_res { - my_ulonglong row_count; + unsigned long long row_count; unsigned int field_count, current_field; MYSQL_FIELD *fields; MYSQL_DATA *data; MYSQL_ROWS *data_cursor; - MEM_ROOT field_alloc; + MA_MEM_ROOT field_alloc; MYSQL_ROW row; /* If unbuffered read */ MYSQL_ROW current_row; /* buffer to current row */ unsigned long *lengths; /* column lengths of current row */ @@ -315,13 +372,20 @@ typedef struct st_mysql_res { my_bool is_ps; } MYSQL_RES; +typedef struct +{ + unsigned long *p_max_allowed_packet; + unsigned long *p_net_buffer_length; + void *extension; +} MYSQL_PARAMETERS; + +#ifndef _mysql_time_h_ enum enum_mysql_timestamp_type { MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 }; - typedef struct st_mysql_time { unsigned int year, month, day, hour, minute, second; @@ -329,8 +393,9 @@ typedef struct st_mysql_time my_bool neg; enum enum_mysql_timestamp_type time_type; } MYSQL_TIME; +#define AUTO_SEC_PART_DIGITS 39 +#endif -#define AUTO_SEC_PART_DIGITS 31 #define SEC_PART_DIGITS 6 #define MARIADB_INVALID_SOCKET -1 @@ -344,28 +409,50 @@ typedef struct character_set { unsigned int number; /* character set number */ unsigned int state; /* character set state */ - const char *csname; /* collation name */ - const char *name; /* character set name */ + const char *csname; /* character set name */ + const char *name; /* collation name */ const char *comment; /* comment */ const char *dir; /* character set directory */ unsigned int mbminlen; /* min. length for multibyte strings */ unsigned int mbmaxlen; /* max. length for multibyte strings */ } MY_CHARSET_INFO; -typedef struct -{ - unsigned long *p_max_allowed_packet; - unsigned long *p_net_buffer_length; - void *extension; -} MYSQL_PARAMETERS; - -#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length) -#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet) - /* Local infile support functions */ #define LOCAL_INFILE_ERROR_LEN 512 -#include "my_stmt.h" +#include "mariadb_stmt.h" + +#ifndef MYSQL_CLIENT_PLUGIN_HEADER +#define MYSQL_CLIENT_PLUGIN_HEADER \ + int type; \ + unsigned int interface_version; \ + const char *name; \ + const char *author; \ + const char *desc; \ + unsigned int version[3]; \ + const char *license; \ + void *mariadb_api; \ + int (*init)(char *, size_t, int, va_list); \ + int (*deinit)(); \ + int (*options)(const char *option, const void *); +struct st_mysql_client_plugin +{ + MYSQL_CLIENT_PLUGIN_HEADER +}; + +struct st_mysql_client_plugin * +mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, + int argc, ...); +struct st_mysql_client_plugin * STDCALL +mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, + int argc, va_list args); +struct st_mysql_client_plugin * STDCALL +mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); +struct st_mysql_client_plugin * STDCALL +mysql_client_register_plugin(struct st_mysql *mysql, + struct st_mysql_client_plugin *plugin); +#endif + void STDCALL mysql_set_local_infile_handler(MYSQL *mysql, int (*local_infile_init)(void **, const char *, void *), @@ -406,14 +493,13 @@ const char * STDCALL mysql_character_set_name(MYSQL *mysql); void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs); int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); +my_bool mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...); +my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg); MYSQL * STDCALL mysql_init(MYSQL *mysql); int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); -int STDCALL mysql_ssl_clear(MYSQL *mysql); -MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, - const char *user, const char *passwd); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db); MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, @@ -430,9 +516,7 @@ int STDCALL mysql_send_query(MYSQL *mysql, const char *q, unsigned long length); my_bool STDCALL mysql_read_query_result(MYSQL *mysql); int STDCALL mysql_real_query(MYSQL *mysql, const char *q, - unsigned long length); -int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); -int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); + unsigned long length); int STDCALL mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); int STDCALL mysql_dump_debug_info(MYSQL *mysql); int STDCALL mysql_refresh(MYSQL *mysql, @@ -453,9 +537,11 @@ MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg); +int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option, + const void *arg1, const void *arg2); void STDCALL mysql_free_result(MYSQL_RES *result); void STDCALL mysql_data_seek(MYSQL_RES *result, - my_ulonglong offset); + unsigned long long offset); MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET); MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); @@ -467,10 +553,6 @@ unsigned long STDCALL mysql_escape_string(char *to,const char *from, unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); -void STDCALL mysql_debug(const char *debug); -#define mysql_debug_init(A) mysql_debug((A)); -void STDCALL mysql_debug_end(void); -void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); unsigned int STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_sqlstate(MYSQL *mysql); @@ -484,36 +566,48 @@ const char * STDCALL mysql_get_client_info(void); unsigned long STDCALL mysql_get_client_version(void); my_bool STDCALL mariadb_connection(MYSQL *mysql); const char * STDCALL mysql_get_server_name(MYSQL *mysql); -CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *csname); -CHARSET_INFO * STDCALL mysql_get_charset_by_nr(unsigned int csnr); -size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs, - char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode); -int STDCALL mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...); -MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); +MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname); +MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr); +size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, MARIADB_CHARSET_INFO *from_cs, + char *to, size_t *to_len, MARIADB_CHARSET_INFO *to_cs, int *errorcode); +int mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...); +int mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...); +int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, void *arg); unsigned long STDCALL mysql_hex_string(char *to, const char *from, unsigned long len); -my_socket STDCALL mysql_get_socket(const MYSQL *mysql); +my_socket STDCALL mysql_get_socket(MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value(const MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value_ms(const MYSQL *mysql); +my_bool STDCALL mariadb_reconnect(MYSQL *mysql); +int STDCALL mariadb_cancel(MYSQL *mysql); +void STDCALL mysql_debug(const char *debug); +unsigned long STDCALL mysql_net_read_packet(MYSQL *mysql); +unsigned long STDCALL mysql_net_field_length(unsigned char **packet); +my_bool STDCALL mysql_embedded(void); +MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); /* Async API */ int STDCALL mysql_close_start(MYSQL *sock); int STDCALL mysql_close_cont(MYSQL *sock, int status); int STDCALL mysql_commit_start(my_bool *ret, MYSQL * mysql); int STDCALL mysql_commit_cont(my_bool *ret, MYSQL * mysql, int status); +int STDCALL mysql_dump_debug_info_cont(int *ret, MYSQL *mysql, int ready_status); +int STDCALL mysql_dump_debug_info_start(int *ret, MYSQL *mysql); int STDCALL mysql_rollback_start(my_bool *ret, MYSQL * mysql); int STDCALL mysql_rollback_cont(my_bool *ret, MYSQL * mysql, int status); int STDCALL mysql_autocommit_start(my_bool *ret, MYSQL * mysql, my_bool auto_mode); +int STDCALL mysql_list_fields_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status); +int STDCALL mysql_list_fields_start(MYSQL_RES **ret, MYSQL *mysql, const char *table, + const char *wild); int STDCALL mysql_autocommit_cont(my_bool *ret, MYSQL * mysql, int status); int STDCALL mysql_next_result_start(int *ret, MYSQL *mysql); int STDCALL mysql_next_result_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_select_db_start(int *ret, MYSQL *mysql, const char *db); int STDCALL mysql_select_db_cont(int *ret, MYSQL *mysql, int ready_status); +int STDCALL mysql_stmt_warning_count(MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result_cont(int *ret, MYSQL_STMT *stmt, int status); -int STDCALL mysql_stmt_close_start(my_bool *ret, MYSQL_STMT *stmt); -int STDCALL mysql_stmt_close_cont(my_bool *ret, MYSQL_STMT * stmt, int status); int STDCALL mysql_set_character_set_start(int *ret, MYSQL *mysql, const char *csname); int STDCALL mysql_set_character_set_cont(int *ret, MYSQL *mysql, @@ -573,7 +667,6 @@ int STDCALL mysql_stat_cont(const char **ret, MYSQL *mysql, int status); int STDCALL mysql_free_result_start(MYSQL_RES *result); int STDCALL mysql_free_result_cont(MYSQL_RES *result, int status); -MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); int STDCALL mysql_fetch_row_start(MYSQL_ROW *ret, MYSQL_RES *result); int STDCALL mysql_fetch_row_cont(MYSQL_ROW *ret, MYSQL_RES *result, @@ -582,6 +675,10 @@ int STDCALL mysql_read_query_result_start(my_bool *ret, MYSQL *mysql); int STDCALL mysql_read_query_result_cont(my_bool *ret, MYSQL *mysql, int status); +int STDCALL mysql_reset_connection_start(int *ret, MYSQL *mysql); +int STDCALL mysql_reset_connection_cont(int *ret, MYSQL *mysql, int status); +int STDCALL mysql_session_track_get_next(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length); +int STDCALL mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length); int STDCALL mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt,const char *query, unsigned long length); int STDCALL mysql_stmt_prepare_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_execute_start(int *ret, MYSQL_STMT *stmt); @@ -592,7 +689,6 @@ int STDCALL mysql_stmt_store_result_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_store_result_cont(int *ret, MYSQL_STMT *stmt,int status); int STDCALL mysql_stmt_close_start(my_bool *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_close_cont(my_bool *ret, MYSQL_STMT * stmt, int status); -my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); int STDCALL mysql_stmt_reset_start(my_bool *ret, MYSQL_STMT * stmt); int STDCALL mysql_stmt_reset_cont(my_bool *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_free_result_start(my_bool *ret, MYSQL_STMT *stmt); @@ -604,11 +700,129 @@ int STDCALL mysql_stmt_send_long_data_start(my_bool *ret, MYSQL_STMT *stmt, unsigned long len); int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt, int status); - - +int STDCALL mysql_reset_connection(MYSQL *mysql); + +/* API function calls (used by dynmic plugins) */ +struct st_mariadb_api { + unsigned long long (STDCALL *mysql_num_rows)(MYSQL_RES *res); + unsigned int (STDCALL *mysql_num_fields)(MYSQL_RES *res); + my_bool (STDCALL *mysql_eof)(MYSQL_RES *res); + MYSQL_FIELD *(STDCALL *mysql_fetch_field_direct)(MYSQL_RES *res, unsigned int fieldnr); + MYSQL_FIELD * (STDCALL *mysql_fetch_fields)(MYSQL_RES *res); + MYSQL_ROWS * (STDCALL *mysql_row_tell)(MYSQL_RES *res); + unsigned int (STDCALL *mysql_field_tell)(MYSQL_RES *res); + unsigned int (STDCALL *mysql_field_count)(MYSQL *mysql); + my_bool (STDCALL *mysql_more_results)(MYSQL *mysql); + int (STDCALL *mysql_next_result)(MYSQL *mysql); + unsigned long long (STDCALL *mysql_affected_rows)(MYSQL *mysql); + my_bool (STDCALL *mysql_autocommit)(MYSQL *mysql, my_bool mode); + my_bool (STDCALL *mysql_commit)(MYSQL *mysql); + my_bool (STDCALL *mysql_rollback)(MYSQL *mysql); + unsigned long long (STDCALL *mysql_insert_id)(MYSQL *mysql); + unsigned int (STDCALL *mysql_errno)(MYSQL *mysql); + const char * (STDCALL *mysql_error)(MYSQL *mysql); + const char * (STDCALL *mysql_info)(MYSQL *mysql); + unsigned long (STDCALL *mysql_thread_id)(MYSQL *mysql); + const char * (STDCALL *mysql_character_set_name)(MYSQL *mysql); + void (STDCALL *mysql_get_character_set_info)(MYSQL *mysql, MY_CHARSET_INFO *cs); + int (STDCALL *mysql_set_character_set)(MYSQL *mysql, const char *csname); + my_bool (*mariadb_get_infov)(MYSQL *mysql, enum mariadb_value value, void *arg, ...); + my_bool (STDCALL *mariadb_get_info)(MYSQL *mysql, enum mariadb_value value, void *arg); + MYSQL * (STDCALL *mysql_init)(MYSQL *mysql); + int (STDCALL *mysql_ssl_set)(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); + const char * (STDCALL *mysql_get_ssl_cipher)(MYSQL *mysql); + my_bool (STDCALL *mysql_change_user)(MYSQL *mysql, const char *user, const char *passwd, const char *db); + MYSQL * (STDCALL *mysql_real_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); + void (STDCALL *mysql_close)(MYSQL *sock); + int (STDCALL *mysql_select_db)(MYSQL *mysql, const char *db); + int (STDCALL *mysql_query)(MYSQL *mysql, const char *q); + int (STDCALL *mysql_send_query)(MYSQL *mysql, const char *q, unsigned long length); + my_bool (STDCALL *mysql_read_query_result)(MYSQL *mysql); + int (STDCALL *mysql_real_query)(MYSQL *mysql, const char *q, unsigned long length); + int (STDCALL *mysql_shutdown)(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); + int (STDCALL *mysql_dump_debug_info)(MYSQL *mysql); + int (STDCALL *mysql_refresh)(MYSQL *mysql, unsigned int refresh_options); + int (STDCALL *mysql_kill)(MYSQL *mysql,unsigned long pid); + int (STDCALL *mysql_ping)(MYSQL *mysql); + char * (STDCALL *mysql_stat)(MYSQL *mysql); + char * (STDCALL *mysql_get_server_info)(MYSQL *mysql); + unsigned long (STDCALL *mysql_get_server_version)(MYSQL *mysql); + char * (STDCALL *mysql_get_host_info)(MYSQL *mysql); + unsigned int (STDCALL *mysql_get_proto_info)(MYSQL *mysql); + MYSQL_RES * (STDCALL *mysql_list_dbs)(MYSQL *mysql,const char *wild); + MYSQL_RES * (STDCALL *mysql_list_tables)(MYSQL *mysql,const char *wild); + MYSQL_RES * (STDCALL *mysql_list_fields)(MYSQL *mysql, const char *table, const char *wild); + MYSQL_RES * (STDCALL *mysql_list_processes)(MYSQL *mysql); + MYSQL_RES * (STDCALL *mysql_store_result)(MYSQL *mysql); + MYSQL_RES * (STDCALL *mysql_use_result)(MYSQL *mysql); + int (STDCALL *mysql_options)(MYSQL *mysql,enum mysql_option option, const void *arg); + void (STDCALL *mysql_free_result)(MYSQL_RES *result); + void (STDCALL *mysql_data_seek)(MYSQL_RES *result, unsigned long long offset); + MYSQL_ROW_OFFSET (STDCALL *mysql_row_seek)(MYSQL_RES *result, MYSQL_ROW_OFFSET); + MYSQL_FIELD_OFFSET (STDCALL *mysql_field_seek)(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); + MYSQL_ROW (STDCALL *mysql_fetch_row)(MYSQL_RES *result); + unsigned long * (STDCALL *mysql_fetch_lengths)(MYSQL_RES *result); + MYSQL_FIELD * (STDCALL *mysql_fetch_field)(MYSQL_RES *result); + unsigned long (STDCALL *mysql_escape_string)(char *to,const char *from, unsigned long from_length); + unsigned long (STDCALL *mysql_real_escape_string)(MYSQL *mysql, char *to,const char *from, unsigned long length); + unsigned int (STDCALL *mysql_thread_safe)(void); + unsigned int (STDCALL *mysql_warning_count)(MYSQL *mysql); + const char * (STDCALL *mysql_sqlstate)(MYSQL *mysql); + int (STDCALL *mysql_server_init)(int argc, char **argv, char **groups); + void (STDCALL *mysql_server_end)(void); + void (STDCALL *mysql_thread_end)(void); + my_bool (STDCALL *mysql_thread_init)(void); + int (STDCALL *mysql_set_server_option)(MYSQL *mysql, enum enum_mysql_set_option option); + const char * (STDCALL *mysql_get_client_info)(void); + unsigned long (STDCALL *mysql_get_client_version)(void); + my_bool (STDCALL *mariadb_connection)(MYSQL *mysql); + const char * (STDCALL *mysql_get_server_name)(MYSQL *mysql); + MARIADB_CHARSET_INFO * (STDCALL *mariadb_get_charset_by_name)(const char *csname); + MARIADB_CHARSET_INFO * (STDCALL *mariadb_get_charset_by_nr)(unsigned int csnr); + size_t (STDCALL *mariadb_convert_string)(const char *from, size_t *from_len, MARIADB_CHARSET_INFO *from_cs, char *to, size_t *to_len, MARIADB_CHARSET_INFO *to_cs, int *errorcode); + int (*mysql_optionsv)(MYSQL *mysql,enum mysql_option option, ...); + int (*mysql_get_optionv)(MYSQL *mysql, enum mysql_option option, void *arg, ...); + int (STDCALL *mysql_get_option)(MYSQL *mysql, enum mysql_option option, void *arg); + unsigned long (STDCALL *mysql_hex_string)(char *to, const char *from, unsigned long len); + my_socket (STDCALL *mysql_get_socket)(MYSQL *mysql); + unsigned int (STDCALL *mysql_get_timeout_value)(const MYSQL *mysql); + unsigned int (STDCALL *mysql_get_timeout_value_ms)(const MYSQL *mysql); + my_bool (STDCALL *mariadb_reconnect)(MYSQL *mysql); + MYSQL_STMT * (STDCALL *mysql_stmt_init)(MYSQL *mysql); + int (STDCALL *mysql_stmt_prepare)(MYSQL_STMT *stmt, const char *query, unsigned long length); + int (STDCALL *mysql_stmt_execute)(MYSQL_STMT *stmt); + int (STDCALL *mysql_stmt_fetch)(MYSQL_STMT *stmt); + int (STDCALL *mysql_stmt_fetch_column)(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, unsigned int column, unsigned long offset); + int (STDCALL *mysql_stmt_store_result)(MYSQL_STMT *stmt); + unsigned long (STDCALL *mysql_stmt_param_count)(MYSQL_STMT * stmt); + my_bool (STDCALL *mysql_stmt_attr_set)(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr); + my_bool (STDCALL *mysql_stmt_attr_get)(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr); + my_bool (STDCALL *mysql_stmt_bind_param)(MYSQL_STMT * stmt, MYSQL_BIND * bnd); + my_bool (STDCALL *mysql_stmt_bind_result)(MYSQL_STMT * stmt, MYSQL_BIND * bnd); + my_bool (STDCALL *mysql_stmt_close)(MYSQL_STMT * stmt); + my_bool (STDCALL *mysql_stmt_reset)(MYSQL_STMT * stmt); + my_bool (STDCALL *mysql_stmt_free_result)(MYSQL_STMT *stmt); + my_bool (STDCALL *mysql_stmt_send_long_data)(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length); + MYSQL_RES *(STDCALL *mysql_stmt_result_metadata)(MYSQL_STMT *stmt); + MYSQL_RES *(STDCALL *mysql_stmt_param_metadata)(MYSQL_STMT *stmt); + unsigned int (STDCALL *mysql_stmt_errno)(MYSQL_STMT * stmt); + const char *(STDCALL *mysql_stmt_error)(MYSQL_STMT * stmt); + const char *(STDCALL *mysql_stmt_sqlstate)(MYSQL_STMT * stmt); + MYSQL_ROW_OFFSET (STDCALL *mysql_stmt_row_seek)(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset); + MYSQL_ROW_OFFSET (STDCALL *mysql_stmt_row_tell)(MYSQL_STMT *stmt); + void (STDCALL *mysql_stmt_data_seek)(MYSQL_STMT *stmt, unsigned long long offset); + unsigned long long (STDCALL *mysql_stmt_num_rows)(MYSQL_STMT *stmt); + unsigned long long (STDCALL *mysql_stmt_affected_rows)(MYSQL_STMT *stmt); + unsigned long long (STDCALL *mysql_stmt_insert_id)(MYSQL_STMT *stmt); + unsigned int (STDCALL *mysql_stmt_field_count)(MYSQL_STMT *stmt); + int (STDCALL *mysql_stmt_next_result)(MYSQL_STMT *stmt); + my_bool (STDCALL *mysql_stmt_more_results)(MYSQL_STMT *stmt); + int (STDCALL *mariadb_stmt_execute_direct)(MYSQL_STMT *stmt, const char *stmtstr, size_t length); + int (STDCALL *mysql_reset_connection)(MYSQL *mysql); +}; /* these methods can be overwritten by db plugins */ -struct st_mysql_methods { +struct st_mariadb_methods { MYSQL *(*db_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); void (*db_close)(MYSQL *mysql); @@ -628,6 +842,9 @@ struct st_mysql_methods { int (*db_stmt_fetch)(MYSQL_STMT *stmt, unsigned char **row); int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row); void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt); + void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...); + void (*invalidate_stmts)(MYSQL *mysql, const char *function_name); + struct st_mariadb_api *api; }; /* synonyms/aliases functions */ @@ -639,10 +856,9 @@ struct st_mysql_methods { #define HAVE_MYSQL_REAL_CONNECT -#ifndef MYSQL_SERVER + #ifdef __cplusplus } #endif -#endif #endif diff --git a/include/mysql/mysql/client_plugin.h b/include/mysql/mysql/client_plugin.h index 7d4fb55..ac29afd 100644 --- a/include/mysql/mysql/client_plugin.h +++ b/include/mysql/mysql/client_plugin.h @@ -31,20 +31,34 @@ #include #endif + #ifndef PLUGINDIR #define PLUGINDIR "lib/plugin" #endif +#define plugin_declarations_sym "_mysql_client_plugin_declaration_" + /* known plugin types */ -#define MYSQL_CLIENT_DB_PLUGIN 0 -#define MYSQL_CLIENT_reserved 1 -#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 +#define MYSQL_CLIENT_PLUGIN_RESERVED 0 +#define MYSQL_CLIENT_PLUGIN_RESERVED2 1 +#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 /* authentication */ #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 -#define MYSQL_CLIENT_DB_PLUGIN_INTERFACE_VERSION 0x0100 - #define MYSQL_CLIENT_MAX_PLUGINS 3 +/* Connector/C specific plugin types */ +#define MARIADB_CLIENT_REMOTEIO_PLUGIN 100 /* communication IO */ +#define MARIADB_CLIENT_PVIO_PLUGIN 101 +#define MARIADB_CLIENT_TRACE_PLUGIN 102 +#define MARIADB_CLIENT_CONNECTION_PLUGIN 103 + +#define MARIADB_CLIENT_REMOTEIO_PLUGIN_INTERFACE_VERSION 0x0100 +#define MARIADB_CLIENT_PVIO_PLUGIN_INTERFACE_VERSION 0x0100 +#define MARIADB_CLIENT_TRACE_PLUGIN_INTERFACE_VERSION 0x0100 +#define MARIADB_CLIENT_CONNECTION_PLUGIN_INTERFACE_VERSION 0x0100 + +#define MARIADB_CLIENT_MAX_PLUGINS 4 + #define mysql_declare_client_plugin(X) \ struct st_mysql_client_plugin_ ## X \ _mysql_client_plugin_declaration_ = { \ @@ -53,6 +67,7 @@ #define mysql_end_client_plugin } /* generic plugin header structure */ +#ifndef MYSQL_CLIENT_PLUGIN_HEADER #define MYSQL_CLIENT_PLUGIN_HEADER \ int type; \ unsigned int interface_version; \ @@ -65,40 +80,44 @@ int (*init)(char *, size_t, int, va_list); \ int (*deinit)(); \ int (*options)(const char *option, const void *); - struct st_mysql_client_plugin { MYSQL_CLIENT_PLUGIN_HEADER }; +#endif struct st_mysql; -/********* database api plugin specific declarations **********/ -typedef struct st_mariadb_client_plugin_DB +/********* connection handler plugin specific declarations **********/ + +typedef struct st_ma_connection_plugin { MYSQL_CLIENT_PLUGIN_HEADER /* functions */ - struct st_mysql_methods *methods; - /* - MYSQL * (*db_connect)(MYSQL *mysql,const char *host, const char *user, - const char *passwd, const char *db, uint port, - const char *unix_socket,unsigned long client_flag); - void (*db_close)(MYSQL *mysql); - int (*db_query)(MYSQL *mysql, const char *query, size_t query_len); - int (*db_read_one_row)(MYSQL *mysql, uint fields, MYSQL_ROW row, - ulong *lengths); - MYSQL_DATA *(*db_read_all_rows)(MYSQL *mysql, - MYSQL_FIELD *mysql_fields, uint fields); - void (*db_query_end)(MYSQL *mysql); - int (*db_stmt_prepare)(MYSQL_STMT *stmt, const char *stmt_str, ulong length); - my_bool (*db_stmt_close)(MYSQL_STMT *stmt); - my_bool (*is_supported_buffer_type)(enum enum_field_types type); - int (*db_stmt_fetch)(MYSQL_STMT *stmt); - int (*db_stmt_execute)(MYSQL_STMT *stmt); */ -} MARIADB_DB_PLUGIN; + MYSQL *(*connect)(MYSQL *mysql, const char *host, + const char *user, const char *passwd, + const char *db, unsigned int port, + const char *unix_socket, unsigned long clientflag); + void (*close)(MYSQL *mysql); + int (*set_optionsv)(MYSQL *mysql, unsigned int option, ...); + int (*set_connection)(MYSQL *mysql,enum enum_server_command command, + const char *arg, + size_t length, my_bool skipp_check, void *opt_arg); + my_bool (*reconnect)(MYSQL *mysql); + int (*reset)(MYSQL *mysql); +} MARIADB_CONNECTION_PLUGIN; #define MARIADB_DB_DRIVER(a) ((a)->ext_db) +/******************* Communication IO plugin *****************/ +#include + +typedef struct st_mariadb_client_plugin_PVIO +{ + MYSQL_CLIENT_PLUGIN_HEADER + struct st_ma_pvio_methods *methods; +} MARIADB_PVIO_PLUGIN; + /******** authentication plugin specific declarations *********/ #include @@ -108,6 +127,12 @@ struct st_mysql_client_plugin_AUTHENTICATION int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); }; +/******** trace plugin *******/ +struct st_mysql_client_plugin_TRACE +{ + MYSQL_CLIENT_PLUGIN_HEADER +}; + /** type of the mysql_authentication_dialog_ask function @@ -126,6 +151,19 @@ struct st_mysql_client_plugin_AUTHENTICATION */ typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, int type, const char *prompt, char *buf, int buf_len); + +/********************** remote IO plugin **********************/ +#ifdef HAVE_REMOTEIO +#include + +/* Remote IO plugin */ +typedef struct st_mysql_client_plugin_REMOTEIO +{ + MYSQL_CLIENT_PLUGIN_HEADER + struct st_rio_methods *methods; +} MARIADB_REMOTEIO_PLUGIN; +#endif + /******** using plugins ************/ /** @@ -142,7 +180,7 @@ typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, @retval a pointer to the loaded plugin, or NULL in case of a failure */ -struct st_mysql_client_plugin * STDCALL +struct st_mysql_client_plugin * mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, int argc, ...); diff --git a/include/mysql/mysql/plugin_auth_common.h b/include/mysql/mysql/plugin_auth_common.h index df902b4..ee4b8b9 100644 --- a/include/mysql/mysql/plugin_auth_common.h +++ b/include/mysql/mysql/plugin_auth_common.h @@ -15,6 +15,7 @@ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ + #ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /** @file @@ -25,7 +26,7 @@ #define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /** the max allowed length for a user name */ -#define MYSQL_USERNAME_LENGTH 512 +#define MYSQL_USERNAME_LENGTH 512 /** return values of the plugin authenticate_user() method. diff --git a/include/mysql/mysqld_error.h b/include/mysql/mysqld_error.h index b63f619..cc8c76d 100644 --- a/include/mysql/mysqld_error.h +++ b/include/mysql/mysqld_error.h @@ -1,9 +1,11 @@ -/* This file was automatically generated from errmsg.sys. - Todo: Several error messages are no longer in use +/* Autogenerated file, please don't edit + branch: 10.2 + revision id: 01a4eb8f761eb669fe2ae5139c73a7434b141a8f */ -#define ER_HASHCHK 1000 /* no longer in use ?! */ -#define ER_NISAMCHK 1001 /* no longer in use ? */ +#define ER_ERROR_FIRST 1000 +#define ER_HASHCHK 1000 +#define ER_NISAMCHK 1001 #define ER_NO 1002 #define ER_YES 1003 #define ER_CANT_CREATE_FILE 1004 @@ -11,7 +13,7 @@ #define ER_CANT_CREATE_DB 1006 #define ER_DB_CREATE_EXISTS 1007 #define ER_DB_DROP_EXISTS 1008 -#define ER_DB_DROP_DELETE 1009 /* no longer in use ?! */ +#define ER_DB_DROP_DELETE 1009 #define ER_DB_DROP_RMDIR 1010 #define ER_CANT_DELETE_FILE 1011 #define ER_CANT_FIND_SYSTEM_REC 1012 @@ -31,7 +33,7 @@ #define ER_ERROR_ON_WRITE 1026 #define ER_FILE_USED 1027 #define ER_FILSORT_ABORT 1028 -#define ER_FORM_NOT_FOUND 1029 /* no longer in use ?! */ +#define ER_FORM_NOT_FOUND 1029 #define ER_GET_ERRNO 1030 #define ER_ILLEGAL_HA 1031 #define ER_KEY_NOT_FOUND 1032 @@ -78,7 +80,7 @@ #define ER_BLOB_USED_AS_KEY 1073 #define ER_TOO_BIG_FIELDLENGTH 1074 #define ER_WRONG_AUTO_KEY 1075 -#define ER_READY 1076 /* no longer in use !? */ +#define ER_UNUSED_9 1076 #define ER_NORMAL_SHUTDOWN 1077 #define ER_GOT_SIGNAL 1078 #define ER_SHUTDOWN_COMPLETE 1079 @@ -90,12 +92,12 @@ #define ER_TEXTFILE_NOT_READABLE 1085 #define ER_FILE_EXISTS_ERROR 1086 #define ER_LOAD_INFO 1087 -#define ER_ALTER_INFO 1088 /* no longer in use !? */ +#define ER_ALTER_INFO 1088 #define ER_WRONG_SUB_KEY 1089 #define ER_CANT_REMOVE_ALL_FIELDS 1090 #define ER_CANT_DROP_FIELD_OR_KEY 1091 #define ER_INSERT_INFO 1092 -#define ER_INSERT_TABLE_USED 1093 /* no longer in use !? */ +#define ER_UPDATE_TABLE_USED 1093 #define ER_NO_SUCH_THREAD 1094 #define ER_KILL_DENIED_ERROR 1095 #define ER_NO_TABLES_USED 1096 @@ -134,29 +136,29 @@ #define ER_HOST_IS_BLOCKED 1129 #define ER_HOST_NOT_PRIVILEGED 1130 #define ER_PASSWORD_ANONYMOUS_USER 1131 -#define ER_PASSWORD_NOT_ALLOWED 1132 /* no longer in use !? */ +#define ER_PASSWORD_NOT_ALLOWED 1132 #define ER_PASSWORD_NO_MATCH 1133 #define ER_UPDATE_INFO 1134 #define ER_CANT_CREATE_THREAD 1135 #define ER_WRONG_VALUE_COUNT_ON_ROW 1136 #define ER_CANT_REOPEN_TABLE 1137 -#define ER_INVALID_USE_OF_NULL 1138 /* no longer in use !? */ +#define ER_INVALID_USE_OF_NULL 1138 #define ER_REGEXP_ERROR 1139 #define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 #define ER_NONEXISTING_GRANT 1141 #define ER_TABLEACCESS_DENIED_ERROR 1142 #define ER_COLUMNACCESS_DENIED_ERROR 1143 #define ER_ILLEGAL_GRANT_FOR_TABLE 1144 -#define ER_GRANT_WRONG_HOST_OR_USER 1145 /* no longer in use !? */ +#define ER_GRANT_WRONG_HOST_OR_USER 1145 #define ER_NO_SUCH_TABLE 1146 #define ER_NONEXISTING_TABLE_GRANT 1147 #define ER_NOT_ALLOWED_COMMAND 1148 #define ER_SYNTAX_ERROR 1149 #define ER_DELAYED_CANT_CHANGE_LOCK 1150 -#define ER_TOO_MANY_DELAYED_THREADS 1151 /* no longer in use !? */ -#define ER_ABORTING_CONNECTION 1152 /* no longer in use !? */ +#define ER_TOO_MANY_DELAYED_THREADS 1151 +#define ER_ABORTING_CONNECTION 1152 #define ER_NET_PACKET_TOO_LARGE 1153 -#define ER_NET_READ_ERROR_FROM_PIPE 1154 /* no longer in use !? */ +#define ER_NET_READ_ERROR_FROM_PIPE 1154 #define ER_NET_FCNTL_ERROR 1155 #define ER_NET_PACKETS_OUT_OF_ORDER 1156 #define ER_NET_UNCOMPRESS_ERROR 1157 @@ -164,7 +166,7 @@ #define ER_NET_READ_INTERRUPTED 1159 #define ER_NET_ERROR_ON_WRITE 1160 #define ER_NET_WRITE_INTERRUPTED 1161 -#define ER_TOO_LONG_STRING 1162 /* no longer in use !? */ +#define ER_TOO_LONG_STRING 1162 #define ER_TABLE_CANT_HANDLE_BLOB 1163 #define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 #define ER_DELAYED_INSERT_TABLE_LOCKED 1165 @@ -176,23 +178,23 @@ #define ER_PRIMARY_CANT_HAVE_NULL 1171 #define ER_TOO_MANY_ROWS 1172 #define ER_REQUIRES_PRIMARY_KEY 1173 -#define ER_NO_RAID_COMPILED 1174 /* no longer in use !? */ +#define ER_NO_RAID_COMPILED 1174 #define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 #define ER_KEY_DOES_NOT_EXITS 1176 #define ER_CHECK_NO_SUCH_TABLE 1177 #define ER_CHECK_NOT_IMPLEMENTED 1178 -#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 /* no longer in use !? */ +#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 #define ER_ERROR_DURING_COMMIT 1180 #define ER_ERROR_DURING_ROLLBACK 1181 #define ER_ERROR_DURING_FLUSH_LOGS 1182 -#define ER_ERROR_DURING_CHECKPOINT 1183 /* no longer in use !? */ +#define ER_ERROR_DURING_CHECKPOINT 1183 #define ER_NEW_ABORTING_CONNECTION 1184 -#define ER_DUMP_NOT_IMPLEMENTED 1185 /* no longer in use !? */ +#define ER_UNUSED_10 1185 #define ER_FLUSH_MASTER_BINLOG_CLOSED 1186 -#define ER_INDEX_REBUILD 1187 /* no longer in use !? */ +#define ER_INDEX_REBUILD 1187 #define ER_MASTER 1188 -#define ER_MASTER_NET_READ 1189 /* no longer in use !? */ -#define ER_MASTER_NET_WRITE 1190 /* no longer in use !? */ +#define ER_MASTER_NET_READ 1189 +#define ER_MASTER_NET_WRITE 1190 #define ER_FT_MATCHING_KEY_NOT_FOUND 1191 #define ER_LOCK_OR_ACTIVE_TRANSACTION 1192 #define ER_UNKNOWN_SYSTEM_VARIABLE 1193 @@ -210,25 +212,23 @@ #define ER_LOCK_WAIT_TIMEOUT 1205 #define ER_LOCK_TABLE_FULL 1206 #define ER_READ_ONLY_TRANSACTION 1207 -#define ER_DROP_DB_WITH_READ_LOCK 1208 /* no longer in use !? */ -#define ER_CREATE_DB_WITH_READ_LOCK 1209 /* no longer in use !? */ +#define ER_DROP_DB_WITH_READ_LOCK 1208 +#define ER_CREATE_DB_WITH_READ_LOCK 1209 #define ER_WRONG_ARGUMENTS 1210 -#define ER_NO_PERMISSION_TO_CREATE_USER 1211 /* no longer in use !? */ -#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 /* no longer in use !? */ +#define ER_NO_PERMISSION_TO_CREATE_USER 1211 +#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 #define ER_LOCK_DEADLOCK 1213 -#define ER_TABLE_CANT_HANDLE_FULLTEXT 1214 /* no longer in use !? */ +#define ER_TABLE_CANT_HANDLE_FT 1214 #define ER_CANNOT_ADD_FOREIGN 1215 #define ER_NO_REFERENCED_ROW 1216 #define ER_ROW_IS_REFERENCED 1217 - -/* new server messages (added after 3.23.49) */ -#define ER_CONNECT_TO_MASTER 1218 /* no longer in use !? */ -#define ER_QUERY_ON_MASTER 1219 /* no longer in use !? */ +#define ER_CONNECT_TO_MASTER 1218 +#define ER_QUERY_ON_MASTER 1219 #define ER_ERROR_WHEN_EXECUTING_COMMAND 1220 #define ER_WRONG_USAGE 1221 #define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 -#define ER_CANT_UPDATE_WITH_READLOCK 1223 /* no longer in use !? */ -#define ER_MIXING_NOT_ALLOWED 1224 /* no longer in use !? */ +#define ER_CANT_UPDATE_WITH_READLOCK 1223 +#define ER_MIXING_NOT_ALLOWED 1224 #define ER_DUP_ARGUMENT 1225 #define ER_USER_LIMIT_REACHED 1226 #define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 @@ -249,7 +249,7 @@ #define ER_SUBQUERY_NO_1_ROW 1242 #define ER_UNKNOWN_STMT_HANDLER 1243 #define ER_CORRUPT_HELP_DB 1244 -#define ER_CYCLIC_REFERENCE 1245 /* no longer in use ?! */ +#define ER_CYCLIC_REFERENCE 1245 #define ER_AUTO_CONVERT 1246 #define ER_ILLEGAL_REFERENCE 1247 #define ER_DERIVED_MUST_HAVE_ALIAS 1248 @@ -272,7 +272,7 @@ #define WARN_DATA_TRUNCATED 1265 #define ER_WARN_USING_OTHER_HANDLER 1266 #define ER_CANT_AGGREGATE_2COLLATIONS 1267 -#define ER_DROP_USER 1268 /* no longer in use ?! */ +#define ER_DROP_USER 1268 #define ER_REVOKE_GRANTS 1269 #define ER_CANT_AGGREGATE_3COLLATIONS 1270 #define ER_CANT_AGGREGATE_NCOLLATIONS 1271 @@ -285,7 +285,7 @@ #define ER_MISSING_SKIP_SLAVE 1278 #define ER_UNTIL_COND_IGNORED 1279 #define ER_WRONG_NAME_FOR_INDEX 1280 -#define ER_WRONG_NAME_FOR_CATALOG 1281 /* no longer in use ?! */ +#define ER_WRONG_NAME_FOR_CATALOG 1281 #define ER_WARN_QC_RESIZE 1282 #define ER_BAD_FT_COLUMN 1283 #define ER_UNKNOWN_KEY_CACHE 1284 @@ -315,12 +315,12 @@ #define ER_SP_LILABEL_MISMATCH 1308 #define ER_SP_LABEL_REDEFINE 1309 #define ER_SP_LABEL_MISMATCH 1310 -#define ER_SP_UNINIT_VAR 1311 /* no longer in use ?! */ +#define ER_SP_UNINIT_VAR 1311 #define ER_SP_BADSELECT 1312 #define ER_SP_BADRETURN 1313 #define ER_SP_BADSTATEMENT 1314 -#define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 /* no longer in use ?! */ -#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 /* no longer in use ?! */ +#define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 +#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 #define ER_QUERY_INTERRUPTED 1317 #define ER_SP_WRONG_NO_OF_ARGS 1318 #define ER_SP_COND_MISMATCH 1319 @@ -339,8 +339,8 @@ #define ER_SP_DUP_COND 1332 #define ER_SP_DUP_CURS 1333 #define ER_SP_CANT_ALTER 1334 -#define ER_SP_SUBSELECT_NYI 1335 /* no longer in use ?! */ -#define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 /* no longer in use ?! */ +#define ER_SP_SUBSELECT_NYI 1335 +#define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 #define ER_SP_VARCOND_AFTER_CURSHNDLR 1337 #define ER_SP_CURSOR_AFTER_HANDLER 1338 #define ER_SP_CASE_NOT_FOUND 1339 @@ -362,7 +362,7 @@ #define ER_WARN_VIEW_WITHOUT_KEY 1355 #define ER_VIEW_INVALID 1356 #define ER_SP_NO_DROP_SP 1357 -#define ER_SP_GOTO_IN_HNDLR 1358 /* no longer in use ?! */ +#define ER_SP_GOTO_IN_HNDLR 1358 #define ER_TRG_ALREADY_EXISTS 1359 #define ER_TRG_DOES_NOT_EXIST 1360 #define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 @@ -387,13 +387,13 @@ #define ER_RELAY_LOG_INIT 1380 #define ER_NO_BINARY_LOGGING 1381 #define ER_RESERVED_SYNTAX 1382 -#define ER_WSAS_FAILED 1383 /* no longer in use ?! */ +#define ER_WSAS_FAILED 1383 #define ER_DIFF_GROUPS_PROC 1384 -#define ER_NO_GROUP_FOR_PROC 1385 /* no longer in use ?! */ +#define ER_NO_GROUP_FOR_PROC 1385 #define ER_ORDER_WITH_PROC 1386 -#define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 /* no longer in use ?! */ -#define ER_NO_FILE_MAPPING 1388 /* no longer in use ?! */ -#define ER_WRONG_MAGIC 1389 /* no longer in use ?! */ +#define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 +#define ER_NO_FILE_MAPPING 1388 +#define ER_WRONG_MAGIC 1389 #define ER_PS_MANY_PARAM 1390 #define ER_KEY_PART_0 1391 #define ER_VIEW_CHECKSUM 1392 @@ -419,12 +419,12 @@ #define ER_TABLE_DEF_CHANGED 1412 #define ER_SP_DUP_HANDLER 1413 #define ER_SP_NOT_VAR_ARG 1414 -#define ER_SP_NO_RETSET 1415 /* no longer in use ?! */ +#define ER_SP_NO_RETSET 1415 #define ER_CANT_CREATE_GEOMETRY_OBJECT 1416 -#define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 /* no longer in use ?! */ +#define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 #define ER_BINLOG_UNSAFE_ROUTINE 1418 #define ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 -#define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 /* no longer in use ?! */ +#define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 #define ER_STMT_HAS_NO_OPEN_CURSOR 1421 #define ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 #define ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 @@ -442,17 +442,17 @@ #define ER_TRG_IN_WRONG_SCHEMA 1435 #define ER_STACK_OVERRUN_NEED_MORE 1436 #define ER_TOO_LONG_BODY 1437 -#define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 /* no longer in use ?! */ +#define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 #define ER_TOO_BIG_DISPLAYWIDTH 1439 #define ER_XAER_DUPID 1440 #define ER_DATETIME_FUNCTION_OVERFLOW 1441 #define ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 #define ER_VIEW_PREVENT_UPDATE 1443 #define ER_PS_NO_RECURSION 1444 -#define ER_SP_CANT_SET_AUTOCOMMIT 1445 /* no longer in use ?! */ -#define ER_MALFORMED_DEFINER 1446 /* no longer in use ?! */ +#define ER_SP_CANT_SET_AUTOCOMMIT 1445 +#define ER_MALFORMED_DEFINER 1446 #define ER_VIEW_FRM_NO_USER 1447 -#define ER_VIEW_OTHER_USER 1448 /* no longer in use ?! */ +#define ER_VIEW_OTHER_USER 1448 #define ER_NO_SUCH_USER 1449 #define ER_FORBID_SCHEMA_CHANGE 1450 #define ER_ROW_IS_REFERENCED_2 1451 @@ -464,7 +464,7 @@ #define ER_SP_PROC_TABLE_CORRUPT 1457 #define ER_SP_WRONG_NAME 1458 #define ER_TABLE_NEEDS_UPGRADE 1459 -#define ER_SP_NO_AGGREGATE 1460 /* no longer in use ?! */ +#define ER_SP_NO_AGGREGATE 1460 #define ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 #define ER_VIEW_RECURSIVE 1462 #define ER_NON_GROUPING_FIELD_USED 1463 @@ -486,19 +486,19 @@ #define ER_PARTITION_REQUIRES_VALUES_ERROR 1479 #define ER_PARTITION_WRONG_VALUES_ERROR 1480 #define ER_PARTITION_MAXVALUE_ERROR 1481 -#define ER_PARTITION_SUBPARTITION_ERROR 1482 /* no longer in use ?! */ -#define ER_PARTITION_SUBPART_MIX_ERROR 1483 /* no longer in use ?! */ +#define ER_PARTITION_SUBPARTITION_ERROR 1482 +#define ER_PARTITION_SUBPART_MIX_ERROR 1483 #define ER_PARTITION_WRONG_NO_PART_ERROR 1484 #define ER_PARTITION_WRONG_NO_SUBPART_ERROR 1485 #define ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR 1486 -#define ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR 1487 /* no longer in use ?! */ +#define ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR 1487 #define ER_FIELD_NOT_FOUND_PART_ERROR 1488 -#define ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 /* no longer in use ?! */ +#define ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 #define ER_INCONSISTENT_PARTITION_INFO_ERROR 1490 #define ER_PARTITION_FUNC_NOT_ALLOWED_ERROR 1491 #define ER_PARTITIONS_MUST_BE_DEFINED_ERROR 1492 #define ER_RANGE_NOT_INCREASING_ERROR 1493 -#define ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 /* no longer in use ?! */ +#define ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 #define ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR 1495 #define ER_PARTITION_ENTRY_ERROR 1496 #define ER_MIX_HANDLER_ERROR 1497 @@ -526,7 +526,7 @@ #define ER_CONSECUTIVE_REORG_PARTITIONS 1519 #define ER_REORG_OUTSIDE_RANGE 1520 #define ER_PARTITION_FUNCTION_FAILURE 1521 -#define ER_PART_STATE_ERROR 1522 /* no longer in use ?! */ +#define ER_PART_STATE_ERROR 1522 #define ER_LIMITED_PART_RANGE 1523 #define ER_PLUGIN_IS_NOT_LOADED 1524 #define ER_WRONG_VALUE 1525 @@ -539,46 +539,46 @@ #define ER_SIZE_OVERFLOW_ERROR 1532 #define ER_ALTER_FILEGROUP_FAILED 1533 #define ER_BINLOG_ROW_LOGGING_FAILED 1534 -#define ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 /* no longer in use ?! */ -#define ER_BINLOG_ROW_RBR_TO_SBR 1536 /* no longer in use ?! */ +#define ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 +#define ER_BINLOG_ROW_RBR_TO_SBR 1536 #define ER_EVENT_ALREADY_EXISTS 1537 #define ER_EVENT_STORE_FAILED 1538 #define ER_EVENT_DOES_NOT_EXIST 1539 -#define ER_EVENT_CANT_ALTER 1540 /* no longer in use ?! */ -#define ER_EVENT_DROP_FAILED 1541 /* no longer in use ?! */ +#define ER_EVENT_CANT_ALTER 1540 +#define ER_EVENT_DROP_FAILED 1541 #define ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG 1542 #define ER_EVENT_ENDS_BEFORE_STARTS 1543 #define ER_EVENT_EXEC_TIME_IN_THE_PAST 1544 #define ER_EVENT_OPEN_TABLE_FAILED 1545 -#define ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 /* no longer in use ?! */ -#define ER_COL_COUNT_DOESNT_MATCH_CORRUPTED 1547 -#define ER_CANNOT_LOAD_FROM_TABLE 1548 -#define ER_EVENT_CANNOT_DELETE 1549 /* no longer in use ?! */ -#define ER_EVENT_COMPILE_ERROR 1550 /* no longer in use ?! */ +#define ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 +#define ER_UNUSED_2 1547 +#define ER_UNUSED_3 1548 +#define ER_EVENT_CANNOT_DELETE 1549 +#define ER_EVENT_COMPILE_ERROR 1550 #define ER_EVENT_SAME_NAME 1551 #define ER_EVENT_DATA_TOO_LONG 1552 #define ER_DROP_INDEX_FK 1553 -#define ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 /* no longer in use ?! */ -#define ER_CANT_WRITE_LOCK_LOG_TABLE 1555 /* no longer in use ?! */ +#define ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 +#define ER_CANT_WRITE_LOCK_LOG_TABLE 1555 #define ER_CANT_LOCK_LOG_TABLE 1556 -#define ER_FOREIGN_DUPLICATE_KEY 1557 +#define ER_UNUSED_4 1557 #define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE 1558 #define ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR 1559 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT 1560 -#define ER_NDB_CANT_SWITCH_BINLOG_FORMAT 1561 /* no longer in use ?! */ +#define ER_UNUSED_13 1561 #define ER_PARTITION_NO_TEMPORARY 1562 #define ER_PARTITION_CONST_DOMAIN_ERROR 1563 #define ER_PARTITION_FUNCTION_IS_NOT_ALLOWED 1564 #define ER_DDL_LOG_ERROR 1565 #define ER_NULL_IN_VALUES_LESS_THAN 1566 #define ER_WRONG_PARTITION_NAME 1567 -#define ER_CANT_CHANGE_TX_ISOLATION 1568 /* no longer in use ?! */ +#define ER_CANT_CHANGE_TX_CHARACTERISTICS 1568 #define ER_DUP_ENTRY_AUTOINCREMENT_CASE 1569 -#define ER_EVENT_MODIFY_QUEUE_ERROR 1570 /* no longer in use ?! */ +#define ER_EVENT_MODIFY_QUEUE_ERROR 1570 #define ER_EVENT_SET_VAR_ERROR 1571 #define ER_PARTITION_MERGE_ERROR 1572 -#define ER_CANT_ACTIVATE_LOG 1573 /* no longer in use ?! */ -#define ER_RBR_NOT_AVAILABLE 1574 /* no longer in use ?! */ +#define ER_CANT_ACTIVATE_LOG 1573 +#define ER_RBR_NOT_AVAILABLE 1574 #define ER_BASE64_DECODE_ERROR 1575 #define ER_EVENT_RECURSION_FORBIDDEN 1576 #define ER_EVENTS_DB_ERROR 1577 @@ -612,7 +612,7 @@ #define ER_EVENT_INVALID_CREATION_CTX 1605 #define ER_TRG_CANT_OPEN_TABLE 1606 #define ER_CANT_CREATE_SROUTINE 1607 -#define ER_NEVER_USED 1608 /* no longer in use ?! */ +#define ER_UNUSED_11 1608 #define ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT 1609 #define ER_SLAVE_CORRUPT_EVENT 1610 #define ER_LOAD_DATA_INVALID_COLUMN 1611 @@ -623,15 +623,15 @@ #define ER_DELAYED_NOT_SUPPORTED 1616 #define WARN_NO_MASTER_INFO 1617 #define WARN_OPTION_IGNORED 1618 -#define WARN_PLUGIN_DELETE_BUILTIN 1619 +#define ER_PLUGIN_DELETE_BUILTIN 1619 #define WARN_PLUGIN_BUSY 1620 #define ER_VARIABLE_IS_READONLY 1621 -#define ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 /* no longer in use ?! */ +#define ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 #define ER_SLAVE_HEARTBEAT_FAILURE 1623 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE 1624 -#define ER_NDB_REPLICATION_SCHEMA_ERROR 1625 /* no longer in use ?! */ -#define ER_CONFLICT_FN_PARSE_ERROR 1626 /* no longer in use ?! */ -#define ER_EXCEPTIONS_WRITE_ERROR 1627 /* no longer in use ?! */ +#define ER_UNUSED_14 1625 +#define ER_CONFLICT_FN_PARSE_ERROR 1626 +#define ER_EXCEPTIONS_WRITE_ERROR 1627 #define ER_TOO_LONG_TABLE_COMMENT 1628 #define ER_TOO_LONG_FIELD_COMMENT 1629 #define ER_FUNC_INEXISTENT_NAME_COLLISION 1630 @@ -691,10 +691,10 @@ #define ER_WARN_I_S_SKIPPED_TABLE 1684 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT 1685 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT 1686 -#define ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 /* no longer in use ?! */ +#define ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 #define ER_TOO_LONG_INDEX_COMMENT 1688 #define ER_LOCK_ABORTED 1689 -#define ER_DATA_OUT_OF_RANGE 1690 /* no longer in use ?! */ +#define ER_DATA_OUT_OF_RANGE 1690 #define ER_WRONG_SPVAR_TYPE_IN_LIMIT 1691 #define ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1692 #define ER_BINLOG_UNSAFE_MIXED_STATEMENT 1693 @@ -724,33 +724,188 @@ #define ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT 1717 #define ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT 1718 #define ER_BINLOG_UNSAFE_UPDATE_IGNORE 1719 -#define ER_PLUGIN_NO_UNINSTALL 1720 /* no longer in use ?! */ -#define ER_PLUGIN_NO_INSTALL 1721 /* no longer in use ?! */ +#define ER_UNUSED_15 1720 +#define ER_UNUSED_16 1721 #define ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT 1722 #define ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC 1723 #define ER_BINLOG_UNSAFE_INSERT_TWO_KEYS 1724 #define ER_TABLE_IN_FK_CHECK 1725 -#define ER_UNUSED_1 1726 /* not in use ?! */ +#define ER_UNUSED_1 1726 #define ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST 1727 -#define ER_LAST_MYSQL_ERROR_MESSAGE 1728 +#define ER_CANNOT_LOAD_FROM_TABLE_V2 1728 +#define ER_MASTER_DELAY_VALUE_OUT_OF_RANGE 1729 +#define ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT 1730 +#define ER_PARTITION_EXCHANGE_DIFFERENT_OPTION 1731 +#define ER_PARTITION_EXCHANGE_PART_TABLE 1732 +#define ER_PARTITION_EXCHANGE_TEMP_TABLE 1733 +#define ER_PARTITION_INSTEAD_OF_SUBPARTITION 1734 +#define ER_UNKNOWN_PARTITION 1735 +#define ER_TABLES_DIFFERENT_METADATA 1736 +#define ER_ROW_DOES_NOT_MATCH_PARTITION 1737 +#define ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX 1738 +#define ER_WARN_INDEX_NOT_APPLICABLE 1739 +#define ER_PARTITION_EXCHANGE_FOREIGN_KEY 1740 +#define ER_NO_SUCH_KEY_VALUE 1741 +#define ER_VALUE_TOO_LONG 1742 +#define ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE 1743 +#define ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE 1744 +#define ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX 1745 +#define ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT 1746 +#define ER_PARTITION_CLAUSE_ON_NONPARTITIONED 1747 +#define ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET 1748 +#define ER_UNUSED_5 1749 +#define ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE 1750 +#define ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE 1751 +#define ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE 1752 +#define ER_MTS_FEATURE_IS_NOT_SUPPORTED 1753 +#define ER_MTS_UPDATED_DBS_GREATER_MAX 1754 +#define ER_MTS_CANT_PARALLEL 1755 +#define ER_MTS_INCONSISTENT_DATA 1756 +#define ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING 1757 +#define ER_DA_INVALID_CONDITION_NUMBER 1758 +#define ER_INSECURE_PLAIN_TEXT 1759 +#define ER_INSECURE_CHANGE_MASTER 1760 +#define ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO 1761 +#define ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO 1762 +#define ER_SQLTHREAD_WITH_SECURE_SLAVE 1763 +#define ER_TABLE_HAS_NO_FT 1764 +#define ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER 1765 +#define ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION 1766 +#define ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST 1767 +#define ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL 1768 +#define ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION 1769 +#define ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL 1770 +#define ER_SKIPPING_LOGGED_TRANSACTION 1771 +#define ER_MALFORMED_GTID_SET_SPECIFICATION 1772 +#define ER_MALFORMED_GTID_SET_ENCODING 1773 +#define ER_MALFORMED_GTID_SPECIFICATION 1774 +#define ER_GNO_EXHAUSTED 1775 +#define ER_BAD_SLAVE_AUTO_POSITION 1776 +#define ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON 1777 +#define ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET 1778 +#define ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON 1779 +#define ER_GTID_MODE_REQUIRES_BINLOG 1780 +#define ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF 1781 +#define ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON 1782 +#define ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF 1783 +#define ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF 1784 +#define ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE 1785 +#define ER_GTID_UNSAFE_CREATE_SELECT 1786 +#define ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION 1787 +#define ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME 1788 +#define ER_MASTER_HAS_PURGED_REQUIRED_GTIDS 1789 +#define ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID 1790 +#define ER_UNKNOWN_EXPLAIN_FORMAT 1791 +#define ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 1792 +#define ER_TOO_LONG_TABLE_PARTITION_COMMENT 1793 +#define ER_SLAVE_CONFIGURATION 1794 +#define ER_INNODB_FT_LIMIT 1795 +#define ER_INNODB_NO_FT_TEMP_TABLE 1796 +#define ER_INNODB_FT_WRONG_DOCID_COLUMN 1797 +#define ER_INNODB_FT_WRONG_DOCID_INDEX 1798 +#define ER_INNODB_ONLINE_LOG_TOO_BIG 1799 +#define ER_UNKNOWN_ALTER_ALGORITHM 1800 +#define ER_UNKNOWN_ALTER_LOCK 1801 +#define ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS 1802 +#define ER_MTS_RECOVERY_FAILURE 1803 +#define ER_MTS_RESET_WORKERS 1804 +#define ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 1805 +#define ER_SLAVE_SILENT_RETRY_TRANSACTION 1806 +#define ER_DISCARD_FK_CHECKS_RUNNING 1807 +#define ER_TABLE_SCHEMA_MISMATCH 1808 +#define ER_TABLE_IN_SYSTEM_TABLESPACE 1809 +#define ER_IO_READ_ERROR 1810 +#define ER_IO_WRITE_ERROR 1811 +#define ER_TABLESPACE_MISSING 1812 +#define ER_TABLESPACE_EXISTS 1813 +#define ER_TABLESPACE_DISCARDED 1814 +#define ER_INTERNAL_ERROR 1815 +#define ER_INNODB_IMPORT_ERROR 1816 +#define ER_INNODB_INDEX_CORRUPT 1817 +#define ER_INVALID_YEAR_COLUMN_LENGTH 1818 +#define ER_NOT_VALID_PASSWORD 1819 +#define ER_MUST_CHANGE_PASSWORD 1820 +#define ER_FK_NO_INDEX_CHILD 1821 +#define ER_FK_NO_INDEX_PARENT 1822 +#define ER_FK_FAIL_ADD_SYSTEM 1823 +#define ER_FK_CANNOT_OPEN_PARENT 1824 +#define ER_FK_INCORRECT_OPTION 1825 +#define ER_DUP_CONSTRAINT_NAME 1826 +#define ER_PASSWORD_FORMAT 1827 +#define ER_FK_COLUMN_CANNOT_DROP 1828 +#define ER_FK_COLUMN_CANNOT_DROP_CHILD 1829 +#define ER_FK_COLUMN_NOT_NULL 1830 +#define ER_DUP_INDEX 1831 +#define ER_FK_COLUMN_CANNOT_CHANGE 1832 +#define ER_FK_COLUMN_CANNOT_CHANGE_CHILD 1833 +#define ER_FK_CANNOT_DELETE_PARENT 1834 +#define ER_MALFORMED_PACKET 1835 +#define ER_READ_ONLY_MODE 1836 +#define ER_GTID_NEXT_TYPE_UNDEFINED_GROUP 1837 +#define ER_VARIABLE_NOT_SETTABLE_IN_SP 1838 +#define ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF 1839 +#define ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY 1840 +#define ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY 1841 +#define ER_GTID_PURGED_WAS_CHANGED 1842 +#define ER_GTID_EXECUTED_WAS_CHANGED 1843 +#define ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES 1844 +#define ER_ALTER_OPERATION_NOT_SUPPORTED 1845 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON 1846 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY 1847 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION 1848 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME 1849 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE 1850 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK 1851 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE 1852 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK 1853 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC 1854 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS 1855 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS 1856 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS 1857 +#define ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE 1858 +#define ER_DUP_UNKNOWN_IN_INDEX 1859 +#define ER_IDENT_CAUSES_TOO_LONG_PATH 1860 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL 1861 +#define ER_MUST_CHANGE_PASSWORD_LOGIN 1862 +#define ER_ROW_IN_WRONG_PARTITION 1863 +#define ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX 1864 +#define ER_INNODB_NO_FT_USES_PARSER 1865 +#define ER_BINLOG_LOGICAL_CORRUPTION 1866 +#define ER_WARN_PURGE_LOG_IN_USE 1867 +#define ER_WARN_PURGE_LOG_IS_ACTIVE 1868 +#define ER_AUTO_INCREMENT_CONFLICT 1869 +#define WARN_ON_BLOCKHOLE_IN_RBR 1870 +#define ER_SLAVE_MI_INIT_REPOSITORY 1871 +#define ER_SLAVE_RLI_INIT_REPOSITORY 1872 +#define ER_ACCESS_DENIED_CHANGE_USER_ERROR 1873 +#define ER_INNODB_READ_ONLY 1874 +#define ER_STOP_SLAVE_SQL_THREAD_TIMEOUT 1875 +#define ER_STOP_SLAVE_IO_THREAD_TIMEOUT 1876 +#define ER_TABLE_CORRUPT 1877 +#define ER_TEMP_FILE_WRITE_FAILURE 1878 +#define ER_INNODB_FT_AUX_NOT_HEX_ID 1879 +#define ER_LAST_MYSQL_ERROR_MESSAGE 1880 +#define ER_ERROR_LAST_SECTION_1 1880 + +/* New section */ -/* MariaDB only errors */ -#define ER_VCOL_BASED_ON_VCOL 1900 -#define ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED 1901 -#define ER_DATA_CONVERSION_ERROR_FOR_VIRTUAL_COLUMN 1902 -#define ER_PRIMARY_KEY_BASED_ON_VIRTUAL_COLUMN 1903 +#define ER_ERROR_FIRST_SECTION_2 1900 +#define ER_UNUSED_18 1900 +#define ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED 1901 +#define ER_UNUSED_19 1902 +#define ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN 1903 #define ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN 1904 -#define ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN 1905 -#define ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN 1906 -#define ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN 1907 -#define ER_CONST_EXPR_IN_VCOL 1908 -#define ER_ROW_EXPR_FOR_VCOL 1909 -#define ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS 1910 +#define ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN 1905 +#define ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN 1906 +#define ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN 1907 +#define ER_UNUSED_20 1908 +#define ER_UNUSED_21 1909 +#define ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS 1910 #define ER_UNKNOWN_OPTION 1911 #define ER_BAD_OPTION_VALUE 1912 -#define ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE 1913 -#define ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE 1914 -#define ER_CANT_DO_ONLINE 1915 +#define ER_UNUSED_6 1913 +#define ER_UNUSED_7 1914 +#define ER_UNUSED_8 1915 #define ER_DATA_OVERFLOW 1916 #define ER_DATA_TRUNCATED 1917 #define ER_BAD_DATA 1918 @@ -763,10 +918,209 @@ #define ER_QUERY_CACHE_IS_GLOBALY_DISABLED 1925 #define ER_VIEW_ORDERBY_IGNORED 1926 #define ER_CONNECTION_KILLED 1927 -#define ER_INTERNAL_ERROR 1928 +#define ER_UNUSED_12 1928 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION 1929 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION 1930 #define ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT 1931 #define ER_NO_SUCH_TABLE_IN_ENGINE 1932 -#define ER_GEOMETRY_SRID_MISMATCH 1933 -#define ER_NO_SUCH_SPATIAL_REF_ID 1934 +#define ER_TARGET_NOT_EXPLAINABLE 1933 +#define ER_CONNECTION_ALREADY_EXISTS 1934 +#define ER_MASTER_LOG_PREFIX 1935 +#define ER_CANT_START_STOP_SLAVE 1936 +#define ER_SLAVE_STARTED 1937 +#define ER_SLAVE_STOPPED 1938 +#define ER_SQL_DISCOVER_ERROR 1939 +#define ER_FAILED_GTID_STATE_INIT 1940 +#define ER_INCORRECT_GTID_STATE 1941 +#define ER_CANNOT_UPDATE_GTID_STATE 1942 +#define ER_DUPLICATE_GTID_DOMAIN 1943 +#define ER_GTID_OPEN_TABLE_FAILED 1944 +#define ER_GTID_POSITION_NOT_FOUND_IN_BINLOG 1945 +#define ER_CANNOT_LOAD_SLAVE_GTID_STATE 1946 +#define ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG 1947 +#define ER_MASTER_GTID_POS_MISSING_DOMAIN 1948 +#define ER_UNTIL_REQUIRES_USING_GTID 1949 +#define ER_GTID_STRICT_OUT_OF_ORDER 1950 +#define ER_GTID_START_FROM_BINLOG_HOLE 1951 +#define ER_SLAVE_UNEXPECTED_MASTER_SWITCH 1952 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO 1953 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO 1954 +#define ER_GTID_POSITION_NOT_FOUND_IN_BINLOG2 1955 +#define ER_BINLOG_MUST_BE_EMPTY 1956 +#define ER_NO_SUCH_QUERY 1957 +#define ER_BAD_BASE64_DATA 1958 +#define ER_INVALID_ROLE 1959 +#define ER_INVALID_CURRENT_USER 1960 +#define ER_CANNOT_GRANT_ROLE 1961 +#define ER_CANNOT_REVOKE_ROLE 1962 +#define ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE 1963 +#define ER_PRIOR_COMMIT_FAILED 1964 +#define ER_IT_IS_A_VIEW 1965 +#define ER_SLAVE_SKIP_NOT_IN_GTID 1966 +#define ER_TABLE_DEFINITION_TOO_BIG 1967 +#define ER_PLUGIN_INSTALLED 1968 +#define ER_STATEMENT_TIMEOUT 1969 +#define ER_SUBQUERIES_NOT_SUPPORTED 1970 +#define ER_SET_STATEMENT_NOT_SUPPORTED 1971 +#define ER_UNUSED_17 1972 +#define ER_USER_CREATE_EXISTS 1973 +#define ER_USER_DROP_EXISTS 1974 +#define ER_ROLE_CREATE_EXISTS 1975 +#define ER_ROLE_DROP_EXISTS 1976 +#define ER_CANNOT_CONVERT_CHARACTER 1977 +#define ER_INVALID_DEFAULT_VALUE_FOR_FIELD 1978 +#define ER_KILL_QUERY_DENIED_ERROR 1979 +#define ER_NO_EIS_FOR_FIELD 1980 +#define ER_WARN_AGGFUNC_DEPENDENCE 1981 +#define ER_ERROR_LAST_SECTION_2 1981 + +/* New section */ + +#define ER_ERROR_FIRST_SECTION_3 2000 +#define ER_ERROR_LAST_SECTION_3 2000 + +/* New section */ + +#define ER_ERROR_FIRST_SECTION_4 3000 +#define ER_FILE_CORRUPT 3000 +#define ER_ERROR_ON_MASTER 3001 +#define ER_INCONSISTENT_ERROR 3002 +#define ER_STORAGE_ENGINE_NOT_LOADED 3003 +#define ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER 3004 +#define ER_WARN_LEGACY_SYNTAX_CONVERTED 3005 +#define ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN 3006 +#define ER_CANNOT_DISCARD_TEMPORARY_TABLE 3007 +#define ER_FK_DEPTH_EXCEEDED 3008 +#define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2 3009 +#define ER_WARN_TRIGGER_DOESNT_HAVE_CREATED 3010 +#define ER_REFERENCED_TRG_DOES_NOT_EXIST_MYSQL 3011 +#define ER_EXPLAIN_NOT_SUPPORTED 3012 +#define ER_INVALID_FIELD_SIZE 3013 +#define ER_MISSING_HA_CREATE_OPTION 3014 +#define ER_ENGINE_OUT_OF_MEMORY 3015 +#define ER_PASSWORD_EXPIRE_ANONYMOUS_USER 3016 +#define ER_SLAVE_SQL_THREAD_MUST_STOP 3017 +#define ER_NO_FT_MATERIALIZED_SUBQUERY 3018 +#define ER_INNODB_UNDO_LOG_FULL 3019 +#define ER_INVALID_ARGUMENT_FOR_LOGARITHM 3020 +#define ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP 3021 +#define ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO 3022 +#define ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS 3023 +#define ER_QUERY_TIMEOUT 3024 +#define ER_NON_RO_SELECT_DISABLE_TIMER 3025 +#define ER_DUP_LIST_ENTRY 3026 +#define ER_SQL_MODE_NO_EFFECT 3027 +#define ER_AGGREGATE_ORDER_FOR_UNION 3028 +#define ER_AGGREGATE_ORDER_NON_AGG_QUERY 3029 +#define ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR 3030 +#define ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER 3031 +#define ER_SERVER_OFFLINE_MODE 3032 +#define ER_GIS_DIFFERENT_SRIDS 3033 +#define ER_GIS_UNSUPPORTED_ARGUMENT 3034 +#define ER_GIS_UNKNOWN_ERROR 3035 +#define ER_GIS_UNKNOWN_EXCEPTION 3036 +#define ER_GIS_INVALID_DATA 3037 +#define ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION 3038 +#define ER_BOOST_GEOMETRY_CENTROID_EXCEPTION 3039 +#define ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION 3040 +#define ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION 3041 +#define ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION 3042 +#define ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION 3043 +#define ER_STD_BAD_ALLOC_ERROR 3044 +#define ER_STD_DOMAIN_ERROR 3045 +#define ER_STD_LENGTH_ERROR 3046 +#define ER_STD_INVALID_ARGUMENT 3047 +#define ER_STD_OUT_OF_RANGE_ERROR 3048 +#define ER_STD_OVERFLOW_ERROR 3049 +#define ER_STD_RANGE_ERROR 3050 +#define ER_STD_UNDERFLOW_ERROR 3051 +#define ER_STD_LOGIC_ERROR 3052 +#define ER_STD_RUNTIME_ERROR 3053 +#define ER_STD_UNKNOWN_EXCEPTION 3054 +#define ER_GIS_DATA_WRONG_ENDIANESS 3055 +#define ER_CHANGE_MASTER_PASSWORD_LENGTH 3056 +#define ER_USER_LOCK_WRONG_NAME 3057 +#define ER_USER_LOCK_DEADLOCK 3058 +#define ER_REPLACE_INACCESSIBLE_ROWS 3059 +#define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS 3060 +#define ER_ERROR_LAST_SECTION_4 3060 + +/* New section */ + +#define ER_ERROR_FIRST_SECTION_5 4000 +#define ER_COMMULTI_BADCONTEXT 4000 +#define ER_BAD_COMMAND_IN_MULTI 4001 +#define ER_WITH_COL_WRONG_LIST 4002 +#define ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE 4003 +#define ER_DUP_QUERY_NAME 4004 +#define ER_RECURSIVE_WITHOUT_ANCHORS 4005 +#define ER_UNACCEPTABLE_MUTUAL_RECURSION 4006 +#define ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED 4007 +#define ER_NOT_STANDARD_COMPLIANT_RECURSIVE 4008 +#define ER_WRONG_WINDOW_SPEC_NAME 4009 +#define ER_DUP_WINDOW_NAME 4010 +#define ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC 4011 +#define ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC 4012 +#define ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC 4013 +#define ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS 4014 +#define ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION 4015 +#define ER_WINDOW_FUNCTION_IN_WINDOW_SPEC 4016 +#define ER_NOT_ALLOWED_WINDOW_FRAME 4017 +#define ER_NO_ORDER_LIST_IN_WINDOW_SPEC 4018 +#define ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY 4019 +#define ER_WRONG_TYPE_FOR_ROWS_FRAME 4020 +#define ER_WRONG_TYPE_FOR_RANGE_FRAME 4021 +#define ER_FRAME_EXCLUSION_NOT_SUPPORTED 4022 +#define ER_WINDOW_FUNCTION_DONT_HAVE_FRAME 4023 +#define ER_INVALID_NTILE_ARGUMENT 4024 +#define ER_CONSTRAINT_FAILED 4025 +#define ER_EXPRESSION_IS_TOO_BIG 4026 +#define ER_ERROR_EVALUATING_EXPRESSION 4027 +#define ER_CALCULATING_DEFAULT_VALUE 4028 +#define ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 4029 +#define ER_PARTITION_DEFAULT_ERROR 4030 +#define ER_REFERENCED_TRG_DOES_NOT_EXIST 4031 +#define ER_INVALID_DEFAULT_PARAM 4032 +#define ER_BINLOG_NON_SUPPORTED_BULK 4033 +#define ER_BINLOG_UNCOMPRESS_ERROR 4034 +#define ER_JSON_BAD_CHR 4035 +#define ER_JSON_NOT_JSON_CHR 4036 +#define ER_JSON_EOS 4037 +#define ER_JSON_SYNTAX 4038 +#define ER_JSON_ESCAPING 4039 +#define ER_JSON_DEPTH 4040 +#define ER_JSON_PATH_EOS 4041 +#define ER_JSON_PATH_SYNTAX 4042 +#define ER_JSON_PATH_DEPTH 4043 +#define ER_JSON_PATH_NO_WILDCARD 4044 +#define ER_JSON_PATH_ARRAY 4045 +#define ER_JSON_ONE_OR_ALL 4046 +#define ER_UNSUPPORT_COMPRESSED_TEMPORARY_TABLE 4047 +#define ER_GEOJSON_INCORRECT 4048 +#define ER_GEOJSON_TOO_FEW_POINTS 4049 +#define ER_GEOJSON_NOT_CLOSED 4050 +#define ER_JSON_PATH_EMPTY 4051 +#define ER_SLAVE_SAME_ID 4052 +#define ER_FLASHBACK_NOT_SUPPORTED 4053 +#define ER_KEYS_OUT_OF_ORDER 4054 +#define ER_OVERLAPPING_KEYS 4055 +#define ER_REQUIRE_ROW_BINLOG_FORMAT 4056 +#define ER_ISOLATION_MODE_NOT_SUPPORTED 4057 +#define ER_ON_DUPLICATE_DISABLED 4058 +#define ER_UPDATES_WITH_CONSISTENT_SNAPSHOT 4059 +#define ER_ROLLBACK_ONLY 4060 +#define ER_ROLLBACK_TO_SAVEPOINT 4061 +#define ER_ISOLATION_LEVEL_WITH_CONSISTENT_SNAPSHOT 4062 +#define ER_UNSUPPORTED_COLLATION 4063 +#define ER_METADATA_INCONSISTENCY 4064 +#define ER_KEY_CREATE_DURING_ALTER 4065 +#define ER_SK_POPULATE_DURING_ALTER 4066 +#define ER_CF_DIFFERENT 4067 +#define ER_RDB_STATUS_GENERAL 4068 +#define ER_RDB_STATUS_MSG 4069 +#define ER_NET_OK_PACKET_TOO_LARGE 4070 +#define ER_RDB_TTL_UNSUPPORTED 4071 +#define ER_RDB_TTL_COL_FORMAT 4072 +#define ER_RDB_TTL_DURATION_FORMAT 4073 +#define ER_PER_INDEX_CF_DEPRECATED 4074 +#define ER_ERROR_LAST 4074 diff --git a/include/resource.h b/include/resource.h index 40abd0d..dc81a87 100644 --- a/include/resource.h +++ b/include/resource.h @@ -1660,8 +1660,6 @@ #define IDD_RELEASESAVEPOINT 44141 #define IDD_ROLLBACKTO 44142 #define IDI_CHECKCONSTRAINT 44143 -#define IDM_DROPDOWNLISTITEM 44145 -#define IDR_CONNDROPDOWNMENU 44146 // Next default values for new objects // diff --git a/include/tinyxml/tinyxml2.h b/include/tinyxml/tinyxml2.h new file mode 100644 index 0000000..124ceae --- /dev/null +++ b/include/tinyxml/tinyxml2.h @@ -0,0 +1,2266 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +# if defined(__PS3__) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#include + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined (__DEBUG__) +# ifndef DEBUG +# define DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#elif __GNUC__ >= 4 +# define TINYXML2_LIB __attribute__((visibility("default"))) +#else +# define TINYXML2_LIB +#endif + + +#if defined(DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 4; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 1; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] +*/ +class StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + TIXMLASSERT( start ); + TIXMLASSERT( end ); + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + void Reset(); + +private: + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class DynArray +{ +public: + DynArray() { + _mem = _pool; + _allocated = INITIAL_SIZE; + _size = 0; + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size] = t; + ++_size; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + --_size; + return _mem[_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + void SwapRemove(int i) { + TIXMLASSERT(i >= 0 && i < _size); + TIXMLASSERT(_size > 0); + _mem[i] = _mem[_size - 1]; + --_size; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + TIXMLASSERT( newAllocated >= _size ); + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; + virtual void Clear() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int ITEM_SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* b = _blockPtrs.Pop(); + delete b; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return ITEM_SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + Item* blockItems = block->items; + for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + blockItems[i].next = &(blockItems[i + 1]); + } + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; + } + Item* const result = _root; + TIXMLASSERT( result != 0 ); + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + ++_nAllocs; + ++_nUntracked; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Item* item = static_cast( mem ); +#ifdef DEBUG + memset( item, 0xfe, sizeof( *item ) ); +#endif + item->next = _root; + _root = item; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, + ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + --_nUntracked; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK + // in private part if ITEMS_PER_BLOCK is private + enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Item { + Item* next; + char itemData[ITEM_SIZE]; + }; + struct Block { + Item items[ITEMS_PER_BLOCK]; + }; + DynArray< Block*, 10 > _blockPtrs; + Item* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class TINYXML2_LIB XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { + TIXMLASSERT( p ); + + while( IsWhiteSpace(*p) ) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) { + return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + TIXMLASSERT( p ); + TIXMLASSERT( q ); + TIXMLASSERT( nChar >= 0 ); + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + static void ToStr(int64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); + static bool ToInt64(const char* str, int64_t* value); + + // Changes what is serialized for a boolean value. + // Default to "true" and "false". Shouldn't be changed + // unless you have a special testing or compatibility need. + // Be careful: static, global, & not thread safe. + // Be sure to set static const memory as parameters. + static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); + +private: + static const char* writeBoolTrue; + static const char* writeBoolFalse; +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Gets the line number the node is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Make a copy of this node and all its children. + + If the 'target' is null, then the nodes will + be allocated in the current document. If 'target' + is specified, the memory will be allocated is the + specified XMLDocument. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* target ) const; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + +protected: + XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + int _parseLineNum; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + const XMLElement* ToElementWithName( const char* name ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// Gets the line number the attribute is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_SUCCESS on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); + + mutable StrPair _name; + mutable StrPair _value; + int _parseLineNum; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). + */ + int IntAttribute(const char* name, int defaultValue = 0) const; + /// See IntAttribute() + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; + /// See IntAttribute() + double DoubleAttribute(const char* name, double defaultValue = 0) const; + /// See IntAttribute() + float FloatAttribute(const char* name, float defaultValue = 0) const; + + /** Given an attribute name, QueryIntAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + + /** Given an attribute name, QueryAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + int QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + int QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + int QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + int QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + int QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + int QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + int IntText(int defaultValue = 0) const; + + /// See QueryIntText() + unsigned UnsignedText(unsigned defaultValue = 0) const; + /// See QueryIntText() + int64_t Int64Text(int64_t defaultValue = 0) const; + /// See QueryIntText() + bool BoolText(bool defaultValue = false) const; + /// See QueryIntText() + double DoubleText(double defaultValue = 0) const; + /// See QueryIntText() + float FloatText(float defaultValue = 0) const; + + // internal: + enum ElementClosingType { + OPEN, // + CLOSED, // + CLOSING // + }; + ElementClosingType ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindAttribute( const char* name ) { + return const_cast(const_cast(this)->FindAttribute( name )); + } + XMLAttribute* FindOrCreateAttribute( const char* name ); + //void LinkAttribute( XMLAttribute* attrib ); + char* ParseAttributes( char* p, int* curLineNumPtr ); + static void DeleteAttribute( XMLAttribute* attribute ); + XMLAttribute* CreateAttribute(); + + enum { BUF_SIZE = 200 }; + ElementClosingType _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_SUCCESS (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespaceMode; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void SetError( XMLError error, const char* str1, const char* str2, int lineNum ); + + void ClearError() { + SetError(XML_SUCCESS, 0, 0, 0); + } + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); + + /// Return a possibly helpful diagnostic location or string. + const char* GetErrorStr1() const { + return _errorStr1.GetStr(); + } + /// Return a possibly helpful secondary diagnostic location or string. + const char* GetErrorStr2() const { + return _errorStr2.GetStr(); + } + /// Return the line where the error occured, or zero if unknown. + int GetErrorLineNum() const + { + return _errorLineNum; + } + /// If there is an error, print it to stdout. + void PrintError() const; + + /// Clear the document, resetting it to the initial state. + void Clear(); + + /** + Copies this document to a target document. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see XMLNode::DeepClone(). + + NOTE: that the 'target' must be non-null. + */ + void DeepCopy(XMLDocument* target); + + // internal + char* Identify( char* p, XMLNode** node ); + + // internal + void MarkInUse(XMLNode*); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespaceMode; + mutable StrPair _errorStr1; + mutable StrPair _errorStr2; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; + // Memory tracking does add some overhead. + // However, the code assumes that you don't + // have a bunch of unlinked nodes around. + // Therefore it takes less memory to track + // in the document vs. a linked list in the XMLNode, + // and the performance is the same. + DynArray _unlinked; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); + + template + NodeType* CreateUnlinkedNode( MemPoolT& pool ); +}; + +template +inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) +{ + TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); + TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); + NodeType* returnNode = new (pool.Alloc()) NodeType( this ); + TIXMLASSERT( returnNode ); + returnNode->_memPool = &pool; + + _unlinked.Push(returnNode); + return returnNode; +} + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + XMLHandle( XMLNode* node ) { + _node = node; + } + /// Create a handle from a node. + XMLHandle( XMLNode& node ) { + _node = &node; + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) { + _node = ref._node; + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( _node ? _node->ToElement() : 0 ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( _node ? _node->ToText() : 0 ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( _node ? _node->ToUnknown() : 0 ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + XMLConstHandle( const XMLNode* node ) { + _node = node; + } + XMLConstHandle( const XMLNode& node ) { + _node = &node; + } + XMLConstHandle( const XMLConstHandle& ref ) { + _node = ref._node; + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( _node ? _node->ToElement() : 0 ); + } + const XMLText* ToText() const { + return ( _node ? _node->ToText() : 0 ); + } + const XMLUnknown* ToUnknown() const { + return ( _node ? _node->ToUnknown() : 0 ); + } + const XMLDeclaration* ToDeclaration() const { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute(const char* name, int64_t value); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from an unsigned. + void PushText(int64_t value); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer() { + _buffer.Clear(); + _buffer.Push(0); + _firstElement = true; + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + void Print( const char* format, ... ); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED diff --git a/include/wyFile.h b/include/wyFile.h index a7ef901..755a214 100644 --- a/include/wyFile.h +++ b/include/wyFile.h @@ -98,4 +98,4 @@ class wyFile HANDLE m_hfile; wyString m_filename; }; -#endif \ No newline at end of file +#endif diff --git a/include/wyString.h b/include/wyString.h index be40923..1439289 100644 --- a/include/wyString.h +++ b/include/wyString.h @@ -477,7 +477,8 @@ class wyString wyInt32 FindIWithReverse(wyChar *searchstr, wyUInt32 pos, wyBool isreverse = wyFalse); void JsonEscape(); - + void JsonEscapeForEncryptPassword(); + static void JsonDeEscapeForEncryptPassword(wyString &pwstr); private: /// Actual data container. diff --git a/include/wyTheme.h b/include/wyTheme.h index 76260b7..245341a 100644 --- a/include/wyTheme.h +++ b/include/wyTheme.h @@ -26,7 +26,7 @@ Author: Vishal P.R #define _WYTHEME_H_ #include "wyString.h" -#include "tinyxml.h" +#include "tinyxml2.h" #include "CustTab.h" ///Brush constants @@ -373,7 +373,7 @@ class wyTheme @param pthemeinfo : OUT the theme info loaded @returns the root node of theme xml on success else NULL */ - static TiXmlDocument* LoadTheme(wyString* pthemedir, LPTHEMEINFO pthemeinfo); + static tinyxml2::XMLDocument* LoadTheme(wyString* pthemedir, LPTHEMEINFO pthemeinfo); ///Function to create the brush for the element /** @@ -381,7 +381,7 @@ class wyTheme @param element : IN child element name @returns the brush handle on success else NULL */ - HBRUSH CreateBgBrush(TiXmlElement* pele, const wyChar* element); + HBRUSH CreateBgBrush(tinyxml2::XMLElement* pele, const wyChar* element); ///Function converts color encoded in hex to COLORREF /** @@ -397,7 +397,7 @@ class wyTheme @param pcolorinfo : OUT tab color info @returns void */ - void CreateTabColors(TiXmlElement* pele, const wyChar* element, LPTABCOLORINFO pcolorinfo); + void CreateTabColors(tinyxml2::XMLElement* pele, const wyChar* element, LPTABCOLORINFO pcolorinfo); ///Function to set the dual color /** @@ -409,7 +409,7 @@ class wyTheme @param pdulacolor : OUT dual color info @returns void */ - void SetDualColors(TiXmlElement* pele, const wyChar* element, const wyChar* subele, const wyChar* attrib1, const wyChar* attrib2, DUALCOLOR* pdulacolor); + void SetDualColors(tinyxml2::XMLElement* pele, const wyChar* element, const wyChar* subele, const wyChar* attrib1, const wyChar* attrib2, DUALCOLOR* pdulacolor); ///Function to get the color info /** @@ -419,7 +419,7 @@ class wyTheme @param pcolor : IN color @returns wyTrue on success else wyFalse */ - wyBool GetColorInfo(TiXmlElement* pele, const wyChar* element, const wyChar* attribute, COLORREF* pcolor); + wyBool GetColorInfo(tinyxml2::XMLElement* pele, const wyChar* element, const wyChar* attribute, COLORREF* pcolor); ///Superclassed procedure for edit controls /** diff --git a/lib/Keywords.db b/lib/Keywords.db index 092092c4e76cf64f921340ae15d7a9a075f1e8c3..c259cb8015611756aa68834caa5a91a41b3c3ae0 100644 GIT binary patch delta 35197 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 diff --git a/lib/win32/debug/auth_gssapi_client.lib b/lib/win32/debug/auth_gssapi_client.lib index 8f7e3ae5f3ef35d12133a8c8c1bc9ac4fcefdcea..0241019c8c3c3d739371731e17ab78e0a82a98b7 100644 GIT binary patch delta 154 zcmZ3-zm9)`6o;vyp{bd%q3I+>@rjoEk+_eL*kY5I%#gX0Lzo0uqK}lsY|da(VM38v p#Uj88k~uP&kxhQ`J(dqBvTs-+`ZlqdF``I>u#12VoSeh%1OO+~DPjNs delta 154 zcmZ3-zm9)`6o;X?k&%UwiNPdB@rjoEk+_eL*kY5I%#gX0Lzo0uE(qjDZO&j)VM38v p#Uj88k~uP&kxhQ`J(dqBvTs-+`ZlqdF``I>u#12VoSeh%1OW5rC_?}M diff --git a/lib/win32/debug/dialog.dll b/lib/win32/debug/dialog.dll index c6fbc25697a7c1790bb57d28699ec0cf38962796..005aa54c6398e82fd874ad12b76acbea1e665570 100644 GIT binary patch delta 169950 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
<9GfBCRV7<$ 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 a0UEPF1X_}GMkP!cPUX_GZzsnV_WeJ{*Umuz delta 169384 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

)gty=Mq-m*)fSa1nD!9v?5N@bw{ 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

H;iSb&8Yg8PEN6XV(g^3W=^vyFE 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 ON&{n_r`4eZ#?V+D4&j1A z-09Yei!R#`Gw*@w<;|%+EG$Np)v-$=vXAXuvH6}*Ji>3f)Oemd$N!AJgg*idv$0a* z$F+3#uj+uZHl7qj5*Jd$**Dy9rea-IwxDc5QiRqM`Xd%J zT^(zJO^74`sJ0GVxywq3`qk7?R-!-2&mR27&d##Z*=+`s_806Vo1YYz{G3E)f|Gxp zs}{_eSM2%BzWVCfv#*|a&Abv165#BTl6mt$Ie&KPT*a_5P?Is^;QytBc?-+LIF=@t`mKZ?#y z?MeV!-zn4Gwu;Cyr)0Nx=9oC`hzZ)y7ALsdJFCfn3(-I>g}km=N+#5Gik6Yo<0Hj*(6Ou{-2L8Km1=7{Qr1+ z6Zp8U>VEubB-@JZI8tJVEKVY9lQUag2{_4$+n23nP`b^ zRsjLRQpys_QYcG-(gJO01BDW3N}+_p4_ZoF+8-^HZnVFa;*=IBOa9;Qx#!$>-)LmJ zkk4NqkKcReoO|wm?z!hKXZvp7H3aJDHiPDhCOR~&r}X9fvm?bCd{f@EX<=b<{2Dmh z+jK@?1j!B6`kIJK#lGR}P`-^cNLZq(Mz#Qgu{qYuNt=r|V&uBjh-Hr5$$ z?v8q>3{u^B(;aR8nfQg>TDh`^8yu!5pMycACx;~$_>Y}sn*R&GEqu|xoIa@u@NYA! zn>A_qrRSf%rWG@WA8Kqg0HNy^dXh!xGEnx%a`-NO>~Vbxd;msAmd%Ipgt?X*^%h|$;MTpxEAV^} z&+G8~2%apz-^H`JPGsT$9P5C8&2@4Du;w~p7{&{=Jlc5LIvJlhJj!hj%Ws*9TGfdw z23d?BL_GG#xLFR={BKs^JCQG@=UsSq;rVVnxhVgucw&+ry$4UG^?i6Y=l@c)IcnBx z@#7!!&+24(oW$=-_&q)9N987e3`3eOJTGX@f2;O$ZdY1)_pFfdb!Y>`z64P;;BuR7 zf{D2mIboZg8HK7tAaj;#C~U@D(tR;PqP^C!!r>Nv*{-F7fcYKWmq~0ZqGNz2ZR-Jn zy8oD;@8Xr69Azbc7%3K+$38qS!m}SwmL&$U#qD^aPGsfxHav&$y$8<`Jn_Cbif0MW z=i>PcJYS9{aEoupb03}`#B)EMe~jk=JimzNK|KEo&u8Je3hB8M&vkf?;mL9y$FsTa zegX8Ss=JQ?-&}VL!+gCEzY9-UchbArXir~vtQOWC>ymZHm3JJolx;z*wgvp~9dp^s zDv7W$*-*5k9$8C|0*x~Ae@r*)h>0mG^e&VM^D>1e>!^*aZY7(svkIU$HHVBE&hUz zV1>CpC`<_-vq&!h)QZ$YrC?hYqsWi29GT|kazvTP7L-Li(Mh<@xcCG-UxFvhTii6b zNNWn(@gmwe4~{G{&#%Cr>!skw2#Eb$GH|-hd~|<&Ah!s{9h3+wgo7o=iI?{Y%PYTRZGz zC=7NB{vAYlT!B{1@?pEW9jf82O=CX8Tmc-Po0`kR4e_aAUy6j0*k90NUw$qYhi?)& zc|OG7+1QzBRCxY8pXWy_jFoB&u9dUInEL$_%*b;Fh)ukvNuyl8Lmt*DFgd-R3iS!7OLr zil_(Ab5Y36&62*=bzyD zr+DJG_&0cd1+-@_BU7cWK$d=Jm-@q}zzd@7zl#FJI@V?3XY=TGo_ z6`nuE^B3@J!)~b8;n{&F*Q8hA$%Dku#}_|=C&pt*_XQ}N&C#mv&!SJZMZJaLzQOEp zUol@hP|jE5zI-`9+?OBD9T1|cJyErmt&LRUe$W?&2P*k$X{3_NN0)*Vi88`TiE^dk z;e4(Jy67^+w}<#jzOPVGf+s0KM@Z0{A3!{%eZ$34wy!T+%lgEu2+52B5v7Q5b_l^W zG02Y53DJ`^!c`$rD#Bc8s9YM(57(;ERweEXi3`JET`VHjfbvSEJS(IO;tohz`Yf~6 zA?Zk!{Ia>hd|$3qJ^;MX!Q8x z^un}nVe7-tCjheXzG21YPnP`u-3A* z8k(VR`WJ`PXbQD_rIIg~DmBXxMtR3~V@R1Rq7mk@!_rxXYlUnrX^EGFgoTmeJ;Uhg zN$WD1a%o8BBnJDnmnoNp_)2!4PmuMUo{#`lx&J_4zNT`gM-%Xp45sAA~+vwarsied|67D8&7z}vV@iVZ73B_xOG`Vl;KdhhMnau<5w#Y;vo>(9GF z>Kk_U7SPQqB`PCTOetNFrf4t})_lXcF$|3`Oj}>P-Q#a+iNDt4pVkt;!{cvmiNDU{ zpWYI`)8lVxiND_CZ*7Uc!Q*$g#6Q*Jvn}zvJifOj{zi|_wZvyVzON;|*W>do@i~w0 zZ;9{o_<@%AJSHrwy5E5@9k&G?sK)yW!&rkeSewDHu-T<_8G#LDUCfV2$dO9%cBp(Y zN8Dlz++bliA5mK%zAZ9*0sS{SoUci9BP!!jwaN%&N1qSW?lB0IuQ1TX;P)`?bB3zq z2cU7w3WRVZ(nm(*;GW_Tj-jsVen8^V{s}SCUl@q17+#@;=HpTY0uY0JEHM?cIV6K| z-6&}`-K- zRI2rraw9_=42|UqMS8>rjccVMvctK-QYE6Y#`LXHuqaXaxKPCamq*UZZb%?Wr?I5M zBP2>dwTJ{~DM2|~8;tugMoDrFyIQfxfOb+jbbUIFeP@twF(p&QSsoj4Gb-P zDC=3QGjIVqj+2EhkEFGft0TS* zk=YQKwMCd9R1U=X{pEsF#beBU@-nF)KBIW3+*ozEMA>#<%R~jzWVyDW+{g@IKrN=NKD?Jy4f`*uvmP*VjOJa7IV^v|mv`{9o zy>$``!+X(5Tn8eLPUSIz;XXz$-dC#Z@ll_pNHkkFcay=N!B!_2oiFAwt*%wv%#IXm z5(*a<{TQOBTvj1Mnzdo%Lgk}AI|(kmH1A7wU4Y5<=cTKW**PJzL1;Rq%7K0?SVDPX zh3o_g%!X)Sd!S{<5EpDPXLoN}PdNXkM`tHT#}CD0QOu|WQ|i4<`re;Of@_l6{P4(- z^gRO6_yh=b52De7GYTFm^^IU&OpSrmXa_M8pb3}~woA$49xV5~Wp3d4n3Zx&;~5LUViHE7dN znEN1cR&~D-ByCYH7o)mzMPa&CLX``BL)Aj8HWcl)ltm1IICJq(HCN6;P#2{p8LBO6 z3YFg{1F;XH^h`SGG5Vxp!5pYqaJ9%F?Gj7YVxhn$xP#zo4Rgz4QRd@hh4CuIs;`pm zuSp>givcTzEew0Lku^%LE6BCK+z&x0j49+86vJ66C@fbsX?zT{Qj&6jg;12*CUBJ` zySy)5q8R;Bd@A|91r!hKn9*PqOrep!Qol4@vg}lrT7I;t-3Bn$^YSptRUpE9Ie`-q zL_35Lw0QziZt}(aUT06>I6)5B$)_AR{5k1L2CV3Q7Xx~7yth!Pji90}SbI8Hm3lja zQD0&(#LHl1B+Y_y62TZdd{8KAnEhdbT&-0K((IiQPXP|NO>qboE^xEaza@{x|N=;7gmwI7?i3qViC8>tNv{T;nNaSfT~M zMl#WIINu}3wVuv%Ntz}8S?;bE4K%iwYk)t z>xl;PH5LI>gCW?Zi+NH1pgqzY2l>{c0nYOQYT4diO!;~%rG2!v%BaV9*LwGWH<>L;0az zXad$zFZRJ?hL5R5c|^Fw092K-B@>Jt36nkum>N2q@S$WQ1;&bmqMEPC?kI_cSjhMk z)@BV(OmT$1S&|B+A%=Oz851!=b1)#LEh0vx0cAFsVuVPT4&;Yn_HeR`NC^4_sk$Du zLe3b;F(VwI^ult$7Q`@+^GO)@+7IhG+871pc2M9(GntyG?r7jP2S&O0ITEQe4h%zU zrO-Q~krUDG5H(nJM297;!@+V~ynx+NB&A4VB3EbxFtB2h1~ocgLG#bcU_|`N5HF=p z=qd+A@6NGd%ES>;c*OCx#CK}Mr6EZ?+Y7}zk_*_l=C=l40_B+-fZQKcIJVQofV&Qf zco{gN#ns}%4v1a%-7eodrC_%J?-uDeN}{5ivD0-xB5mDGkj~&M<~G;QNntB*LV<== z$@HJ(GA+G`TQn8Y+X9@>o7k83M*6cz4~gW|W!4eH*m|6V zu@OS_Plj2|Fj!P5RYW#1fUV8BNV0Lcus>g{`ZU;ToT0HmgTQQ{3~VcKf-O}=RxqBm zj0fVPkcGK|stk#34bHK`C>A68z*E35(Af-RCU?q42C_9d38aN?(_^=8Kq_066DlmO zm{r+VbQgISu9YE@0c?RT2_Su5EE6=Zkj7T$TzX-YF@!C}38H}ct2L+f63Z@`caVdv z#R*}5F*_h*aa=2@7AaDKgti>#l2fZVIxz=8JXrzSdYn-0$1sM8J{E69c9M%N#tGiE z5wXBfHju&=+=N1HO43BFxNWgb2soK3z((h7|Zh;V0ZZedyI ztdPy+Re)g}ER@-1_r(1p(Br8q5{{t_aMo^>%i_aW!V@KmI1FmQ4d?fvz1Y+Xs#_H! zBkfuw!N>*@nO!%NSPU4a$c1VXEqa*V)^NR&3yxt5II$@*I93qdQlO|4vN(-yF0xxR z5XOj63PJMwxjI$sM>Yqzn4#t$T6#(&HR(bm#w-QIBbaeQ8AIJ?d$FP?dIzzXa4==i z7r>?$Wx&@Eg!`I=lZHHh?~^*c5Okrc%isK#%L}egj6MqoZ?2 z<0IHyeb>YZlx}DD>i`_0{OjwD`LBZcMg_x+!_3X&q?5Dnz{E2?JBdLKlCHD+RR}i7 z<-B$J0ZQ^l>2!840vUvyo0yx!h={{UJihcq5IkQAWUIGcycgq!n28w@3Xgw77RZAn zGvhdBg;n`^99)rm)w;o>!GwzqMAm}GUBQ2)ckT?%*{M2OtZk;C-F{L%XO9J)a&=95YqYX4}Wu=u` z|4Z=0nqf@}>7Rlck`zPycXs~`pc69-)4t{;FRtoY0#u3SM~|33R6Eg_Ku75mdkf&S znjkZK1xBkHVC+}J)tYUhManjiPT&CcO`VLXo!rnCDPf(13r+0IM9fsG=?oE_Bo*%RFhzp|2NYWcuA&N4KA8X~qBjtFYQW_~sf1m`8A>R9n zaUoY9pD4_rOsA$|9J{&}S_S$8^TdWFS>jeApB!$|k^+608P)hO6iDek5$QU{rhw98 zI{yVUTEN)vu$t*aCb&|?eotynUFc}g-V6gFGRArOq8z*hIkv3PWLcJzcq za%U1riT1$G?k{@?_Qe$YBr;a)0uCTbqveN7mk?Mdp#1qyge~V>eX=Ne7>-$z7RjwW zGU_{P3g<+ed&`uF)$m;(vup(;1A3vrE+be2C^!EA`8TmrhJ8p1n4!El;jtPiOjg1@ zqwy3kgk*6sCA|k^1*o(8pO6sO8+iL8U-G3d@*-fTQ0HTye3_a3SB)FlTq+s6N+}HE8tU-kAy-uVDtHeiscyeND zT!PVlz}{jjm})H)xxiT1(5qNbjBC=3D(nI{)H&Cf7=ux#Qw-FViN@6E*u-3}K07!* zJG?MGF*`ZdH*t7!26JBvrQ$WtD%c~V8f z6hl@c*won$AhV%S^u;iY2+d~8FAmqTQT!cfnDQ!@IJi*j7R@C3Zz#@yScQ{%lb%K0 z2bJTLAITRD7=R!JB1Bob+R2Tt*0_C|T_gv2`BXeLMzrLaT}0H*Vm( z^5od*2{?dq&JVu9bYI3X4!JaJ00r~oFr>7ADP)+iSk7|auoK11#LfYfP@EVH**Lt_Ac1>$#XecXqR@hb=bf z>15jP;-M8?B4P{V3PgJS0k-B5S^+xc24oq_L`H4}X}xSu)Qqhb zwYsmB>V8$wd8y6uP9n<$brhZglr8hDXpROth&oZ?e>C`v<6B=1ZV%Dg$Z%f1<+0yGgb%cFUcz&6o4L;(cdSui8IF}$@ZKdCR|L`{+`%vLO ze&d(ky!r!Adb_*gyQ}RduX*d=zUu11pK0vWeEL;62_@+F`8vk!mw2X8#` zwYOdMq1@|mCP?7lx%JrlZ+h=ncl^=r`-kp*-OI3no;S92wO#bvm(LGeci;Zu^`H3h z$KHG%4iue>a|T^)U;pg>zx~PF9~{g7u=v?uf7uRf{HOCQS#`CwKkGG*zMy>hs&)62|Mk3M>)#1CI0Ap_3$ow)>wo&;E$_eZ!T$6u@ldO3lNhBaS!&eAq)D z4?bgGb7bac$dRkmx%${$JI*llDXT_q zxp_Po`JVK+bF_QAREJj=7Y;x?W`>bBIj_iULs)aZFS9+Qn8e(&sg za?c$C0Gt5#G3P#Z0sHixpE+O;E@l*_*KXgnvuB&|25hInb}0?zOYoZ=~TOF;%sO4Z?`nEb6$J^Bs;sJeI6FsPJa3O$kh}bpJ1^R{% zc)QMp&^Lt8H>~Ml#36P~RMEH9(NPbZ@~|F^J{XXZ(kXpg6Vde{VMysp_qHbL(zn&o z6yC0v5FgXGHPJ)*wmPb<^$P5z`nEcHE#7Vw*!}vpI(i4*ZV}k8 z>f7q*H}Lj!f&HewA*HJ=Ee(BJ9evotKH_2j>S5pUu>bL}pL*EpHO6n9zO9Zf@~}%i z>?#kt#=~y%uvr~0-!TD{fXm9r*Vr*Eraqi21$b)f-a3FOg} ztD{U8<`L2AdwKi7iVab;h}IbXwboOwxive|60>_Z_-DGnHCnyM@;)t3vDhr(N2v1Z zP+q4>AMP=mpX4=Pyt!&LO4y|l;OO$aQh8n#wV!+ThW2O$zU5jHnbtgdlCV{PbwtyL z#uUc*Q8<}Sp><`{xr`p4BtR#&rr{$6m1xEJ4E=K}gDO5DHBYXKR-Vs!1Flbsz61&6 z>j3r2cjk}vF??qAVN>uW*$C$6zAV=%Z?>x^B42G<#$5`(L(5o>Vta#3LzJ56KV4a4 zQh>5HE5J1NurADE`gYv#oMfV`wJ@i~a2we8L}L_=ejYu^JfS^j&P9Cow>DibL9&Ck zvDD@ud16`8Fu}6?9Ln>fuw<#5`EtZ1V6-7vI+c z!*sKpjfV7;3oDU-ygL3AAo#mN`EOM|jGOfQGu%~8agdkglV&gGmGMbf;oBZ`g&fiSu4p{!9z=&2%;JZt1#3=`CH{hhllNbnPY$>M*Oc zmNy7-f z8D2Uj(lDjrrxUuaO^CzNP*=F6p%32-8>ZoIfKOT!6;TN(!O&9Gq_o~t~b*Tlop@B$ClHvckLcZ(kG`kB$cSmC#|9`}|p#LBSO z8ix^rZRK9&d(Er9vR`$O`w<4~61ax7e_=*;4n(5sy;0z0Sgx>M z2#b~J9lzw@*locL6OW#}L3NEc37ovBx7@ri!yClLx53bRizpZ=2=az9KVzLQw0Agb zg;?dk<-V6t_Bf+2Mu-B<*a@goyV}12T zt2SUto1tFuE67Ld%@b&W`*yZOp_-(Oxu(c6-hndsPO6OevVCAzjMG_P4jLR?;X;D6 zp;zD=JF})HMrRfp1GDvohJ(Kv@U0*

Nq=$965n2V?1oPArS&Ze`$vSV= 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�VG@7WszO?4e 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%0DVpU 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%0A~5=p$SmdzR)Us&O>C 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

H=<5WI*4xR2 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⪙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

}DZ!NHr0-OvLWlnJrNa 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 literal 3583320 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 Sr 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 q*k)Yy3Q@L>1;#xOdF@_|0V10&Kl diff --git a/lib/win32/debug/dialog.lib b/lib/win32/debug/dialog.lib index 45160d9c67d5423c79ae92890a261b689500ab3d..0e3c215e02c5434185b9b9e5c71d0916c4dff242 100644 GIT binary patch delta 158 zcmX@bdy0306o;vyp{bdLf$`)A%wiKQR-p3#Z9(BrzQ8EJ>3pmthKrGbfnzd1i}d6K zR_V?1OgkBo)v2+9)a;n-$SOZsi{%Njl=x&_R(=+c^kxTEITT%DlWW*Sz*3W^u$ch> DIEXEC delta 158 zcmX@bdy0306o-+axut=zfx+Yl%wiKQR-p3#Z9(BrzQ8EJ8MAgv6c-}{1IJ{37U{_e ztkRq1nRYTFt5ahIso62vkyU=O7RwW4De=j=to$q>>CFzTawxjQCfBfufTbo+VKV~& DTiY%{ diff --git a/lib/win32/debug/mariadbclient.lib b/lib/win32/debug/mariadbclient.lib index 195fed9afe142d79c582135fd3e11cacc8bd9cc3..d66495c70b4a37ba4bd05527214ca381b72891e5 100644 GIT binary patch literal 4152632 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�z$W!GM80c**7(Jy0Awvm+##bClQ@9U;!NDBNW1sE`lg-st?y z;<<88-z-oE3N&)4_O+3&^>GYmPM_;u?=%LEXiZ`zmJ*1M`UfoYUs437Z;paQ!sr$ zfgjwa`$4WvA+-|;kjUAf=SOe?9G{J*<8exsW#E@c>cbQ!q+IZR*G!D~_VDt6}9>}gxYz&oa4n9pKHknb%i6Vwu7z(Jp3 z(fLYkndo}1v=#KDR}E4j8lJFBYa__8~DI5Y3%T!jif0-Zxl!w)3Q*fWm}xMWnmhB zQ6iSq(B2SpurAMr0Jyb`M=5Z?qZ4${!;Q3jC=>pyud)f@=CVnI%59qn+@{auB*wMr zV#KT4kJkGD!C6+oC_Z`Pl`y6XBT39n?>)rcjX7|uG z1zZpVbngTyNv$65)>QaB<`m`ziBVk915Fi99Z{ICh`4oxY7^hWNTv41YAcj6%A#R% z&Z&}1y)hzgtIM{;(I$2id<~uD+j(l?2BwU6;tT`>DP4&va9@cRW{8+@ODQNuY*0_( zsZ2etn63BioxpJmzY&8Z1sV({a9q*XJ%eL`O6kI^fY1W?&dYP+C=w1ZyE1d!fXBta zC$*Yl03H_u#oQDF@VFT3BVSFGvVh0M81~mN{)_*!br)nrC?4V4E1a(4FZJ z1>?Zf+Ei8(A%0*EZ`6|`=+zOFufwAX>F~(A93HxugHdNx0ce;GvGEg6&IRVDr}X!* zQ#?xB@rP+UI86JT(|6&CF5HSlVbN*~7DoN}b+%@*TaY|w^E{j4qlqOy`j|!Mz7YWk)2G&4l%CI9PY1o)r5VvKD?~W;L4WEPh~75gkFKxbq5ar!>Cf~J5QeoVusX-iIcXY zo_xwS)Lo}-7x&}|x90?VP^ZW}sUKAe7+DeS5*9^Nf$%XkxPjj0f^dMbg)9`>#-Xct zg)5jmdm&h65Ly`Z=m2lRp!VyAZ*6#_x2hWp0d&6Cu{};2>uhre6Le7qp-*=CrBY;! z@X(VCf{)X{eN@>Pd^?y%LQ);Z#EU)J%8Y#9!b2PgRYP>qmIo<*>DlBVF%-#YFqTIf zO(8KFNnsyI;;H*(^|_XYqm7mtRf{|v?O*8O zk?K%8iV^k|T(v2^uwpwntkE70s~_19Udse$Km zSg)voW!N3ztFKX~pim+m)??3zm4YcxQ+W^KDlCAm!Zd~syBDC{Xmp%(JYEE+r~;Lu(? zeR&{U*)!PTLEq0k6ed&HSb}zDFk?=yJ5C^YmIQa1f|Ri|7BK-?!`mfVI76yihbTZB zX~Yd2O|lWECUL>OVUI%ardBw@b0-0f{{ z&C7<4IV!wED-m&oWtIrw(&JXZ4O|+M32hjq5SbCw-ewQGEiSWXcID|=J!m(HG;p#; zbZ6X_KI<%uT-XhUcWE+1gW*F4PGS?aFLc;Ap`)Eauc??rVa&x6@ujr!T6?z0tHw#| z4|@2{*EV+W5(nL*ap@_0F`tn(wg}j8%n7f=JyqQ_iQ8$3-J`I~UoEJk%!b23stXFr zT@uByI5`0Q*V(L@x63VwV?H`%fJOK1OvriNHmhQd&Ty#v>NFF7gVFQ`4GCD_uX0<5 zm0NFo^NNY2yR-p%UgSsvj>kvbBdaZNu9@6ut(d-!;?b=(6pJJ@Rg{=#h&bjuR=(Oc zF(n0}m|(=6IQgQ!a@Z(~ICMQz62b!-k+pSlxYfn{gZ7er~wBTOlnD6*55Jfw1SHB6#N zi9|5Ui6({ha2=~v%YMzpHtqF|PK$Qlzwo z8o+V7W=OTj9~Pqn70u((+R^LC!eWU3;uB={@84(5}^8qP`=50)LFmt8!}r8G`e z)r82mSc7ChZ5A1|DCF@}D`=z@Bu#A-_6+=Wb){BBi*68*>v2U=(cK;H?WOQ#_Jk$4 z)}Bzg$f&A}PXjFGs(VxH@Y4IX9Jp=PU?eLZ?d>RRZ82Hv`b~Z^%n0Wo)0#iRho#2b zJEb;QyqPIdxS1)kx?>t+cSqmO@|r2JeL~zWKhC=L{Q_S?shp$)(r(i9jj_+q9Y{Al zrYxw({e;;vte0r_#JL2Ku(U}FH7Q}>*A-dreb#zzk;DPXBy|oS|KRgm>J&JCNSZ-^ z{EM+*0z@%kJKAiKhXK(Ru40_6&meFtGO(Q5@EMV~=qAipu8qx&%;;PXOX*=b4aeds z$#ADQp$cP=mX55?6(w;;L;GbtrIC)!^Segb)FK93*nx1OHVUU_bpm<(&Q4q!3`V74 z41y*!h_CF_n4qDLRY>S`mIN!C?tBYp#*x&`x`2>m#>No+)#;QV+Grz*$cM4bCz@1I zNVgMyqc0){_YdgPCVOVEUUhH|%X`tPPefBQ^N6CW=lr>N+@q#vCggDjXM0be_ZcF1 z@r?QD$vrrBtfv?f!;}0%+*C}G$9=~Mr8;2`;*8^w=WUFwBJpI^zZRc(P>Zp#>NYE5 zEs15bkCke_;bU0fqr49sDThTwGGx38A=(*YJc={K<#meLQFSLEj1eiZ>^O6IdEK8Z zHJSozctWI+SZ@^kW0b(fEtQBR zm?})P%VNwz)OFaz-_%e947SEl$o0nv#8y3hSaszBG;+)Qf@5H1thJA^zbO?yZ@P?6 zAo=mPWTYW)1dWl#r0^_;$=Ts?b;%H#>rzN;bO6KBT!0~QyZBK@B$+qS8|s;%q;0k# z;A}Sz9sBj~KweYrH1X2fNnT`IwsGwz@tC4FbJxFx(|(P2OrxxYQjz{GBEx};$uyK} zuKSdN^*>&nSjRdK_U`;yZR0$S!`xB>(6XYBi%P6&pb&# zE#u$V4wozGYDOMOS3g~8=Dp{Q-39}}NjNz;&w5s(P!cu5RhRD@p(8eygghx~uo<>gry8$kRDotmrW+RDQ3gJQ2+W*(Q>n z7*cC%;2;r%r=knPY|tJy{KPxl{;VpEl9-vs9rFUvcyPtKWA@^%jR2#62_t&Q5Ro%n z+z_!z#DR7})e9ynwBKs!D1KK>ET)t-fje^uGJo)@34A^{^Cw-~7VAe2i)Dr@I=a$+ zzLT54a5iW7(3Hualp<80Cr4JN2%ziCV*pR!GzXL?pJup=20Nm;++ZguFBt43DJiqn zd5O+%76L<4@8P&Lm=R%nv?45J0A?#{&7H1oC|f-|k#$BSA|YY@5lK_|BT}NdAloFY znP25n5F1nF?;PPDs0CVXvj}8+h`Uv;|3Jq1>sE=b7Q_NsFNZTyEn2HQ*@aF@=6NY( zoLQJBc%zFaG}VSMa3g9YYXn2ZdA_fafMy6{u;*nF5mq$}<|qIVNWL})XW65haq{S$ z08tHhl70vV72NR{JE~#wz40BdiX{#`Nb9a3TcsN_+x?wpO4mn(`5y1W3SD-K38rp9 zL?G!S`!Wewb_o?QrKEl3#XwY;hTmc`v{g+NF_p%6qCIw8Y6#ve6A+#vO!p@iCk@u* z%s#Bz965qbj%=Pud&7lvY?Eg+V$Z0Ak*&sQuV0kn^yql!*!!bCt+1EgWy(TDUvB zeLs70kqmG00o#xP81bSY8_31gscS; zwB{qiK|pePW+ADMm4?%@68U5KNrWjUObrz)*X0#lOhEYG7f#d}iz^mKi;)Uh*<63N z_+kq$@9Op;;F3|H)=Z)eG(4^;Z3o3Z8gPo4O64zm*9M>QmYY%j}CB$+A;C~{YmJy60+CzEV)vVxXC-d#W zaWSM4HEs(b^bzL7(!L__%_zIv6CsY@peCF_;gm&pB^}a&Xw^9t1B9KFzG;qVjJ6T$ ziJ??*3c5TYVIu9Q0V8gr6`#@R#hU#Co}CLiwQ*X-%JvYihx(JE#2 z+BoiDqa0oVyha|VN#Usm%IODX(lq9+XISYUl251Yo`f;kClKCFK(#uUH@AliZB~q} z*)h1svY9ueblJJg21}S)<7(=DUQIF7tfv^}tdtnuZiN|bh9U{ChDk=YYd)hro^{oO z93#{F14J%bRui*AP!UEaC+d7f5r{^t;3Tk{kO)*iu9C}9phC)_*+uGcx+2j-azNL0 z3k}&hJCNpwPeXqXKr?SEpqM{1+{;6^%^*93uPeA9yjBBjx7kFz%eK{UYW?%%SXSzx zl=Y06;APGX5UY&!r|a~NBX1A%#E<*86;4cyK(`Ybj7k=6jYn@rJy;BufIQ*5Wo8(O z7_zAPm?poCwQYFH&{i?c62z-O=@AS(;Bf?>zv4AjNMMadbZIf~6;!zpTVUc6M+S;r zLWa2<(dcfawd5pEL^%zkr{l5}l$a1Ji+XxhOlr%Bj|3}&bRATQcPIO!-7{Y%J;?@x zFWoD5StoRMX3(5Du^wZh`YB&~n ziN!P}awY@%ds1#mC0$4v}u% zl&sgb3Eys<0W0pm#-fLNWyL2hf~gH~bV1XKi4Easo8)PWa4l^S&eI~ny(%SmyG9w? zs!)v_ju0L3n06Kz6)}(D`n?!Qs7QKy0Ug8zDUGvu;11#E%+$b+aCDL<7zG$2QE)e_ z5OvfD$O&o0>1=`N&JzgtcJgLA6Y4G%=uD>yKq}1Fj#itdYn4pFKaCE@akyY`t)K#0gB1_PE=MyWB+Qg1}>)`gnuLJ^v@b-fWO z&3tqp1~a~HJq^}PdY?T`A6nH6PmFe50$BnPL8Ec*KiFHK1+h?QLQKzqk$soi`p)^m z;n_iKN@avtUcrOlTQ61@5$a#{D~Tv(+JOYiRFjUyK_^Xiz{^s+*@ z3vxjuE^kEpa5BXaVuNLwFEe+l08s(Yu$`cP-Wb7Suvzei8j$X`v0-v`rU@wY2AgRn zVc!T`&9+%*B%H=ZN9AIHWNi*mB+6T2hkT|sW;aa&d%7p%-$=Gbkw(?^#8{dPIw&F` zRZZq}{1THnjQG{?STNQ2lu^#WC~@tC&XAZB*5hGDc~eeCl5=3Y6pU?Wh|s;#M0}q? zuT;dKQ!+wdSh_H?+9s?NKx@N8*i}u-P&EGVuSiO}@p^hq+NHW6+ZSc|g6v*0t9jI` z)km(SMqjinui6p=s}?{|r{zSjOYXE2BCneVLA_Q%a9^v8X{?qQ*I6wQJ}yceb)@Br ztCoy(%bTzbH3@V#c|&a}xv##2ZL2F$`0Y$6g~O!;1CH0;E6R(Af(w|d>h9W)1@YR? zwq?TjOE|*x*JwuW`S)>uTKU`#r zR^7GNALqw;Sgg8;#8pjPAe|1PvAx7j_YjHe-XW0Q7$eYr-w_0U*AWDLty@A*`No*I zvB4hy96eo|f)(bCj4Lt#D%cBE&~*X_KBhw&_^=$t07FKLxRo!xkl=8KX|kg&3`B+1 z?NHkjkT#;lIfDe^#8OORO%!?=9+L$%)!7G+ zX32Rl;5dgNwbB_QIj%nY%R0DKPt_q=hzkfe+d3IX<7lwtumi2U@D1=LGTa(!q2XQ9 zMA2b;t+PDja%AmCtOE7%9cQStmO7W z7yY1#rGc@H>?jYu)y;Icu;0q;_DU1=nR~ZB_54m3-9(06Y7_0`=43oJ4@^*{7HBo1 z7*sW+FrI8Ip`YiaOX6BkK5K)o`Qv^W%+*Ju)8aQlyeY(N5UD!3gp0d-Tu6~bI)V^4 zdhPD?RFAT_CxFL(n!{JTm`iw60J*(agLk~5R*jeu9`7PmXj*ZEA=pk;gz>M0an}Ua z>M6vks9MM-f?guZ=nx?uKbmBZA)4OloUX@aoq$&K6~ zaX^184$Nz;c^`gYDC9|`LCG@(jnc+agOjHP8byVMN^`Dh*pUw5Sq2v)stU|Tx1%}Ne50LxCWb< zQJw)*GWA{)=b9n!$*6e-EZs6Qixm-txX=^SCD$>EDZw&4mG;Ju{RCvb%8<0L97L+acVu;tB|DlZx8l5gVTMMDOmd~U7mKSvOt z{SO=L0@5-ZAS#nnp#fZR3Sgf{oheY~ij#dn!i`cQ%8}5h(3qeW{{FHT`6p#t0UN=Y@+qp2r0KAPl5GzyeVZt{LbItiV-+ zDqw8ZutOE#c2NP4r6Pays&Ns}R{Z*-K^*-&41!TB?+2)h5=3w%m2lS4Atu?!0g>p{s)tpz0lvm7E@ zkH@EG^^nB{f)3VQS;*vavtdN*J&i>|DEu(VA1BAqp#G?M<5UqBYehI4MPb%bIVIrI zOe>k9102I*&#o2uJdQbJ@@ z1YXrS_1X%jqY9HRhU#R5b$eG%dw^Hf{R~suYOz~N%IM%v+)2+4s1BYkoK#?XgxPEP z@Yy)v&%}A>4cmdnlTqm$q79xm_m8wurd`P zzA0yCQ`URLvF0%-R#_SANEcaDg!}nVNH70x({Y+cbcuXeE&|!){ z3^K+Y=NRLTa{=RxWQ;+{ZuzrYLc7ZkS|Jnyv+m?pT(I6EB4b;fQ4qKtDC1kbArrWL zEMpt>lkq$>Vjiw)FjKf=oWhEC9CByP1m>olY6R5m0-mCt!|9(MaC}O6{+ym4xuM9t`|UQ!mpZvay zXmpjoO@yp{&)V+@xMHjVo1TT}xo_zS%X$RL<&f;MW(iZ9^a&c=7ZmMy%5k(2i>Uz~ zzM{51eKk^xmr+TV2^LClA{wtV$*x*LXD|ZHxgt66Tmz#v#j5LvGx{}e(&IBF!YBa^_M3L<==E^5H|a7P6o_f!C|rviXI6#(q109Eak zHG*@Cs4CbJI8BC0YJD--(N}`k`ihuJUktDHMPNr?1a|aAU`JmBZt2T3nVo&BL4r`! zJ=w4TGnoR!2;NNr4Jp#MX@MGN^j9IZ5-nP3QXx$i6|R|CG_7W43D?YQM7A;;(2dLj z*~~0(t;|xrwld4OR%R2jk=cm$GfT);W(ikic6xTN&LsnFv)YAg!@Zh00WH`1_!m}g zD~3Tv2N9;*a|Ega6U>y8L3?WdA3=9y??^B&J1I`38iPs#s}YH*b4M{R{Vd+G3d@Y_ zI1mwyyw+Vm(fe{ev8L+4;Dbt9iC|CD+1_-j^fTVwn~tQ0v5CNo6Z&wLwpU?&u|roz zR4wt2pO3+O+{s%wxxjV5+#f=A?QWQ0O{qcz(6`Ym zMx~&zq0oHroEjn+i^3k9;4NbjhmslwhvhJZ3NZ9?J(w}rl#5}eV6@nGs~>AinIF5< z#J7ls$(aL0uQfp<9t4jx_in2yef#R*^zdXdDUJr8*&3`a50*I?!}jLlV{=2dMhmM` zjTBqO_g2;sM@+ndnE|xrNrinpSRHJ@zliPz>sN6!rbyLrAy6XZ^EL`D4ww{N+A$S^ zja-wnSL4%F(amcT^{jzH`&pMk;}kjXWj*zf+HMUwD{{n9iJ8RB%I5Z?t&M@M-IO%p z>YOHwQ1cT!5}mR~zrADU0vE=g43xXe45Xf+PF)$Jc8m;>+r? zI!qGA@=5S2Ge8Vhw;F{LNQYrc*Wl^r4vDHl1~FAJm!1rko^EdIXYE-58Dnyl;WkTy z)g@nH31Ju|u)~KeIS-Gx2+Y3-m0?{;f7Cy zR!p8Yn!r{>ST+$X_&i%f2P|aoFXss!KZmND6F~NI`rd+v;8e!XBB1W&?=R=|4Srgd z_YBK>9?N?b%cVSfzQ4S*V3`7Wmm(O!iTieBaG z4BxP_TB5fGP&|W5Lw5w8<2+Qn@h6}qpiuy-ys;31C|7_$NXy^w%;GRFiwnlQv?vgK zH9=>OE`8LHI>UT9#AaA3Ww5omw73r68gh-^9DI5kT~g15t3HWPx=-Lq*<62$c~L1W zB@QTuYd|!(tqfrjq0-X~)e@UoRSOuM zh9>!*ENSl6DT8&n${}5`@DiDdJS_ zzRIuuNEoi6%JfdTg)asr+*RI#1rjrp?aG7^OLqFClWICv!}~aJd{dMHg`htcdw47( z77;7blsJoL5F#EO=B;6ZKt-~ANV70iL?E!t2_!s~h*ik7?1~Jn@`YrU8-Zjl=x)`c z#m$wajRAh48u2va2RP1LD6Oy}A&OiKjg4+7Z32~PofZu<2;W;cXt1X#q0KvDjsL}3 zC520b-Pi!U zdUu=!M4ZDcVk(9k&yd$TQw+9j7-%`HVaq=Fbi2_Nd{yZY)o5-JTjednn+>htTLL>x zOedyBh)${6aZTYiE<;wgtVm#V9HCap(D2IYdx(%P+;6zj6T+}bV29840PhYrhX^E0 z1eNv@u2EkJ?d6eqHft=UjP;__ZE)VO;E>o#b4c7;vvhT}C5l?%T*j8d)iNm692-lx zDqg`JS$uL7-cu(hgtl(Mb?QhifK|#@XJ^0vf^;D^Ep<&&(`!#h4U_OhNHk#3~{j& z^VEi;3%a@)P?lXr)ZA7dKf^rJTitBJs#j>L(MzBk1DK$wI-S5ZhcQjl%Rn6Hyuqwy z;!Q$6l{=(4r1hvKh^jitTD6rj+T9(WoS}<~CG?)lkdf4@Rgu=L$9 z6;Wt7HBJcJ@#J_nn+~`^3M5^sJ}=9DT7Lzs+&qdzdgsUp4oipqgUvm|1Apm_Rnky& zRlUGwd(N=VaDc-Sf3PPa?gmceWA3ClJ#@yGUBtVL*VV6^ z1Xilba@kdhjrpw`bV@D?q}o@)^CTq?P!#*B5v62KGoo&wZ)8MP0Mk~~h>uXTtf~Ps zC#r%f33W5OTc#$Tx?u2k=MLbfZAfFjjix>wAMc^q)hZ*wt3^Xbm~{b}dyYmQl+5ZY z$E+=KK0O?V_UGgkt#3Gevx^J3s<*BWRw-TwUaNzPZ&9=W(@AjFNQ9%w!YXh`mVpVj zhp&#{!-25DmmoWyxP;T)h4bUG>5XF8{81iuUrS(!I>;BxGxX#f9T}P`;RO=v<5T+};I3|9|h7>trtiWqe2VxKwh_iEP8HxzD zz^3S%!5y=V(UAr#S2_Ab=<$Rrq1Mdw)#UB|=uB+kV~Xh+R?gX-J(UB)BRqP>js#$i z8z|J?!f0A_!i@?`RrGdxvLm+)f+OM)xuaMVPRKUc0w^VCpjuXBsF-mxOio6)848KZ z2W1ir5E^v31qauYqG5wJA-Zr8bO8~#7xh_LftKtPn8*%*Zt4J3i33Qb#p_$H@B)_{ z3RE&dupka6B|9}m5XwL~R%L{GQ&&SRedV1@mj{@w!ZxcXR2O8eXk%V(oaxT z34v}4#1(*synJ>+M!kIARB@-P)el@~_P)y*>XLPWa{wR zA;Ft%k&#{PMT(Y^BD&Eo341}?j3n*$83=mvFWF9sk>6Gmrf#npb3vPBI=|O4s=BwM zs;$#_DRsYjCyHhhj|4pp_L@2+cbj`cxJ^DI+s(d^I88qzP4lm2!!T!J}SOt=^E)jv_Oz#kJiDLekaoO?kmrxovISAQ<3ysW z*F?BGA_QEsLlm^v8#1=3%|<^632i4RP}>6p#%=x*uiL)BcnzOB;*bp3tAlTlvqDIR zPU8Z@3KJWM@hIPzD%C_?&Fw!CK}Muz!ge2{)XPtr{fyE5z7|QEwH5KLK1b+_`dy^y zw6#Fd&BJB;AhBxn!;I=Gn^#YM4Ku3OW0Qo3g~;!I%Q$z^%Pns4_`N=1{GOk&o!(z)yb&N{-BCbd)kqLR&Mv~&baU}N7y!hc zG@u?WKGr8#)NXDszzG9zpIYu<12MTvSEpBzQN~rwGR9;0bU^z7f zda@*#6aRxJD*KmIRS+QDoQmerO_~^ zsG2Rs4N4Il+F~2AQ;X-v-TX$ho8yf0 z^Bm4R9Ff$77hQFT}6YLs0-yhqEIQVaPx@q)Q%Bu0mkc zTQpLjXv7mQ4wON5f{F;K8R1fg8#sJ=prxPeyx!Y)B)nPR0(xb6FkIZ)LU?5yfSVCA zVxA-L@_X{q0OjogjyxWdJCE(-8KJvj2Aih;UeSFqSHAyzq9y!zWu6jn^R$B5iL#@aP8U3(u;a6P{4vw0ahG7y}kIX!6lmi>?Rh&8^EYk=UeE97m*wx0Pd>4;Fn6*>Wl4SC_Mde=;v<= z>qoIpFdqu6p(IgH<-F-fup@Ch-`d}d$%B!VRFEa$QZIslSTn^2fhjbLhcMGS(IPmA zM`^|>qD06LpDPs;Ltx3+UGZ}`IiWD(rE-_<(sorPSi#Z7vIugrkpTK)a{-$RI&q-PXp$J+e6a} z363|B8gc|mixCJTC&ZpN}v0I0%f z5S1K~=o@x3iaI}5jl;m<%${2pqe>KGGXg}cd5Sd1p=*ESxT!CsCS1)3E`k#b1@gTW zA~wn+hILvBXXJq6gFd`~2z5(MMwZQ|7#_Xc&t@dbL`{b3?en4fznBdz`-T^YVwxO` zz-9-n_07VaR$i#BwQz95E+d^NWN27@eOa1jQ6*u!uoabC+(6YXaKN{U9I#cPY2TnU z#2bkcP=NIvjymmfQ=;r(PWt3w%S{w8P8u4vQ^fGPnG@FOYXo+Q@s?^DRAdopt6;yw zY4_UF79xgV>4znnrYMi6QK|JKtpw4Vf&%ID4XNU|Yr2%hsV25LfL+R&ngg6;blEAF zQD$~#m@_>GxZYkf3==d(nKU)WC^O^25}hOviI$;yjs-|W1`A&m zZ&0X6C6TP=R3eHI3F0d%OGkv6d=ipNZbdMxO$M{qCOI+ZR#L#iu|yElh@4$U1N=1!c^#WW*5(}4% zI!`$dYnc~6xIDeE;qpRUR-WeD>G0&7+|G8|Ul%fa=` z%WWYi5fA+yOkXL*uO*a-9-z|5mQ6L45+Gx@;l4lKKPbJ<;Pw7Oai!^RI?etI9u7|t z)tq%(D@9sS5ABc+oF72w3_DCxI@9m zJSDEZq%iAZgQ9Jt3XCN2bnPWqfm68QXU`9)b-y}4+rwDyQK02}BMVebrKcmm$+=sw zxXMipz~dcB_Hg}L_w>j;;$^(mR64fKMLhX3DKk+bvf}~RrZ=ub^RbztR>kGwn$7P9 zBz_r9O0O#`qoa@p1&t>i{)F!ECv=y;*DH_+10XqI)+NSC(c#H4-EKOYRNaZBF?u>a zL_96G(121O@Jbs|ZucP8obZB%!gTynuG@zg9oA$^ix*M!G8%X=g|@hs+DC>blh+4y zu{YY98ifv2sbEe!Dr*w*)WRCXXOuR~nTS_`(h*B$E>TChCnNZJdG*~GP)L)xU~zmE zhCC^$JFXC)qv^}$xI_43Of{j&VI=RgtU@=%WQKyB9ZYeC?rZC0ifJZRW1M!p;uBe# z(t2d)rzex*-6o6QA2q3bMSW;8I8!Y#$|RrZDX!Y@(1O6rCu2i#XqDO;NLd^haT}SO z=0gN4hz>*L6X+IC%i(HShY>UJPxuQnlA9lfn?5n777$m9+bFa#w@`l04yV+Bkfq`D zv_uDzMLI(a(7jh(`9y-a_!kqMP7%ev(^Sq*v3~NZFsP!9fkn)j`lwj7H+(9b#c59{K~o$$h?m-Bd{cK#&Lso7l)EY??)v@ zI&)E(EzYd^651@e5}2J>yrMEQ?BURR)aaLn%4*L?1xIueJUmk@S!h~e8^}FcX1=>SteH%Xk43~+ zs%bJ!ikVpPHXBQv;Jn0h%mJAhO*_lFV2uK5AIopd4<0yrHH zlhwe2#jsnU{B=1oGr>HFH-no?b;h2bVv&*(SJD!;n3!55s1d|g$5zM^q&2d$xS$Lm z1j|IVO$L6T0)nTa#BnEF!ra_i+dw34EL{%vlqo1Oa7SXo?b}KtKSx-;s>)=?Pj?wY zZ0NQ4xDTV5(H1+SohdjcZwba2O$Hic0O4d}4y{BATs6N^;`S<InmV}rb_A8ZA0>Zf}5Q?kI;@X8sTwMRBS-@6RL{}?c zk<=P|1PaFP^FuY;M5Nc*-#TsRt!^psR-pkK0sb&@mtC98G=*;ClN|{}+@#YHoI31s zfbCM*yU4~e{JWHzWr=LZZW&N12)Q@jIajqtKxfrTVBI`2SJhCdJJJ2$7ud#JZBb26N7D?!)NhA@p%pr`orVs+wW{?7{ zO&|hSkM@K#L%26@R(gGl$cXMlSNGV)K-V4Tw8ceMp~h6U4TH986hbTeie;^kE_Y4g z31}?vNwz?_%q8Aq-8HhHS=d?o?Wp*y(eTM$9HPv^i5zHrIR->H4JI?N_8mhC!nwfM z2_0OAm&Yn~=bBR|S6-&>G&p?*@kLC8@68Ak+wcgHD+&Vfi7-qmc(!Tqc(9Q*D{&%5 z0W(f%&Xw(eQ>c9_LufVD;vaDp{|I;Zn*vFf*{x@rZ*C6}kT=ZBTHOihL*2R#N#Oq8 z=C@$#J0u~e(=5yK{E-o!?Z!9jokoE}NV#;7y4-!tAJv!JuEeCrw_7Er2sU27> zrp*bgA|6__ESZYN=eERvZAm1oBN3itsl8$w2Scq~&_Oo4c~D8uV5UcUItms!W^`DV z!~E1l$U>GRV$Yi-Q7*9%JwF}o=35IAM?+%8j1p12-`6MsE|;<;2zTm)qmW`jmml#` z0hZ|{TCF626=R5-Cg`@ z<%Q5^cnd(9%cM|SNs%il$(a{&ZU}GZ293OEeo)lz6rd>3=i-?|F?7gsP=>;QEH<bbGFtU`usAZ7P&AQb=eoue*%UFxl;$>_)HR^nie^R&k7z^5!)Ts(ISx zHS)?0WAeIO+)TWBEyigrexF7mjUsF*2;FL!VT+As9Ud{UNh3O6rElQROzGllYkdD& z>ri5hDkVynUSd2Yq+9vU#FbI*>{YO83d>+;9?LkB`wXW_b^5cy>uJrR>bcFM&=Z_T z;mmRsnVsq?0zKbZw4C%5&Y$@diJeUp(pf1gyf@`2f@;aAu+mEby;0+)Bhkzis-Da; zTDRB??lxEIn7yV#_zM(CBuzyUvZqMGcNIwlZAB8crAWs4iX>F6$g&o|hG#rFRvl6x zO}7&md8C3m6&PJN6pC}W`0Vl8hPz6lK3~_`XSRmRkK)@in2^MSvReVA@)bZd5@03j zQ6JzX8?mVj^zu+9a#eP$?UmtLc-tbiPe8V}R-Of;crgJRusMAJmKXSRWbLE)TtFY$ z#6$$2}met2?t8r z3PNz6Yi62|txOZ{GMOg2R;CG8Wm*isC^|KVs)8YR7ZxNjq7bKMdn07s z-UwQ8CZOpZ2zj{5&zGy6-gW^O^RWQRQf$5VkQz=7O1ez|^v(?Uh9@f<&(_!0@?#ts zFnn}yrZ3kP)O#{gSplzz>zD6633kawnslixgscETD35 z7hp6QM>jNhiig()y?CfrKwG5_CH6V-g2s^@7COa^R*1o^LJS9al8+dE+$)3?)E4uI zM~%VvwmiIEz?g>MDLFc2(_%0%*w#SR&6gQXPBWZW9$nLKh1-+oa3jqF zZNzf5J5`wtB-5}^G#R4$teXWv%^^b+!x*&!5{QsHT5vg10vWu$0X6PL zVKh#1fe$GVj}gYma#d9%@fu^CZ>{FSnp?&>BR+8@F5Zh1P%NNiP9m+(n3qrvbs5YB zV=rv-4uywK!g@>O7T%VIiyS*e(NO&Ti72mD@sw zrqW~1MXk$>Lc6@B7VU;9<0tHm-Y6ndkQ;adZ>uJYuBs!_38&?!@r*(JTFDd1#Gq_R9S8}sNr}eQ*ZKX4>T{)c(!o2ki z=aFVGe>;)0LnJYpuRIi1_(Q}MsTbZ^LR$;OoV-~(iH%LH$Q8k<6i`NwC>V|PZP zLNg85%~V+;R$AOx^ARrn`4n7)Uy*PQ{D}K)o(yTzm1!C(u`ZpQgtshsj$z|Pr$M_! zwne){cGV?_Y`Yhzs^JS9wcDy$8@$tk1chnX0%H{?P;R?5_?B4OWZ?qVY4&U?n$IY2 z?qc?e!qvH=a20OneP)~{em`S6HhIagTWef6XR*(6{K}+iZ0Lkgd@Rt^iK1|ILKGAr zpvxi=xE$<8Z^(t=?l?Kri#5i0t;%gr2&0L}t$NkZ9O}`ifU)dRBY?t)o4%!@&|p;x z6mqb%#cML!%2GsnWnmznAR@p`J5riAv_%R84a0L!Z^oA;tCua2Q3wm^v>T3|UbP#B zT9wAo*sE*HgWBE@U!|)TqT%^tTKOp*6)>)m%S)cD)`&F~9idge_|ZO^&pZhL`w}+R z*ATM~J=&xSaK|=>A_g4FqPOP~p&a>QVM?;$v|7@M#8l12+sY>9M$k=OFPSCt4rdhr zLdmsSC9ABzM93IZYZ-3qEgE>k11qW$6o!f|JnT4k6#<%gpMxE&BL~{!I5t4`GvvWO zqpfL_Nt#!@b1vi1PcMg58FU7I%9b7X36`_zW~1uAlmx95d)gy7u2q6*$aZs-5G|cc zyr=SvuUlfwk}ioJ7Aq1Tjp)6?k2Y)CX?9+VtA~CP8}@5viUjI;t9hvlrVKJYRb{Sf)YIH-`uUD!kzt5~syZ z3vEoPiKWwq13zk0Em;xgH&>OMNa_|_k+@r`l*J^?YuuWXwN4}sRT~Y->UJ97)CkCA z6~esNj)fcj`d0IU`+9_waOoUgm>PeY^CNBiC`6xjFyy>uDtGX*F=nSz7Q{aR0 zSXIbd4mzO7!hTRSF2k^1G1LTDbyfYrQt=gpAp%S3HKHL?;os_v;|`C!XW$WBRHBPG z6b)Kap315Y|4?TnI-IDh>mHSk7vWQ&t!Qrwm+S<0JPt4ls=FSBvf5jhGPN7zNw~9% zEWCmNQ;$R?JvtCt-|3;ANDRK$n5YL<=2MlvTXmE?TKgK!IZ%ioT1Gj9S3x~Ie7C-c zgK}q15n5;U|HYt#dy+<}EKhX`e8W}J|- z#+ZeH2>lto%xf|M={G0fXpZqVb3q_q;i^J?iZc3*9o1(-Uy3B5_3V!jQUbdu5iYT! z@mpB0Z4fSKk9&|`cSO`~JcMnv48r-XVryf2bF12z1*kU<1q{s~s{Iyly~4^ksxq@L zD!6){FSxo#6$4`IfI-z>*^)W-kcy<9EGv?_EhrLi zic$p57^U#t+C}rp4;9p^CakjwRP33iU#(1XpnV`}9tS7#;qOLf`jx_hxUGsCm@X&u z89S!g968foMMCAip#G32cZ{oeRdZxbA)`yw#p3>F-OiZ|ec0cTG2(RmEfn0?F^V&q z$D;vv_jsENv3_Ef_>jqK4Nf-CU238qbAjIM5Yu^6Dd zVT{3(-Kid!08JArujCM)c&r;uMPX0uz_DUO6kR^4NqHGEj>b6; zo@={6>NN*t3Dy*Tg&`eTy2We2O#{1$G6mHPO&KZda+#F{Z*&0a* z>6!Iu+S7RgpfX?P$q{EnM|#pLsJe#aK|?i~C}cGbRoJ0Dk=1s$+xIIWv`VXSM;Im1Xc1#2i3aQEIF)%OU;Vzkh1SYN0C4` z4hezbeoa0&B(~-Yw3pcg_VX&SZI<-_`Q{F3hpJiD4WRzo69|%2lSinNxst>wu10#x z5J8~^u5Wy{wkpp%h7)=e=+>w1Bj;0oqZ)5V$@i-R0a`kyIYcr_#Vue;M{iv2zMh`v zCuwT5d5qE!crQvu>^3cv+d{6U^pLx8jd8g0Xd3#f5ZoD@}M7a75Zjb8XqB1x4 zk!{28c$Y8zHHrnSx~g0yZYwM*dZEdgk~Y-2->D;n-+enCy_WGsbgr=08cwmQ$&M%* zeSD#gFQGP&^sC!ERIamda$y#*#6f3i_Xc_h9-T~_+iM9C?{`A(rMR6sTu5)kED`*%9@5|@MbXxIl&l-l_Or|@N!&*`jQdy844FYEG}^8)w02(3ZuPzwS#E^q9{iy0}!Lu?@UNQd9ay*xC1O7+sp9j z=#9=SmbbeL2U^kxxS*2n_Ht61Om|;R5N8iF7(GN)u6JiVwjP+uPKvpOG1OKYDR)p? z>(8IcIE4%f_O7Sn+_E*aqUXo7EqMYe>SJD7yhV_Z+#z<3u_JghtY9!0^6Ln>6@V}R z^3V;)(fOgvlHiu*^s}cm?0iSVP#2*uJX*2uaA%b13mJ}87W_R^RR$v zhKW8vU3Y0?WqoU9Z8areEJcy5MHkfj>$=Ak3~ql97Hej8pUz2QPhI)O!SWU!O0Mz| z@eP41i}zX>9kn&fTit$^FQ{jrR$2i&520ry$4gv%^sLTu#x%0FIr#MUV0CFQTwHxo zm3MQHD=&)z%%$DBf4d>VRpr);^*XcLrXgja+p8-$Q`lU5))2A1wd6{nxB!hL&sR2A zps)sZ=R<_&sPw@v>eQ%hT+G{8*?JKiL_>R4X*0po!HW_zkxO@eHd(KR7sB9W>6Iml zk%}BHLN9riAS7LZTzPM02{RLWC$9`N`h7%K4G!2V;_V1d3Dm}TcZ~OuH)yIThnfj1 zqV6*Yx4M>Ba4@~TW^=Lpgk4CKo|d2B1s6OZr-3UQ7zfriUewwK>-A@gFSc;QN2;ty z^r31prED&HZ=zKQIri4bVxCF3G-j(zY%WHpZy)N&$WG$fb`b>(;eBSf)Y=;?p>URR zu(bYkofNIC!NeAr7Tj%UpwDodcZJjH87w(k$iSMBuYR z7Xq(rZf*}Y@UGd$%Ay)Q2?>3!u3*zkX%)ZEYz%y2r%nJ0;+OisJ0|tY{^5WK_%ymZK_EZb*GFy5wSbDm-{eG1Q zL%k~maA>9?r`co4)(z)sYXu4FOl>{gvKd13^3A2ibv&|!IzhFC`9_M$6r1Z$7xSu@ zbS5z?ZW1zIDFg?W*%-X1faA02?&yR=@=N&I5`s7KKudu!D-4gadF4;};RFN@5fSSY z8_#ruutPPSJj;nH2-7Za*@wb6?zR7lEv|Hadp`lBLfL$41x-8q>q{at4 zvSQe^O(QU*L?}orOODnah!c_|WK{;&o~%go|XR7f*c52Lae%zDBN@mTgDTK|bh#5igY-$Wfmm0XC7SVw>_I!3E$_P^v z8Lq2>!R~0KF{&Fe%B~AC5EBey2vh~2JG(Wo>T=A+G|dF_3rp?OD{S3vBOhKnRawE@ zSi#`CT){k1MWNZ;eJYb@6P=;cH!3D zPTD)S9^^$<6e~C*dmYaAZ{M|97HJ>e{#54t3RYl#U|GIaavst-}l|6Q8I;#^kw0A$D8#RM@x!s>&u#DVkPN1p8|x+g?|mtSUzr&Vk|dF~=U))*RK z#u&;#-xwNDl`%Aeqxn@TvgAVPfgXnyE}w#?VNe%zZ|+WXX)- zEGhxg#2LA0V<-VDV`u<+#?XkVjG+;phizFNW$-k4S2&&fZ1>c>Qc){L31PT6#!${| zZ46Cd*BF|Rv@5s9P{uWlp@fx2PgxuZS1rG73?+8O>?xTQs5BQAdSeV#2w@MgaF>}i zhUP@Z7%JgnO_{-!F*IYeF|>fSF_hrhpvkNBG_6R@WC~>rRcV3A#!!Wzb*SQHjiF5K z7()rpmb}UsnlU{7W?O~=Yh!3ZNn>b+YGY^yV^J-491<>#p#pA6h8C1Hh6;=|hBC?;LkU4MQ9GL3`gG&E5e2$m*ud@)(%<025SwuOn;Ffw-9MVF2j{Iqd+PJ2a}@Fsk_ke zP3_D&(_4Lb3qUfv<^-~?6vAdyBXxcW*OHXr9>0vM*hxb!l@JmVa6r z^{i=80;4nJ7;=ffGUR4}p08lvw1!-w1lTd;))=cbozB!YkiuFPnHiIqfa)@G;$q0n zblQ+B!Bu+4kQ?cfSyr|-2uxt7lo_R^)P`J=U>8wr+*5|!L}d)Q1#Atu1yk&`8OAF? zVaU}8X~-=Yj61UQoJH(SJ(#j>77p0Rng*Mgn0CP6%8;8GWsKSqa3X2Q&GZD+hTM#j zhTHS<>0gv{c!IJa^I{ zR>0F>-1F>l6>7L8eE<&@B0*(NjBwvrb`}I$1KXRnk?~Dq+0f$WV(-UW&ShI>~g z7~@>b2ylH-gkkQ@fPgunXU2=#NhWy&$7>_f#hvL17jH;N+#!Ok!|nKNoGOX{lhNU! z{l+Ei{Ma;TSyQx5SK#fi!N-^!=^dE3MhMULYz-WFB@qD%BDO&LUfgJaoPj7 z6oOS0$mWE<4J+6QFSiYZ+=3#Qc4RDp{5f!F`nZh zDX#6OtR|2MZx%sX-wB9&kt5+h9>KK?iXU%eAlyoJijV0|CfUm`LFD_>5hkBW!+8$J zQ&`09g+^PnBu1f1^1R3s)1k=}O;$y^Pn4El=O3g6Y>@z^R z*%PqDp2C-`ocIaXb-`423lQjPBEWPwMO^)IRR}OqKjCY5d|vt=fyxy%e2HoaU#eLV z=)63;gHKe1$RJe<#h=(eKhF0Mi0IY9z9JLB|A9U~wgl>RB~W}cKFu%H<8mG@mK~fR zuv_l$3{rN4auX!P8|!i|~pb)k|l)9{C*$&zA}nwZ2ZMP#Ed*MM8xzR|pl(E)guUrTNmP zRSI)eP~p@iL4{G*13gT<7^qRzmB1P;E(1Eqw^rrxc3`;xs1i}94YNrFR+s)X77^T! zU(z9dy6)FNJDklGKjiN4-COYwSy$f{erJF8{=?D2!-qTfZ|y$Zq1MIpclP%d9zGa7 zxPRyV{@pwGDV$S+-?@AD_8pkc_aA&}pRT<{_&BlV{{_C^fev0_a!61#XZPy7b~bZO9VZ{(om!-2u&4Ipv-!1M?CpLz2%xebQ#eHHVaq5clL6NZ(owfc+{>LRAT zf=OTE@}<0XSzow}ka*P+U*eJ_eUa!)D1;FyxX zlS@hl;J_f9>`F**LlKbdfTCc*^+bW_5KjSuyNLh^N0SVdE+z$7oJ$0(xRo%lIF!(* za3zVK(TOB{3HK2OM8}cxJGzVrKyelk!0aX>V0nNQt|18xr;z+J-;FDf>`*8Khr3Lqw?ZJKv)2j`#=pV<C0wVwSY{d zG92HA64}j*Pfox`>p2U$^vr0C`1N!Ei-BkpVC*Akyv#g74Pc;oMtq53Re z9619U;Yf?2|wwlx3VSFEhK2Z>Ub;UCu5Z=3^R>S#rS_F$5V7K{RS`803 z(rS3Pi&n$KEwmaQ?w{50aP#ctN9o0(mmiTTs1jd(#4&iGobY=xg&GNnAHxD0!lM52 zBN$N-h>U+tPR599`|_jl1RBM^5Pa?BM{GzX2r_}=GX77B{%Eql&#f!{B0CFyM>h07 zK!V|va3|-11O77yv>&wcmmi&u-||`b%a3q)fWztVKct3;w5xmh(b<@eOT+(wKF5pI zfoVM7;Yixa(SbkU^l-$%q4_JE+w#wJX3HPpq?~_F@i5Bnt9LkJ_b@d?bG?r*+&LHA z@xh>pqlGF$g|BS+;!kV&3P54`ihykS(%;eY z#X!9{uRvijSA%KxPtdgJ&X8<1iWF+?Y+!;>xO^7zX^f;#VfhN5+VT})!txa%V%K3I zrCgQeE0C%(7|WNU;3XhK)YUPDNXu6O7|T}zYs(iy9m^NNrJXCNTtYSj$g_M=;$rCv zbmcpkuL@1Jd?^rHzAVHfEtaoLm@Qut!j`WL5SFhDOO~$!NR}^xv@Bl=7cE~F2FsTM z(Q-F}isg$bl;w*c*7B8M$?~ND$?{cz!Sa>AljSP|ux<~QF9`{jF9FGxF9i#hF9o7K zrve1amjDUNSB6T5Q`*O&@X8hqI}Rg5&{>QW*V#xq7X5|&ZbaLj|Gh36|ujwHUnq$FwETB$?VB9}Sp zR5~jr#{yYdh6wg4P@pM5oSBkvLf7sJP&yEpiDcEpizq^h61zMNZS?f-8$0(L{?}{+UKc zn8b=jjYBOM&t*$9YW_ zxlEF+Z-P^X#ibIb3>LYZPFmzLFj(Zur)ZAMBUg6%vKdw_AQPo}h=6$UC5vH;T>fH< zT>jFfPmI*nmV*UzsU=@Y(L39CAEf}(MV3r2wyW;tm4gLyZRKFWxv)Y&xn8A;(GaQ@ zn6~iX9sk4AJ8ba@AHf>K*Fw}A1OcL*Z5gJntOQ89tioT$2Q|Rb1r`2+!3HKbeq|%L zU}mVg0dQ~}ZK3hUqY=gG7awc^72jk9h1oMgg0VDyNYcl}oEfpnd@4Q*pZ7qiV_{rB0=)btDqdvm`m_XtZ4ol@^0$8Za zogAbsw{h?h@8P6hIZ3{ILq=eF1ppH07kU20pSh3(kHw*%!Qnp=o#H{cQ!;dN>bIjq zRO-=axcOx9HeQPu!Dtx2s4?V^?Pz2MjxPfwYcmrB$mwJf=y#4LZ^p0&Vj~Z7JctT$ zc$@J6HdFBptNy_;9CZcg{A~aBeY_?4a(s+SJBPR~VbKpO96!xG#k~b`bR*rNWW+Lb zZT!kM?U)a=7F^0;1l@H}1qljFpkX$L67`38PXlhVCotAR^%gQb8Y6yE1^w*#gzvQ! zM5vbXP438ixuSreEoPMj?eD$`fPFSNgOHfOiXZh&UmxLG*uh7k>@O2N*}~(g05ha- zHrv8A7DDF|Fk{Px)q2rH8nna;PosMvxVZq_HON8U0Ih{9j z{*Z;Npo3%N@qo@YP_IX11_#H(!v*l+pGTwD!0aMQI^Oq|FXVs>wLxB;Sw(mtYp( z3sVu$xYm@k%0)hT1N$U9W5fHtKz2v)7cKcO=NjHwxWke&;BFYWsr}FdL`^F`*@rSxg~?%OdT?}tQC;>v z^kLOM@lD;Cg;2>$>*X&|G4!44gnpByM3s`y|LO#^rs(%)Tp zSa`+hRe<3`o;P;)Hb4rTI%`hicC+1!EjGH1JXismP$1Z<$VbC8Y%LV$PQk zP>zW6W9sWw!G+^MBhQM$VT^ejt8Cb3xI?Ra66$agCa($+XZ8Rm#pJbPs6^QWE&9|V zX`S~jJsFVdl~NE8+rI?DiGCPbWMaOUI{sk1drqrEKJ{08_?cG`zV>MJ0k4VQ@**S- zo;)DOrRLeIz2VV^JX8#^U?TSmWI;l4%l(uH!bMnx3ceZwg#MC;!^k5H!$;Ib66Ey( zRzH#-muepl0N8G1`2vUnVTGPp1jHdOP2-w#aF^g7NbDI$%H)GIEVa%?afP6;LAs0P zsRr{r<%HUIPR9t`LI!7A&rDCSx1lz~1lUmUE%9N<&ya2<0QVs#o(bjq!=#uzZZhNy z_xcHg-Nt#Krw;<+8t~cagjTABFb?<N$mOdNO)T-LgPF zqzCE(BwU;Y4z40cQ(C# zG*64+sYjsDnJ_2PmFv@YZzGO#U?rfImqZ0-3%5kFG7s@EQF0vj-aF?9Saj3oG)fAS z4}}XDo*bUPJUEt_3&;RR&7^vuo8pmQ#5tI}c#Lebo_HA{Ge(X*RQ*MjOfsAv;(bZ9 zI+{pWj|SXNMElOuGb_geLmkp=93=2}rSkv{X-he{v4mG{cuQH7DlpT-(exEh7%YG~ zC0g0|wNUfkc<20O$tXRz4P^tyBV!X`b7|7W^5^W1k9Nj;d*i)#b92GQwJ=AkKc1-1 zNf^C3+v8BoxU}E_oZ(^Y;wywDtpKK>I_E;*M0X0%U=gXn=y{emK(_RO1tCl|h5L>C zO0!_Y?^JRbJX*qd^a+*=47F6WEZ zT!1vEvsMVi^Af+DrrGi;-{BkgSGB;1s0$nsDf23qQ@o@)7J~uhh+gInn-s0MxUC&x zRdjB2s!+ot(Nr;vV~b8Nwqh-XOk?GqN>845RmaigqT#b-g1&|)h`(~aGyM?zZ(0Vk z9)k@OyVgSc`T)%}HwyZ)9fM(^Pn3Sk%g?=?X-S$OHhG4-EVy$`MeQ?rfV!L_Dl*Fx z9w$Rn*oDn-EYzyuF2|h8c6?6D=4V^X0Cc%UR8`msz2(gFW2%h90vf(~w@kuEldw#J zaZ42B7=~5YU(-fcPoIe;+q8HT3PWM3=48?W1Kp4b!SMjHJvlTLatDoTP01w#ZQ%vI z)gyxXVCRlylPnHkdPPJbT>7PpVLa}Nbxs6{_7fp_=s1DNpcH_MQpHT9YQF zq9esg2k~xVB(k6**~QRj({`AbhqT1u4M6E3VL!kNmC}&{&^8xdGRyr#DME#^<*5lw z;XshL8}HKP@lYBGc6jC_v3lt_5|PkM@EREuQ3}nXTy+Rc)QRAP*>3u(=<{^UfI6=M zTRlP;#CQr+nw=M0;R*KG6JN9+Pn z2wvf+r%=#%q6mWBAg^Ym5)7&?gC(eyg5xwX^QPma)WWIy6+XdHV<~6W2FhaCsVJ2S(vlpWw^h{ zVw70PnEVM$-7lagiTCnH3n9JeVS&No=BX-Rk}b~UCR)^Nl_W!(*VGa&WKImfRLeXI z8X0+JtZF`Byi$h#nN5V2BWV)#0#+Lkcx!a;^}0lr5Q9qMPD{rF2w*R|Sf|Q{UUs>2X-4;siu;_hlAnU4DTx zlFnXXp|wXxZe{L{Fu6HQAlhB#eSQSe0eAtPA0K>xgYB|vE-@fW8LFbu9-LxyzQZT; z6#dE^>C^5c8itd*i{0adw6q_OcGtYs$;ZnC3Fq+{R0Xx=NOvlntqf!aWL);?t(zAu?_J3hp5|5N$`J zwMgZKmXIm}ZQ1dhPL77RDInlO*oe-^3du(x3%3H=uN+B3TF*2??eK6jpVb2f^K}6dwx7rg%;ms9#p$K_Tfe;=h{g zC2dFb){3QtrJJ{DTm6CNUm><}{u!bg(`HCLe{vgPl{{jxRni1gt$NWa!^;;v7vp?+o2g$2MkhAd`;0n>C0lON69^I|Q3q zaNfE*=5^0UgK$fmuYvO!+($GvQCQ=Tc0(P1gc2R@<7a$A{oTHI@AmC`_YtR5fj@C8e%^j~Ya#sn z`Cl3jsl(~l*Ww`ho0sXN=9}SJLdym0dcStE^DXbR$-+50`=eZnGB`eTNk2M2J2>o8 z#Om(S;DYUV+NFTa`cgy`8sZ{GG>l(FLmp>cnwKB(n0EmU4Tu+zphaCk!P8Th1_R-R z1?RYqT`o9O#wvf>uZS3)w9AM)8=B;sE)_X7!j90TLDN2%TtuOcgD)c9JDZFyq6uT$ z#Z=g3P|Wn*izvxlPu778=tB3TA@~A93hjIQBAVbBdl6MKn_omn`{RpfF4cZeqddx9 z#0+!CMI^KUxrm0=+859SwO`Z?k#Ee2m?tjamKG%!kjXk=%yu|9TODE56x`gnMp(P^Iq?z|?_YMzfLcM+O?!v=c_wOt`@MqC`cN6^Q zf9X5#{K${I^Ukx+dGJkt@0)(gJMX;n6+ikNfB7JVydys@B{9z0pZJ89_z6h-lb`QM z+*Bge$ED=m_DlGaA@7fR@|1*kzI5jDbu{|LNuwdo$;#F+1_qHrl>Ez-@a{vugkOOY z{y{3CUXjixt5JLZ0%ZMLpGUIdTORXC$!k8{M*c-eIsd{SC9La}n3?P9?mb^~{}SYU zZ!AsPOUx;$qqpyhCF1Ri5+gq@)e<^-`!%sVVY?(be~dPs7U8B3|0L+`-%N6_SIRHN zC~@-RQl)D2;2#HRZnJbfIRJ)9FM1(U*soP~L5m+-KL{y~g(7 z;t&6GLSlLkP#&^KVX7g`EBWtvl4aBgnc<;;XB_zmYCcJw{;@|R zr8@djqGq3;JEQW?r9DrQg(J5)C3W=oOJu1i~|9!3v}!={tlD`Gjmf{WV5p zTDg6aCGo4U)pAq{y;MDQ+TVZ2x+|~GO5Pu1j_J&4zm?|f%3)wmd7bwD(@BHYV?l|N zAD7Z&XZQVQXqAvXGbHEPwb-*-{1RGWaX^&t{P3KTI&;V`&XVvfGlyQ8Q&vZNzevhb z4|V>{*Y$vmsRpQ6HC**jO`u0_FS;DUn>voMtJDdl`8>+v>Mh@>Fru$E9R7Mn|%9 zeOr<>zwMzjt9)yeawRizqo&AG{85y11+#Idk9`=Wa1<+!T_tP(V~iY~5$XdeOV#|x zkkhH5w@D7~*0ms6y34e;dyRSjt58F4NRAt0O-h-)Y(1IhN@jD*HT&+Q(?-s+%y`F1 zt8`{r_Zn^FUxrSnMV5+@H=joDc1m}eCC07uyrpZ5P-K(%Y>~CQ11DIH)iut`HOlw+M4Y)*Nd zws>IVeR}Q|(ktDoO4|Ib@dD_J2_yB0Td z$r^SB@-^Di(&%Lo$zFY2MvFb`!mg4fB8AT-vA5gbsU)fbsgHR}xAD)$(VxSSi&*J% zm9Dop8L84`iK__G_0gu@2K+gDtXsCs{9*P-kdep>j~ei zWzmBH^VM5tm-lsHj}TWT{DuKPSfB*XylUvp2Y>yGWZ%oLCMbdO<1&4{Hy><~B{)AO zu!uJsB=?We=Q`T_CRKBb`OSzqC3brG&r>5AKVvbcKkwa7`5ts%i5ch{b@`q>UfY;c zn|B-9Bu~^AQrf(7I;HxvCNBh%hL=<1GbM9M?Cj-!mM5_q zo~8WD^ts+y_m6iZ>I$4$T1TTV$fG1`R6ZFaWz62sd;Q?Iit=p?@QRJy(#<|%cKY~< zC?89kyY6~>)$cQ9o3Gw_^W1-+$~FJ4r&nWNWMow;oVmt&r^KJs(zFU^meli(`>~?7 z#N+B!gOq*YQoXxjWB4RSu;12@IloSOE9f8ROPyD@oqqSv3yJyNEU8E(`!ZVX^}E|? z7UI{t@MPC~k{a^?`L=wGk~E*3-b!yVt-QoLW_F;Ig}jUgdoASq(#lfEo4-x=MwQ=I zOVsL|y{~uXxu274mRvqOyUMRjn&sZ?5*sarP7uCFN?cnUth*v-t;1d~*r(eDG?!Bu z@%E`!=d6-?7LNZutu7%cKlC^MxY;@L{mrh#`CDku+V>exrdI0gEv8e(Z;n}@@8(Oy>WXpYcrQnt8;c~9lPy!r!g(Q#<3ry8xk}xtne;p?n-j|!Ry-(t7(4b^7Y2*AJ(#}E-35qGHvC4!|wjCpjtXyVHT@lVmLjQQYNXe_uT|5(peK2LO*eYY zC(*jTttENx^7iWYTU%1+E^DtR{lbRS6};1Qz4iNxdXncZbMI_qBd>$drXS2-%AWV> z-$>S!b(V#4QQVC2Xzsh~ot4+8b@}GjWv|t)YguqnSse~mpAVj`tqpasnRR-%v0EXF?qelSb$0b}nby)< z+5SYi^18iHO&GJb%w7-t2}V{mc+afCo(Tj|&azF13BC7FHq+AG(2mh|Z9@_P$x71!csE>~ks zOgqV+RHO|YQ8Ty7UVr;g$hwkpb=FFMG41Epww??&$m4H59rkSRfB&C}yYaOp9G-8k ztUi7=pp)%6C3fbyzhNXkUR~VU-Y`X+x$b&p{9MHQV~ay5<6z_Y$`TfXOLLa7(c``f zE%WPD8Kd9wRoHSmGwVmHlvIantD8oxv-ZATU*9lg++3gcq_k%VA5^7VUff!ovj#h@ z^mkP99=+Ham_d5>R@zyq{AMHZ)7$f}RC;@dpKRq_Mf>cW;s07CZ*3LB%%|t8zuubV z4=8EyxwVaR_PXn=AihWS1u{_w@2C07*Xw=%q>^Y0ICEd`^oHNAwE1Xpb7iTXBxcuW zr#HNp*3qluv+(vS4u`cmXO`ES-~U3I-&fbRFgtA6P3Fwn?2Ob;l1~y&)i;+G*9Sv# ze%FP&N_m5<%Or1e{pre_@;a?$*^{?urrViouV*p*uhTh3)+iqnZ4NMqt}dBLaAwK9 zQS=8=KYY6J=-zPa>DHsQWpf#1c6psq^bcuyD@#x3_RQ$i&%oX(c-dg5Mv_?tdy!veHsy~Un z%LnOnfNY=G4-S`CHn)cBYq()OuhdS@_`PWa*KfMWic``rV-x9(+rQJ3rzCs~%ScD7 ze?7Gt_F7mTEc4kgpSaH}wbTC}r@9=#N0H7!s6J_GoL6SYr{G7V%xFKq65DxaR{XNG zqM~y0)IaxXxHH0ibFRzf71*7&UR=eT*pYXhZiWq(h7HH1D;-fkrzyP0fFp1IUe{Zv{q9<#uDC1hbB{zTX}BWK zF0V6=ElPRWS+_cPoLy$4b$&Hk=exelsv2i*H=UK}&vj+$ikw+q$9DK7$#1Z%vxoJ9 zVpfU0cKQXiL|weu>#(ynTg)TO%I5mBMOe{4W0s$@maR9x|J))C-YHva8!xW=-Jz%H zX3p}H53XdiZtNoH#PjFmw)w;pHG92v+U4h@Rzd+QO4~F?AT!rpXI4K+JBOwBHz~~S z6?vsK#uu9XzB}F7j}mn^n7M3?nxkFy_en_`A#KAIpe zCiMD6SS;pktsUL|V3J8Dr?rihtrxVVpLgHci$M3IlXq&7$j;@s5sQ8Ae0AEJFMf6! zb@<(n@Q}Bxy{m1r|4!P=2WgFAK+3;Vo9*BpRJ^B zZ@u@>6FGA^JG;W4rRs5eYl&ZRmJ&WjO*W!={515+Uze=Utk><;mFEK-;yv?;CO4(PYm`I!-e(*Wl)0 z3!bp^o^JKL;J;4Q9OUUiZRS?e^L|}1WeZ1zbpdCt!A_4D=MkJ*3!SHJEneAJ(`h-M zQhLpDuTi@XmBcH2E2^{8c%WrI`g&{tbP;E*%U;j_c2$?F+s{nU%~@sj`r&<5va5-8 z+q0eA)AAPYUCl_-nSIY&n_IJ;RosW+Uiof#h3|^Sf{tF_D0z>rO0OLY+z*7Ad1si-n)RbQGmoyF zw)%Urykgd@OpG)4j$Uk)e>Y2f{`3mU)|nG;hh8xXt;OqvGi$OV?Us_Zb_FwVZ%q3c zO4{}Jgx?Xyw5ZD~8?`$l%ufv~en`CP5vI4Y`Jbqquf`t?&)5WaaQsqF6f?J&P6>Y} zovXdX1KOwiyLav_+^4rUkH*7?w?DO@h0fgndL#Gm@ul9sefRD)O8tGl)VsGnb^jWr z{$5||om&sCQ^WtGFLmM8-G|p$*6;JB-oAHdZVh*=kH23?T|jNdHvHheDe6`Bo8Rrr zynSn7-WJ@Ox4wu*+&#R;%h9^$^_u8e0=`g5x`NrbF$U48$`>eE*ZX?H=POy28^P?O zTxX^Dc}mvxzn<{9M&A5!M0>OU=Ty?>ZzVndg?B1>^@W*Pdw8!0{K)6ZzIFvZpPhBv z4=Y(-2&tJ%*16yKPqno9J-j=+mw%#U(YZQ8L2PXpBj#0>?*FSK>IrXFS-sQlZ93n} z<8cm%HRoAS&ocCnRq3)sUBuZ(u}<6kM@r&#zn<_9D{0p|s{DgW-t~?uf8WZRv*vpH zh`*<0pj{5Hm+zWiPxybOG~ESeuC?Ad{hy~3WojWe@_ND_CmR+?yRp|3 z{+1`P8lGqEbG=)(-|k4%6*#lBPOp1Ko)1x@H}iVJzb4AZ?-|%F-OTN?r_JxQ(&nza z-d^?37-{p>TW_BGr%KZNyPjSjAB#4EJwa_ep1H<)uP6K@ElsO%W=Xx%_;n%are06@ zdQopuX4NcbFKMTje~&M9Ufp(9&^ton^}n95kY=H4e?8%Al_agenaAbMdDMTAR$ded z{|0U@d_h`S3VHLl$=;~)PwEnCbzW%?_&V~Krg@IbcN4EC{7NbDMqW>NMW?2zjMw^l z!f#J@DQL4CnA(Ya=Kj#R3G&~#66bHBJ!{|JPHSjc%6Z#pr;L9~$}7jhR;{!5i_SU1 z|KrQ76gzWWcE+~9>B`iKomF0Mt@JmNyxdghlhw1>{<1WVihGx~0%t8-&o=f;9eGvd z&D>&odTI@x9{s%qDbC#pSvB4BefiEj){)fC)Ht)2du4swk~+7Bdp7gGmgh%~9X@wE>aA@4Z!K%? za`m+Ne`#4a6yg4_)>5xM!u=09GOshj{SRt+R~F&EHv;_?E%OFr&i`dC`37Rn|DRUk z4aA)POO?#)jXD2+XnEHjbN+u<^5&a4dL!Id%K7S=W6pntkyQ<+v(HW)o9vexY1bcf z{zn^$*B^8K3ys9Gk?!&i`st#_Nqa|L;|$ zyWYs6Ka^}<+%HI**Bx{IGe)1+9drI^vPQ)ce)=jbG@ZF&UCF!dnDgJSw0Yez=l`Z^ zEo9ic?wIp;RDa+AFJ>z?vz?-|Ci_dOd^Ztu{x7C=^bN(F|A92W-$2ayt>gocBcxw% z%=sV4y1bc~^Z%PC?^9tzJ~jzCY@m@cs#<&+Csl|KnBpV*K|jh>+epRr^t@j8W#id(Mtd zzrB)ISK?L9h38t{4aA)Pidy2l`fS|5`y|d^|A#a?-Du4D?@J^24aJ=QU7oya)aq%f z!yAn`znMHaZ!qTkZ%FNjWZqEB`Cli?8P3(`T@82ca{h3x%bSTg|LfCznjDk;3L^b> zM$~Vu}rXe=6;J zucTBx55Rwv{F-kl=KR+rE4q+3f3NHL$$f4u@f!Qw|0-HZ!+~@5KHeF}{=AfzT^z4q zChB-~{W)J|RgE)`*PYq#&$=>oMb0d*b1VMKlFw6#>wV2J=f9|ysEapyyXn|{ALS9| zCSuONTcq7k%=xu+pWy~#&i|R*Hm^VC{O6}ua-}ind$$C?CEYu|_6YF5NJ_e~2=L!4 zrQS#c_&=I@10N9FR0R0{JngNoIs$y>gyL7Exp(pWY*N=HXW#Xq7X-b{@9|3%BZf(W}ktI&seg+o36dSl%GVO27B0G++|I_>3u z*79y3#{CzjlTjXNZYsw8f2Kz7n~QP(-zvFR7A?7Bf&N3PMz24{{jw_IO~knWgSv!Q z6^p&IPW`UD{=f1F)Qypq-evoZG;i&`8t=Xy?v3}yr+N^dbsg1xWwwiRp#Pt@ z^9+yksQNx72{p8kPQd9sv1D6L2=E|FvMp>&idJ@P0=Zf3uB44uyPMsWOMr*oJ0Xw& zA(SNa5<>62KJ*rP38B}}`+Lsa_MZ0VJ=e_UgRV>8etYViIdkrrI3@>uWBERX7AVJo z{o;zk3w3ut`r__k924`+sJk*B?QM0cUDb5r431cz;AmjhC7pq@KAN(YR~kWBXqx3C z1y;FQ4Z=gWJbgIj)#&}oX4Usra8yq$@d`*5tFE-8gr>TOG_sL*d?=NwTHg~!gN`i8 zH%Q+-_4-iOLOac^JnJyeHwdiEH|muwwf*KLU}8Ojo#sajo}bOo8SCvh@5i$B4||M* z7kLhGya03zS?({nbU9HKPfi2t+KY2qkas^Ea-B?a4Rar)+-(j;U3y%hvec?qYV>cT zR_V30Q`$cef1Qbv8aqPmSZ z0)f|T&Lt!g)heDO5bM9`lbV&NTi#RiW1&@Ui^A&AL%6Muh7)@xT6=z|@aoNa&rdeQ zx?W)|bZVMlV($QJ&mVGDwG}m5mEEdXavcIsJS_KlVwJ1&DoQF9TIG5?`w~Z2rPb{A zqK#y*?vfu5b^phB1&?{WhSxeB|11f1svqRqB&Kbu^-BBL*j~8T|$(hmdar#!S6itn(IJpKvW;~mxzse+6&QoDx-v{2Y zkE-U$1s#=2J-O z<1K7zd9{{lYh3e`c^%lJ9%M#xC*c}SE%z+IeS;ZEm#mOiS9W(-mQ@prxhPxz&g8bk zWowi>)|#4bwR?5iL#X14V+nZGJjAn#5cX!zP8;IhP0@e6cArg;3O`62vopN05b0YP}ont(ABCR{-n4{QDuMo)<#YJLrDMcbd$! z$XcU@kT_!?>N}iN-}4BRE$(dE)ml(WqZZxW_<5_O(OxR5d~0?`m*_-_n|)SEBd&2g ztvceMo=wz`S!Au&)_}Rfzv1i`2}ogycKo_e_%iwJv_RoeRiX7n12CIer7utj255J|ZxTiXZ{Z@R2+ReFj% z?yaP|6aQV&TF0LIaFX&ntlNifou1kh>4!1$tl-GP#}nu6tWCb|XwRDXsrlMIIwx$c zG`+h)1j> zDj`~{udp#GL<~ojOX{ddxek7TgKD^{oC@;!vn*8AS;d+Kd*loGo4>v_S4Y)yuS}m$ znW`029ohU?((H>0GNuv2ZlsDS*D8?n^#vlu$WRo!Ey>x_gGDSSpuWaMH5@l2^;Isa z;kaU|V->p}+4OQ7)zhLQj!OCr;=LxzdeNR*r@lbzWv$aoPUEd@_>i)`+Q#;j70nM_ zr}0!&NXeecGu)gHqF!f(W+^I-TG=};f!AD{OGYPTF_&H{RmGF%0l-_}^YTQ#`f`ot zQZA;o*^`H+doJgxYK5o5#I^$+{8#Y4CuVh5+U-`SSEK2aeZ5+Vj)>?=i@}R8RrE%1*5;w^gXvwqRfKeBS>gwyiHV z%e|FOEo#%rvQ}1#?TYTAI+t&b(3sT~Unx!Nu!>Y z0~zNPeGVOp(^?fE8quEa5AtiAmnqEl%DizrD)kmL zt9+G0YqokDY771|sA#J3r8;qRq35knkYQe;@ao;}O05$oa@B3*83x40p1j)N$#a@m z=G})c5A4jJn$@Uum=P~jmhvW~*G%Uta^jy+wZ2Hh%bpUV4Eo~Sit*}TTz@5&4p{Fq zed%~5V*3sB)wJK`wNxUTUbsnRL*F@Fsp`?wVk3^d@aeP;{fVbV<5jlZqHlC)M@l2$ zQKPn}*08lz#PPS@(Q6nc_GX@pHQ4lR#Oi3JOW_~?qI%7D9>S4z_|$8iRr>fB*x_RN z(Y)R&xBRgIRI^L{3$4;mx6185{f|yK_vy?gjec?uZ*@eIK8-qkfz#1UE!Q^i^ryJ_ ziR-KC4$3|qu*;pAcO8u){9>J*1b3|cAZH7X74I~Puix3(vC;Vls45qGxP!ck$WPT{ zE1vuv9PcOj4yje?w(B&GX>O0C@}U!{EAkbhS=+0MCH7oYd47QB5aS%(Xz@5+r$L{} zH8jJ?iH@Doab&p{<&q^t?yH$dsV>pU>D%%;uurrLDyBMCKR!8qX!(pP zUw65cX*7Mrk%;P(7wAkH1SU7-?RBhWKWR}UA?#_EaOTAt@YWjcEjlO4k zelF+Yaxd)&`)L*V?eqFH+V2MJ&45$Phv)jFj1zV9?qRd;-I)a)q35cS2I~kRpM8$P zOn2P$1qwBzsdM66*&;7`wuS8JMUFia&!{|0p%pTqiWFxe^bO^8`3lWm#8WZ!Ac8N? zu~*;|;%6!{hMK}b-(5VzAO@Vl0oB&iZCwBJVL*JEjp%(gjP6%?s!sIv9FTc#(mXYy z@;s_HtG?YL6df%J$pBaZBICPn6xt?c;l zoi_?c6BDzupE=R#>e5<3hG@7sX=zCQ^Dmr0(T<$&oeND78yE5;PEKr{3;kC4~Rz(wg49bF67|gT| z>+jG!>8ReU<^CGGYUHn9)aiO`Zb!O{%~L8g<@A_7$8t<2jt3C$|Jx^pn$LAa-+d^H zK0CJ-?VKatWvWUPO9rZ+N9U3;tFqGJ-gW>c@{bGhQ&s=Y0IIT%?{nhoKH~{BRh8lx zN1fN(YrOVKr`_sm#*-7lUj0#h>%|gg6`e8KAg4Ndg{#OvU)cB0m>Op?tvMj}QNX(} zU;mQJK!{yjyQriD|$mw-+>7t~VpPbhJ}j@bnXhPx80va~dy^ zvAaSa_WItG23Chh_VWuJ>d=92h4+j6Vv47vz>d$#_r`R@T<#9|l;x;AXD2kScl~5T zeU1IOJ_CJs1J;Iz^(Eu)7n1SpRy=R33Mh_vbTW6GN=?V6Y}k;|__Tb#5`U|~?Z5i4 z=ZZAqh>No*8b6+&&Fz?&o!q!9ni-uP-4^xA^VHDb8L_5b_)4Wkr#!E=(|IJ$QsRio zj`ibIlKYMM8NDKROg73?v0tIDH+HyXww769se!ex%5$$FH80l-jq;*)SRkf5R+`gD z=MQ&FK49`DH@RAC_dIXRMDaD}BoBp}F#{Uk4(R-)f|@?Xwgx@J9ZpXhqDwFRt6tPI zj3C=nW}xkh0N1}7MqTlpfE=PSMqi>F<;z~>sW^#yp4Py8Tdn7U0GO#Gt zHdvdlc9N-WU8{8ha^D`HIY{*8x2o8BaM#(wr%uU8qsKvyf5D)?-WDl=fD8bne0w0sXfH@m$w#~l=Y>Wa_&eRb*hnwVcZxo57+oa#wKXLxte zWaOpBviTL~A;i3+g=tyRgEAjvVOo~dpv;@|4qReM)-4^9>h08^%zvBA)j_@{1f9nJ zSeUBIilY)tsC`4DS=&TnouZkDXJ|xPI#lt*G*st*Fz>&Y=B8&S;;fV1w4t@ASkx}sUfex%w(6~hR>$rhh~CKe^`P#mkOL4$hH z`C1-Mm~?!nxvp4Fu#$E({RXIS9eaL$Bjgf|M(Y|qPGz=}#1cC40?(JfKcC-9EXhnt zy1sUF^n#BgV%s7mPtB@Gsf?%}`T}iL8=Kpi)YNn@P`6k1e*FuvzhhzZz9m=%;n=yH zOq%{pUMD5CWw{-PY4S(~XZp`^$m~Dyg(jl!k?$x}X~Wbns6xEVA#aE}0!jQIEp{{e z2D(24c-FsNeSMWp2eU0mLOcxo9{ z$u9`?MHX5k{%(omlpf;SEXU6JOp^O=E;6qXwu3vlZ#(SHwa;G>eSp^fi-Vg@p!-+4 zD3ATwMGvrAATN8ar2>lgXUWGPzWN3$#!D?#Ure?vkm5ZB;4WxAt2C;`#KlI;zfw5(mS{<$0*IVj@0G$xfhi+Qxgh1yC4(idgW-RxqlbZ&7LVLgbRIx;? zL7vby6si2}hC2Db&DVk1i5=5hCdT7_Lvm3|h^P11`(;M- zP1f#Q%NadDCGA*$_|B$TLt0-SLUqMTo&hrHk{U9^?H8!7xY*EY#tm^+jP3}mJIUd0 z!$8w^ONj4%D+VGjBC_}G80b`C!9`ZXR$Nn{+l6Ze(?3I^Jh7P9jael5e@l$MTd5lI zg?fnxS+ZhK`CNfMU-7ggst)g-f0LJKmY75F6+PbH%%E@3=L@o)pZ4`tF~zl*qZ7$r zI+hh$`c{OB3mP9I1%Ew1zM{b_@}=^jd9p_+^6@QQs&G;k^3q6UC8sh0Zly5VRb$htM4RKRET1U<=)C}Y~anCJ%gCn9l*R-~(*shN0Po161dZ4iLX|SW=>e>eVDZ zIZ{-WifxE8>;;O10rmr+Z*YIbezs>g#NOiQ7avdhe6`}8;a)gIJ%jhlx(QU4X1Qu9S*u+1D!8jdxqYUXw)JYusET$%mBp6>hGP z6?igE_&4m(!S zQ)pd#xm8ZSaB;9-$9}@a)m1F_U9h^GYtu2EbPrb6Z`))I^X(L-F{RhP8O8&LL%=QgiCU$W%$a-imr#fPkPsrx-9N(v^LW=DO zXeFIyG)km2)B)O?pZ=w?`LCA1eh1{!2Put~lEK?=R@W#|J?#h9=ks-1hCwVyx!kL0S4qjqU?ymrE^$ugIwX03+Am&^+|SqLu2=U3ym8u* zX}R{=s>{uuMRsmdv!>_SNky@Ox`-MPH*`#WciK?53y%KeoHmbCE+sqel+Kv#U{)xB~ZmxHC31#welN-Mh zV-;AgX-Ca{WNgGr{vqqARiE2(vn509$E5Y>>QHsCLbAFR@1*=(hd zSVBjafN%HzAC+kwV@O$O2m2t6WqBq+?k|q~%I884)OhJ*38u@4sb~dxfJ!wU6_9Ea zWr2Np-y_cI@!R=xwDZOKMKWIs$b-#4=c$&>we6RGkgWGti4#+E zvvD6LvRz><)-pO7Ki5SL@ckLe@#omM-c=Ynr|IU?D{%}ZI`*!`kX6^)WaNrv;8q=R zkwaJ&^h?*-xFJ?kaH_G^#`Ip_(03Gv=N;ODCspXBF?yxImXO6OfkWCeXsuggleW(` zQgTT4FlHM`S;|J!phG!(>-6-N?K4q#X{A?f?bQZQ<+;((%itdMYMtqypByVK&kmoh z)67q=<3LWNM)#XFD{^yV6rEY`vDUFPsKjKHfljuNI0v;t zcf!-_M%sm5QZlM~kF}7EWlSC?pp&~hKmF`mRxh)q5+YApWs%TTWJ|edV*Gv%?qEIX zz7A?2PjXbA$5G@QV7PC>7n9koZ z&SSP@eBdD`g4+7XT-veOtwFxaL+j|-c}`+lx8-}EA)3xSC;uidX3;ltgZ(D&2t|{F z{U+}Yc@HI)janIWQ(}N`@=%`rjcPk$HtE1;dz)%naN!q z6`(pf)X;CE+zlfun9g{Iq2aWeH%AD?(xR&9?EI`U({cJ#U`lI$x=oP?OFL0=&LBcFm`yZKg?Xhp0j zS$wJ2Ye&ubddt&lDC7KC(Ii)}!7>i$0(~<-Wnqmnl~2>F!}S45dYIy$88gUKxTBgp zoucAUE0r21_R?9L>ChT>Zx`FUUyG=RxTr=kDbB5q4h{D)?`5OD)yd=X8reG=&Q$jC@lY77n(G?K*{PMzIsGjoL4e?wZ7o{ zem2-M-(A&WI+&mz*h~Eq+3ju$(HKgQXEhK57buzx_%=AmE(a^}#YgkHI)lo1FQpwQxB%Z&=pxpM){yvpidigK*6tu6olPXsL zEu!50M(e90sln{P1>tc9=c$3rHeZbG@wICfC{8qJeU`AidviD-iAx%s5c=-k}w z{*~s`8=Dvt(B(s z(Xm`ku$~`~?{7!9ZknEr=Tnw__h8^mbZ34FoAXxtX%tns2lcZ)Bd;!gdPLo;12sMRXINyl-yE2|SCjaNe|AN*i}KD~Li6t@A=(brZXqTR z9NC+z*&k(^+_8q91?kWXVPu+4o=-r%{*){Rn8@eY^jWmld=&GLK7U-4ka+&@f1p+2 zvpS80iyG$VpyE{lR5&*&%nHBfYB8di2-bvav$c6x`b^#4%j)ne~afnu$qX#7RC zdnV6e2?Lz5f>W`Bv(6*Y@|!ZdK{_BH!@aWLIh@=q!6?=#Ix|1`pma4PDfuiQiH;R| zU8>`0Nz}Q1MM26wH9$;)U31qeDaT~wy@sG%@N%oH0dfKGqN{C8PkW+w9$%*M=+)t7 zwcLrHM6g}~E%#wit^O>lu@WC1iu~V00De@@I?Y6jzg}DDw3ewF36cF!hr3nqUz#!H zNTp=t{q+{84X!F!m5E`dywGXSOKn6?zeRcIf3tH!vL#Cx*OTT|wsLO;vH7clx8_Vw z8PTfQ)cnQ>4!LxoDtL)zL0+c=+%D~i$75(0@?w+dsZF$3eM#2QNIk~f@JMS{WV^3x zvIVGkK)he6(c=2UFrHLCq|GZVMAdj=8t}~*>9j_z++1m^KzTHP8uGJ+{VK;g*E&g# z>F!psVmZN%=N?*C%c&|-E-CPxww7g>8DL)rh%eNv$wadq5K^y~TZlovUj*6h1t!zi ziVoVzluO4nf8`tIgLw~#lcmDWj^iZb2CyfP_8VH9@Px^&A?^1yn`Ybq(t^69%=1YX zY@VFmIx{`JHL`vFAKe zt%G<3Mdmt%sHOmEjzgR#N8pg3uYw1Gr~Ypy@6zwG{IBZ)=hTs6-tZnr}b*6z9tAlX2I*Q|qoYwDze~GNi@l z6j&j?V?tT#FTCQVa?u5(A?69dTsZYWC8@T@kv171o>70`z9}W~!r1xu(uD)HLH0%$OeS57RP|<}*ML9C zt0zT4K~8d)`ntzW7QScW&MO`0i&v8Bsm? zgo2ENuP2{epoOd_(X{jT`^?qR3awq1qFL-Uj-BsuROx-NZ^PA5uhz{nfS(Of>>pDk zrhyn@ngaRF%ZggHZLs7u0mw9G^|RaRsI}7LSPUT{(&}+Vt(KEXqY%usj+vOl$al7; zO#i(xs<6&ZwMmnN={-DFWy&oGqT=Y(UznNX(h#~tQjQozo?)O96g3d#Qi2s@m%?0V z4PLKrDG+O&POD=@iu0SpM^}-Lo|^h-l~P-$wLi!zjAG*6sf6amnqsLO`*Xg-U~?K1 z>6Zky(n9VjARdm)q{{ZIY4NW*r&vNqUxnZP{cCDBJ~5y>oazg7WkNgzt0Lu60z%1jq(db0-)~BU1Zl9an zN*kJTHEQn-!}v18XnS!M4iqjq!Bqyt)o(Ds|pgw1^SNq0RCcOjt(lvHzdsz zUzVd*JBloK`vQv%r=rCA13muR6-cz#t$E+^2QtfT3oPDy(uFf2c4k12w(b(Khv;8mTf$HKNt~8h2=)s@zSg*kpQ$bWlHfpb1_RFVe$8=JvTSd-ZeOYTE%Iyi(`MowNZC81T zsptmjqixi7t5L5|TK8PB(0Abvv}w52p~Euz7)>>-SY8x0_p@=Et!70tt<-5SFBl(3BRq= zxD*n!k63R9B?M=+L!~+grBofZ-q?wdmHyw$b?7Qd}+X$@S8SS!(~Fy z^ZA2~Odkh&pJ9O<@ihn2{QOaxnb3;9(Pme^*w%8%teETArJY4PiyK^A=QXopx}(2# zD$yV0(lyZo+(rV(bwCbq7YV3~uXkvCaP`D_He#rH!l7gCN&i#VafrPY$QD1 zn4o?+N7t=!y@fPh(AUE!88pWQt@64Mc4L&iX{c7x3?6jj+7wfq4yguF7k|2ASI#h)l-Tdo9qz7*br#*41;Ng zrC3JbGjA$tlVuF%GwAeaxG1HWT*dK^{AE>9LL;q))aBttsnTPQK$!+u@aCd?d?FBM z8|tw}m3hB<0L{zaqbO@eE%*+P&1-E>u~ktoaHmb`0^d_|M-9z8qzzUwEo3wYxVz@t z4MZ|O1(5w;jX-Sg)?YzK;##XmoIyd2 z_)eRjh1wT`J>wH}u76ztqQefy0h4(jyU3;!+UgUfb|~j z$iJ@JlJ~|zViw&^v|g8zsrp5);w*tq;1+E}%jX1ATcR6-TUKVd-k>dgaeV4|x9AC(J;EevM z8qaxjA*X`Q&fhdD*Gx1Cc!{U?0KGo6Ky+-4#S)_Vziz=>jU`M>Liz4z1<82%vL4yW zi6AZ>p%HJ5xaeujLC3`<8ZTg6fa+(t;5BSZDzJTPJdjbxO`3U-7u0j!t7(-FAuNY@ zVkUYi;zt&y^8imwMs>m4E&8<`-bw2M#C(=rTI1MG%0%Cb-N$6AiCnH#uy%Z2qlH;J zP~U2I!H#ChEY&2sN9Fv2Y#bZ@G_*zy7idO1PHr>MOI*^$799tusvw6y#-d&ST!-v=poJJ9=YcA@ znre1znqD_d&K=89vpmp=>(f#xb0#0_2I+>Qm#N?3p!#>hkwyQZ>o>?eB|3$Cq%LQ? z@u}Ce5?#Kw056);nStggM;y_426bBQqciEMt|%_E>U6E?Qn{`TCy4XCgMA#apRQXq zc|clIv6P7R2QM>-wS_X>DHqk6i}j{9m>{<;$oNmt^&IR>1Dzo4*Qu4x{x-GosQ}VrkxtXo*?5sS*MyC8M)U2|2b3V8QU1C|DZdV z&*qzbOFO3~=s}X&UNsoS97iwuaHLjl2GedYku-_;8ByQ~83ikWBK^(08K56g* z+0QXy#P@ov$(fVm0pi@@oqPlIavtYI@{V*g*}AqUQvk0-{bst(gR)m?YpuLL(D^I6 zZhKedI2weA?yS8jCvF%mS)O!|+7V@$pQ@}7_rEyS1fDwmrb^?e zq{C~z=}mPRsf1`^a95UdcEs8w=8zpK_EV(S@2Qf8SS!E^_`{4gR&G?HeX26$askqJ z71D|)3Ege{ErmobLaEejJc&I8WYO;{#7d)HYxew!sK)(~Lfqh~O+>m`A&q*H&>DZy z9eK^&Ho0vgxjHVI*)mpIuL8wZ1AEsO^PBKR-q^O1Ck^bpM!C~cq;WG%#RZMGrM@>zF^Jt(q&m8j_{7TZFZl99oI^||}q1Dk!J+V}dx{JFvf6t@}@Uj}} zM*S`01b9;oRdx3{IMLm@p<%0`q`E_~d?CN#Odi23hpEKTg{Ikt3Ov(XQpwN`{9gqv zS_~$a%8~2iH<X-_#V<154G%tk&(0(w)?n@Qvw~EE zw$nTMEMGf0dJo)>{%g9<4+V){wD`0~vh>9LZT^@tR7A*1Wm~-Cn3x!k#~lJp%s702C)_4;R%>B?X!snO zGm9s%1}EJ_PPC%Lbr@O=xAa++dAn$09;z|Nb6&M(QKOiJx?G!cRwbb2kTy5=iSv~} z+C)=F|KZNlY-u#RiHiFQL(xpB6fG|jj3%(@K1NeO=lle%X+-{DY9^d-% zyFO>J83nf*knp!fvZp4|x!Kpa#$ub%R|90W`3Ak%;D3iWs)9!N1@x3?ee_9eLDb(n z;D7?n`Y@q5w}4aL-{e*+oGXWU1Ipnm$C8)+I-|B%$bO-6H}aZaX~e;=hri5;o%)_~ zuV!DM#I^*r(=T+QRY)lj)fYc65b1sJrsM?!S58-hNxDvrIJ$sm5%+REkMyMul|{fl<1=o1hsYrg zeczYlZfDhabEVO+mg7<_quT$cS=B-F{Z^RRm(Yu^KPk}sJO}MCF3fDVTw88+_DB4s zp&t!taD8Sko{?7A}4~chR?GQ_0Lbl{^E!MKIM6Ug=dDH zmGbh7qHaXF*MPP5u{NS-d6PK9FY)Q+bX7B&md`+P#-bGzS^v@_}f$w@R~&Gl*q# zXp<|KLlv5uJjEQx&X(s}z8`z#*joFzK}gc~GE%GEqs!{Giw&eCG^O#~lr%W4eJ3Fd zhtV4PF5=r6iAFR=)`mIPK(n6T%6QfR4XKq-9sA9kaa{6@}m4Q7a?16lCvF>Q2eJpD{(q2ADrYNRw|wa@bx5wlE7o^kPu zXw)r#Xq<0j5;ZgEI|aI_zt&r7`My_!n6HcLD}@>4rZ04|_qE)9-C9i(E~MqY+UL+W z&H5v9QWDbQ_acb5@A# zfwXsJu01+N^7RQ&+waQb%hrOC<|ov(`!#p%W@e{%?uurnw@%V!ZN?Q%V!uE&&&>wU zyE6f@{jUs~*?5s^6Wx0H^FD8EVsCt(fiTZ1K7FFELwJv)HO= zQsozzZ7N+%N1fnT@~KPez1v1-W@zr#RJEK4{OWEzU8xau1xsy<`lJ_Hc&1XtM29yW zOWw3>>a=7u5#>5{tQaQ}@!JI%>F#NopB|-4tAh0O9hvq7qK+2iEK6mRgiJ13r zNIF=HevR+4N__VG?W0>Kr#4OxI7-grU6Mxh)~loQ#^)v9ut?~yQ&hWssZR`~PjpuK zX5KF)`iyDbx&+;VuV|9_>k+*;^JT7gX0}Z1inf6UIdRu>zGFT@E$0E>`6Az$!Y7F5L~WjbpidB1tHrW- zr2@29Xf)c9deTq~{w}c~%NC^1iddgZJd{~sdY@puKdkQ~JRwJBTj`b;wFaTwOTa34 ze4j|q&+Lde675M;>@A?mcvqZ5W8YM%{&5c`$WL_18X)q~mj`9uuW}@=Prt@f!%%Kd z$1ePMT79q2;&6TXpyymE*#LPmk$jKinbt(UZjWvi(yphG%LgjOdS92_`f{6EP~ByE zm%UQfS{q_-1*JL-R%10P_j;ZB{EE@&7F!Xl z`B%mJnmF?L-Js+J6i-Rf+1V>pz0zI(^sKwqHVrA?8dbBEdV5K~R8nk7R4qPE<+)5K zXM*T|jbg*qv9m_4o*}4Mub`SbsGm`jC(l~Vp}y_TxIYy~ zga0}Ys;GC>cFk2emftsYGyNGFpRPU*OT(Z%OQ>Z)EzfyU2#G>XTiY zGO=dSI^XU4OwJ3p&ZE`#b*7~8-q&-rb;SP36#K)fteqO|DB}CTO_Pdsj3ga$aQ!4j zUBzov-O_!7Qd zA?X<;>BIVawE{QYdRtl>QZ{-IWJF;PWkLt(GoVR>{d9XpZ}$g;2OXDWqS^X*{)=DSo4XOen%LQo&;>Dif5;!7FR+mlem zbVNT_6m`o7brHQ0uWf0?Sqhx?ywk4X5FQNnE$`5%mV<10Rsub{k7_nGA4L=E)X~#k zMUnD$LpoEPVjehGTHRmIXD7xcXVP?_2c}%3fcdt*j0L6qN?x)t9Jdp2<4!+_L-BV(ss&w{M|u`=1fMn2G}n;vH{;U z`JsMvnq=L)Vvj<7qU({&rn=>9M+BWoQojYUgH(xVBJ|CDy1PUZ%Zs`YKj$g_c$nv5Xcs9vPfu}R7?cb${UNsv51BxX{88Hco43>hwfJLtcHM}4)OgUymG9I+Vi`s3-PDvDo!pV zu;jC|s*iaz#FXyBTH2GGVkYW2o}SIW&@E@}Ylyj~@?B6y2`xGo;TT z)&r~4?fbNu4O_-H4o91}jgIl#U%q!oqUz>V*$#dk1w~Hv(Y=|? ziPT&4lMbDY{WDuBhN5koHhS9)c*_l02Bml5_N`leE;ajyE7XLaFE6U%iFJw2G)~Cn zOQ?2a$e906)*~P}>Dk!&!v1KvTv0_7^H3kSpx2dVyG%Dd{e&_B}`>ldtvx6RfIvS;#ufniRulqiSaM&+5#Bc`Eq+`ksQm6u@4 zwI*U7nvy=EARWEe-t|5q0Tt9Ain4`_3s5KCVlqQS1(5O;g{X+5KTu2{AANXs%1ALm zJDGO5t2NH$KI6zW{7wCx3qBKI-vq4puY&dXYauGOqm^b|P2OVJP<8Q73$fhQmJ2x% zoTY8bc28uxdat$|#ZJRXG{8y>viDO9ej0P@!__d~Ev*C8?`6HPOxko(EUFG`W|giP zXqNawMOM{)#2iQL^X%e33f@z1>f2E%3F+}K1riV1E_7%jrP|ovEbE8dVk+n?9$tui zrt&xg2c@S*9nryacmG!8YzA0;(altMDaaR~X96_&rh-RiA<(51=c!3Y?VzeiaXf%p^r`XJ`qZDHY{p|YmeN-)A?PC> zVc~g7=g4L!kjMP75PK{g-Ev=UaMR0o{|n;%`s}-wRHH^ni1mq1{{E~Sn;nV=Rpu)rjrv0R2E)hUXMmlkvy)BN=b>Z&{FvW3tk@X@Oa z*?V;R+-A;iW^$A26MaANnYd#!u`RuDcfQ_=c2W~Qnw>a5nwq%4Hv@nb`PK31u$4SO z>U9q4*z8tMDw=XyitA-l*7yRxnbFBvPd1uWzL&$oquY1-QbB&d)~;t?qN8HxuVY>t zpE@c!=C^rfwr`-N#gmI7=q>S7w$9DpneZh$PLWR|iLWtrth_j(qNP~_eOd7;liYvk zLdDA08err5$7j5Xu4l>}s^fdLj&G+K&3H|iF%-tH9DS12WZgf-r@gAIw8KA#ZbB{G zM5HQPYGd@e=^l&B%i7?vM12>D@+d?FOAYEZ+Tfu z+EQJkHR>&9{vfK=#A44v9krKRrF9uuEHTjYY&@l>#MSubeL?gL>iDZI@@}?4#ac$z z?U2s|K#rrs(^Z%S<^(OH)HuL8V+Y4f!&|s(vz} z9m;3bN+aa{6YNl~QYFl&s+e-01;m$Hi2nOd6eaDr$DVs@EMu@eCy?|nYVM7>{`*bT z7kY`QTVG3pKHJ%<#|GPHq9}R0y3gdDUiNaLucTm2d9kY3ko!xZ-z!zBYw?svr=vFG zuT37O`fQl}oulqPgLwZ`_ZacsCg|P{uvb+7)%H~Z_H~Ya@hK$tL7JX}?&%y{er^75 z7JaLMBV9ky>E;!h2m9}+MjSQR*(BTZ)g9Gfc2f?2ioXk1*O@>&DU=N(ofs}hfd12Y z1~uRg3h4JmsyBt&J%J3oPR$U(c1~!P?1hGuE~APg73g+K-8F^UF@fsna!t-KyCqc3 zSJYjL_l^b4IKDuU&NIV;si4a;4$Y9!n|y_XtHCj!Z)X}sywpEYKjF1m&Qaxbl<`tB zx&z_W*-EXFjY3|`1pDjfSvBlwQBdC=o8`G&MprQ}l@jgh-<;L*MXIBm7jqpoF83dw zYiJh~^z!N&==nJYIaqE7)Td?LlU&cPhNo1^==9*TM%>so6H+3o|8B`@+rFG!R-^5N z+`3>z`-h#chHX&dvrT_8OKdT5y<`6{OtJI4tj5lD{QpyCORbD*-VbIy{QMU<3T?66 zC|5n+SbrwQLd7mx_hu~8&N$2Mka~WW;aiS^TdZeP{hng1M6RM+Dl0m7e5OrSmwDy# zg8JoWRgL{K?BO<~#F*C>XdgYvW2R9(T?H~6`s(2R3_FSdP97u)fuo3t2YpD%2%)M;v_pBkE~Cqw;s`}I|2$5m2B{)ZRregFiVRReI=tp^ zipa+nW%JE)j+o%Davzg%+MQM<#J%he)=9+r-;BkdZcpr(iRi}M&FL-As)*9{5mi=? z&ZyN^v_vgq{V6sv%TaS2O%gsTXVrE`Azo*2^z``L`ib!uF*M^*tt~|KVQgcbt~62A zD33OWM;=SO&&S`W5O01zy$%>OqaitULeXZB^p65U?Ey-l~$_};yPa_8P6Ex_wVDB|}NSpnWILRwtOS+#Ow z;9BezX#>_`x5x^hMfAmFCu7Akj*cJ?>iw6PM9)}5l}cNo+0%(MhoJ~)89Y@uDGN=! z?1{gXjBj3?8J!*7=KpOiinl+;_xBWN1N{zkpDtT~??6$OykEkba41q90gfFf-xc(p zxPI7>vUD{{Jp_5I`Xs||;Zi*ckG z6P-MKo#!$#8hx|VtdzSoe+zNoh_UXCiuafPYeoAl*Om=u5!()ZE&1%Cbd46z7p~MB zy*l0d*Q%~G^lOF1Y-Gt-aAlkM4ZR*->#Z#MerJt%U*v9Pk=NN%uV~Ak*pi@H`iH_Z zE~k|166Eb?@R@NgTY1fJrQGK0<2-jkfcUgx94;>NTaQ#QEi8BvL1w$L7#S(CT)kKY zinWSj@f#-5lZMucv7$yR?Ug!RZ%8rWx!NQ7dd29sB{s1((Z2bO3awEqH}%V}rO}6I zw=1smw8jq`*BDD_=njcz7G>jW_jvz6&ndR3eY>>WjhZc1uj)KvzGH98r>W2SFMNMG zs^KR2oH5Hj=YguOWb*vaSb%(giEEvrdH9dUfa0|ar{7 z*G*NqVlMh(;HQRmQ*H=90$RSWq2+ovV#C(7GDs{fs!Hx}NK1t-*|yd6-9@A6gfk7> z##HkXZMm!pjo6LC}u5q!BGi zRGeE-H{^wV9=$#g^;-Us4zlM3ed{qT+|C2+uhzb{H4Me}wf1yuJj(gJ4uIK_lSFzHVLcQ9ygE|yDobj}uSl{T5@XKue z7GMSjeZ9TjCU3RYp!?8SVpY*{X+f^O+D4{@$;5`V@34cK*q0uT^pzN7&$A2cO;e+D z+h;AKTXG$PTI%n4cf2&25%qK})h=3*4$G^XKF@UEki_AB%uLMgm>iqfIz2YnHSldV zqOMfA6&7th7jh=pE#7El>Z%oc52%YD zpWCu1rKwsm6G-{~0<$zTJyn{B+MT+0cN}DaFBJ5e5)DI&B?LRhlk+UV6=^J?ZbZ4? zfV^5Wd8P^FM6hRkk)lys(?+UK)FFDSPV?6$u-;lln|fXtP&4_-c$qfU7=_* z=K1Rrc<1d*UI>i>;)@iGZrC+P^S?&G%i{sq@E;bUu2gA6pgNOY)Ys5TN>*50xl^^5h2 zZoJ&(Bs*Jsa=s&CPNQAjfrg$l$!(22Y0gFWA|8Y!H=24lwObZ7sg&sMw?$pbjO$#|#B@h|oJ#(BI-mzQsRHCTy7WzQ z8w;A)(r71oyhCPnL6d43&1C*Q@9Fn_%dwovC3WbSZ;ASqu46Mj$a!EE^CCSzxRx_H z6?A9!==QWOXCdu5smtkJ%*2wSjCfHlDP6j2YhlW1j_QPOELfjQnb7p~E7mAjS$1lY znT{%^0gpL7j|+ZKqclh7dX{#Zmy1aefElH)T`hNY2?%+Bw_sId;PaO3-{y7RrX1_$g=;maIJ-3P|F@}(XYGslgf*}r+5zE5l(R$_4f6KTl3mg z4u~`K&E<;)EJ~p zOF5~w*Z-wmbfev3MrwqJDU^XbSxhD0LdStc)ePPAp zymw1rZ}y4I^XI!Y{%VEhpCiv4@93)Wz4E`*X(~z_UFd$rS7j_NrQ)?xg^AZkbn%}#B(wa4?mGqj&BDKt9$rw0M5wSAuQA-Zk*V8( zM#u-^Tr)9O8XKLNh+_Zoj}TzVhN)3*qK2^~IJtVbsn-yZ2_)TZN;*HXmhLsIw5nRk zCihvuUAA+pwGdpO;fLuO9<_W9CzsT*A6rFP;e4*Cidlh(y7P)x6Oauqv`A<=k(7vL zRG-ZiPA(yzphcw#8djYe3-SFX>WBY9(XC4M)iIh7eHM_|U)O6L);)r}>8Jbxz|`3E zREX*hRFXgGbK={%7d&V3QNQ?C8q5ENO4Nz@u}br-#?emWXMGZ{9&`aFU8?HK1DWPG z8jo69{x2wiT>9KN`eI*X`I;-s^K`S8_o@MQiofqm$YB=IQ)*>Zq0+pDJmu#qO$CY9 z2-Hvbb)QsSS#C#zjJDrutN_sl^2kg0OgPC`^m<}>rJ=Pi#P$N`GgtLl7fepA8CDG@ zC82qr7xF#OagT(&zce>HIyp6G8EO*y2l^AoJv-hD^P@dQ z%~tq!G}WA9-J)*xL%C+!Ha<2S*&Y^@dJbB@cjYAWQ9&`svE$~`-kmwe@}QttcWWG# z{2@fTAS3zO2S~FcVXU*7M=TA>#DCzEp>5;qqPY$|6R^Z2K?ZOJcqJveC^=<;PDyhR`7!-Wvl`F!4oph zfc@ZcDaX?f9F;Dg60hcd(AMdxP5wJ+Fok+gt|zw4ZlGkaWp2at_%5@dE{;=lYW4xH zrxl*}>h93tD$?PD4O)Pe9n|ixW}79_O^$7um@}0r%|&QWIor2gLeo_#w;b@4Ih|&z zQqFU%9LJLFo{`&bW_EIF%>KxsoCv(-@45B*L|vs)`=M(0h+Lz6o~cwZ5%}lpatWz% zwPnH*>{1%?&wp`_jH4l?>B^K_5BTS*++R|fsmh?dql&t;Us)sP0o(nwD4+Gp8maBj z`QT-Sbf!8(^1ht&#x_rkZ7FRJ@bWY2TiulVX3q2XPLRzWl3Oq5nF^Kr3y6pN<=JI) zJG~M+Wm$~mJm8;i&Lzxvx%JkN% zqq}qh5r1wa2GA^6bswWx(w<1gmIQGzq{M|ak;>x&ME*BS`Amh1iD=z@P2Y+$){pAt zG{=sZzv{e0U!O6}+dn~$*{!imMT$KISZ+h#ax7V>hzGIoC)IK>(OaJ&!#vR@7KNaiD|NOJE0d3l9Tr8Z5_oj9Xgqtf;bbF&kcF%z*C!CKekS7vpho*v~g zf{OZ3n~Y|1lrtTE$vOFP?3bC8aYu=U7gzI>L@U~nzErnpl4gQe0+ZV6E!8^a<9$*x z$}%HdPbg%|(4<_$pt^oPPYo$VV`x&&0~O(M9Q_JUcUrMNf&W}-_zw+*4BUUNHvA{1 z#{M%^UiS1{)CKy0VNEkY#rg%_v&PV`@rj(=djRjnhGvb2<>Wk2-+xfor)8ibq(1+s zM@PvxOp?n7R*?^x@|g}JCZek5?OaD~oSZ2|%QVc(7c#5MvQ(R>3jK=0^5dZSkUw#6 za$@J)#MJo2c*Je`?WNI8mI6SmNwh~gilwtq2boVdv42{arqhV+=*Z$+o!*h7eqzT= zw0EiAX|!7{&)1vKj^g*RR*BVJDz6*T#;dLVeB;8UZ z4SUPv$Xq<9vW@3D*eA$NL%tF@RscTL-&)|P7^#P&b$d%r;V(M&(*4w}<+g8T1igSw zeDim#y;_YvyJ)V% zj^umyW1UvkMoY`(O0-;E=gC7E|3ln~$arft1IoPxWUa|umlZ7uOZ^1(E;sin!)6i* zN!nB-87V|e0&%vnNTLKXGC=)JC@ejFh^2DO!}3iF(|Pu&3`g`ST}6kJ^=hqbCJDLU0oH>RmXRjpEa2n+qp&QALQVscJxHZ_M=z>HADFTD`>8;+ zDEe;Y0YzT5zF6z_=J%UzRS(6 zwMwZ}7$t#u=&8EIHdbF5*jXiZ+L%VtT$VjeiXSYzny>({V z56Swb%JQ!dzz6MZa%n>W(Y7D3~Mrp1~YC z*U~-?%KWaCIatsAj+HrB&;6E*IZ)62wv#$I&;6#IIZ)5N(PR#vGvJ*24J&i7p8Itx zbFiNKRTp!hp8GW?b#R{h6+6@0bJ5A;saYjCzYxG*5$Tiy$=^%SUhw1s$x_&f*AFDs zNkx{orBJu-FWK39nfhm3((Tiq01#I?VE^9AI!qbOY%q!Sh@^W#wol7=1MNlLL6>f^ z;(2oplI`X3Y#jC6GuaIH7h4YOY<{czNu}5E%vr!s-l^NoTnyxX;y710mMZWUS$M`m zASVI|KWQVX3YGJK{r+Xx&(}B67Y$F;BY_40l8F}@pEE`RrGAQTLtTx?TAN17MbY>+ z{*r=Ez_MsGMjpg8;60ZXrR43*fb;0(MQ^okpTyDuU%kC9-9Yo`Sw+jSYy-`szbM8b z(*~MH-=^Dbz&+tY1>GL)aBoFT@Eyd%@u1w3b?`Mu;1vi4K#{PmP%ZdKgLZ4xg2y280BgaPQc+Mede?&JHkT8#UID*qmdvwx`VOLHXROYz1jG&u!o~hIE&A#$EzNI*s zy1n;NBfh++7PZSAnrrFRI==58qxd*XiI4cE6@E^wQP)1?lx8>dZRHgI7ZDe1K;lWB{!Ao&&LgKL!h6T1;nRp%8;3G%^|A|=1`%ioduzpaQ) zK95%7#s9t@v|Bt%VJ+9YU3xFd8J<$jBJ!^k%~CR0;@d*fg0j-nuCEi59hLdnl#kws z$XO|?x|BRxK|cI0;(Kz@Sr-Hod&UR_(E4a>n-#aeWfhc;LUD_&bNcD%`#ac%4p6ud= zkQZ3@nRYJqg0)YT#nPhKeY4%V<`t4+D$?-_9aP)H>C%+}RTqyixyJG<<)Jn3^;yR> z-gn0tnZL?SnkwEodBovOyav7ok#B`H@QsK+z%}sAcJ9E}z&E+MzS25&dZ&_=-(aWS z3TxnN?c{;4fv>i62fPN}V5bgz4Sb!QJMcB|dKY)VYv5b#+ySqFZ*x$MYm|eofp2wC zgRFtz>zH4fYhZl6X}!77Qd5<5B}ARthDkLq9Te*q5mzk4db6sE7?k)clNg|mLNZ=t z66s{m_hu?|R&s$-r6%bf?VN34s%DgWD*BptkD}AM<}gyyh@-1_7Omb7Q{>{p zFn!KAJ$8M3NV$Z7d6Xt$yvZAIlw7V^GGUsg z3>hV7DN$0bSvIqBy@Dt?LdkTz6>uKB$+=*M_sQ%Yi#Qw53ky!HRJ-U@v#wME{_i@V zHRKjW!ufj7_Z%GL)+Z~TI$!SABE2k^TMy)$!xgV7(}C@x@A)_I(JhK}TxKMB+%iTX zmJ*!+eAU6VjZ#Rx6zzKMq~yB3ygc5ZrdTo6(T(SmyX%x*Pfo4(Y8q6mV|2DNYuB+^ zas{Qn)vn(gN`(y|C(WguvZ)QX6oe4qFD5^GH*(3xn-ZZZYKy(W3-D`@g1)$=3(k78nw21`#d{pi2DX*$DnYHmYQ@;L)?417xHyb(n zw0wuz4#k(U_d~1Yp6AWX>%fbYZ?Q6c@0LXN{DqZRZnqEz1+2dU-GQUa*@u+>q8NQ{-96!Q%;mSwliDQ(Em>r`)Tzw2g(F z?8v~U6Zup_QYJgiDrTb|+@)5wzaOKB9kXhBkP-V=tCV3P7VRsJu}Qi*YLjg}voOj} zmpG`@aWuft-sA+U+l2;?w`ykLE0z)H^l4V6>O5i| zknv;16P)3hEn}r~qWMm1x9^t)=*!-d4=jB3lQ2~Q#TgILPU_Q0IKp{<(S&+^$K^4x zVIm5#V*&lJGjhp@733ymbYireht&3hH|6F9N$(0s#bMF~@;>MG(`aIDM6QhwC3yt!k))El2P;6h7tvbZ2w&?x?TIE`u zUd{J37@br+v>;!?^o(qyAHCy?+MoyVuJHSOa=d6oedd~0^foa)qUuZraZCrbxwzR3krCrCt~9^8SN-&o5s zxmH1LyLYy(PbA-+ZEw?VUi;))tXJSSQ<;P*kIR<9`pqGlgl3^6mJf8ks##p5^2Mc+ zA)uHDDvNt*@>z;AxyJzBJqx^6wPte|F%Rv)?xFHb^NDF_&v18@W>Kctb|9zSO{Hz% z;=;3z0rNe`mGgH)brKDl(jTMkrd7G;WU2WSVVv=H?Ku-xr4 zTGH*bg}PjqAh%SqSnqdNjU+AACR&4Tr^*+?Q$Qv=EsOL-I(wkY^$EP?wyJyqd=srf z$7MU}L_Xg&2*`Cw)`=gRoY_1vYiYGgy#$@wJ}B!;q%`iF#gnM@J-#x6`Qis?)c9(G zs7Kw`0ADmYxW~{rz=^pP6Wto0Qp!CP>>iHQXxun&)S8REB~`UzdxBlkKeN+^)SmS{ zR-{}`&~194W=)>x2;@T`f8SHnZis#_`bKqIwrfc>8}h6G^+s=N<$8J$@YZH2h48v`2B zN&-dAkVVpXWe+m@i)JQ2Y4N52({-R~T4RwlNId~8`Up!VHa~}wS`_K^<60%bdC>nH z60LJzw&*qBStO`QZUZ+oZ1wPP0Y^mT)wJUadn91#jmh32b+niR_0)5 zeb;8p$x>-MbsS0)vy-D+P320x7WExYwlhuT2DRuj>{LU&Vo4p9%6%zD-W{K>k>|!9 zJ2@UeuV7dF=uEAXiD{f_#ypz7qWd98w~35VuRO0m zuO-enK)?U$OIq%>nhYkR(hQ%`T98uFJmfz!YI}ta*BPlU%~BSsWdD(~NT!t5jTYL2 zBX;BS4YFqPphzrVm!6#SBm#f^yG=$FC-zq~JM^0@)3sY|ZpE9)PHI8)ediOi=%Bly zc1Mje%?KxM+Nd{cmINeaqfYJ<5ZhP7V8{0)2UkUgl=N5eHze$}tYxTRxi0}p|Cal% z%Jq{J?MD7;5>=R7J`kIK$!Gzq5OlA|pA}wwLsctH=vwh3_8zdC{gXo7xo-8jftXi?-e=e0uwt@E+^3K?-V9Cx~#4nl=)kgNlqMy2|V{z zaUVL1mx-xOlT#CRtk|L;;~tysb>n!U%Ym(eiisdEtc_0hpz6EJ_Hcy2)50w4Od$_%Ah5G%h|)|Ro^T{CkI<%;bIeCSt- zoMY2d8|?-S$^5R86~?BwIntk)34CZFKFP=;bZncWC<^Mgzf^R)VY@@MawhQGU#QHf zK-L7B{kck6NbLvY{Atdt&x5v?Tu#9JNyg;E@kByfgHOyv zy|$ZGrgz^Io#B2W%Xutcv$n6_sG0ASJKkRfgBAPKtmnq$u>Ek5|r1uy2&7_FtKz%r$5qI6er}fwlEP>K?eF^MqOBGRzNxsGeKwQ2RXA- ziyvhVa6W}jZ~l}a~HYWkR=9{?zSJ5)VmU_~S!Xq|p9k3Sgt6rZNPP)S=KL#OzYN){@%PJ`;32s` zh--I)TZspeJh`Y#eNKFWWN=G!)3XzP9)_lLercDM8l0X?P?`KV?p_#@a)VQaiv1bs z_uX+X!JtlXD?`Ofy$Ma~Tw=E>Q8%klxvXIAuG?eBUs6!X*X&mHmlJr>Z40@W$3EiG zfG{_;0PViCkQtd8-{}=18#?NSQz;vtYh$|7u-uoxjMAqI8G@y4mX|&6h*|IOqV*)_ z|HWO5BubeUH#oc92HjFvr*WRBQtQy=R8*0MxM|m6{u;$NBn6g*;VjKfn@#I1e-J-I=R7aA`5BV~`5Kb?!%ntsLnHP#hsAm4{M*9%qxhSph>&to zbp6d`XQP-9Q$a4dMOh`%lRUO@fO8LYj`om3RiS9vQeK3V_d$TGEym(Jf~>pX@@J#q z5K9Yoa2GnM-m*H@WZuEmY&s4RJ&wK;-=(r-iyr^TajZ+clNz!TjZ$3hML@H6u;r!@ z5d-8r+QIbpAYjeU*mUb3DPWI!gq7$kBg%m9DO9d;DH9hH)PIjZf%mJ`(XE$XDP(;A zyEf1o{`tbGneD{PPe#<~UlqT?o^+vOa;M5ybg4jjWP(il=7LsZBAv=L>J{@+FgX=; zK|f+p=`@a~@aRNN6;`~efaok2VkMT99vN-YY3SgHf6(Qu?xzFadc~6nGVQs#jL8R@ z)tYvNs#LEiUS6Ox=U3{DUY$PnZ!Xdo)LM&9N=C1ay}qDd{~O5AX~Cw#xfBoM2Aqum zaWYz1!msCDMSI8374lz9{r?&mkp2QRXZg;8UHKQZJHGylrnWv9HgRirrIqdwc8ZA@1aLQZz%d_LDb)u!j1 z%-=|;VoSXk&7GV9rM4PcE<5N5tcQF*xl#0fN{e3pP-Aekx9c?TiK-FD`pSLVpB2_R zj@ztea*q;)^r)(~3MKTwlS~ee;uD;AXu9URQamjSdOUB{Xt&nf)K_(`R)9+_ioRfo z3Y`x2rx0^fi1$8CwuO2}H=#TSIZokDC6Bq*;02x20=3hfHOtdUtX_DJ(IWQrHS?Z%S&P5e+SICr!)K1BNO*ripY!{py0$SFvrrBG_(Jv1pTk#L&4p;WRbA1qOBPen zDd*P<5)xH)7%>U0tgYB%#wTY+XXkcJjc%JTFN2r!z-sXR*i(wUx^M5u(O+Lho-$_8 z{4*yyL)aVdCdMM(!DPo@m6gsO-_tL&AKn_D7LP?SC!)SeZ`gQRNxC{9-i*ep5>9U( zNqJ~BdQ@z~v1n#`a%!#{EwA|IPsbX|JEXg5tn%(!R9>K|2G6f^QO;h9GfXO9e5pTO zbzN`rr;I)A7+f5Q>m6qzBP8pIapV`dJQ&%jb-OiAbFB`&`$mWH-DuNBEtyNLi@r@h zEv^p#zkbE=vS%Jdr=4pIZ6tONtO-Y5zJ~0vD$O0SpT~Y+{RRG7aGVPAm*RIfwD6F2 zr*(0Sz6_^V5uj6ueG_#vFIHlr-J&b?hg%hGp$JMWDSns`m-H5~oCwyYHHy6x;=FcE zk~GqgPVc4Imb5t>Gd*Jpy;RaDX43$51!CP@VHt~r+;X71e}c-QJA+!)sHI(5BquuJ zlBYFKQ{rLSwJZf?eo65c+DXv69dV7}=`m=|_#B;Crfc@BOQAS2KutQM*t6c;L-%2* zLW*g?du~uN4ds|1afsHohb!`NZE9Uvd{=p}wry2pcK(8au5I5|e2ag>;MO)&&t9Tf z!+$@5vSLqJV~mHe#Q6fT{;kMWo!82AIm>ZIbsx%yA5mETFGeD{o~E*vwJ;IOg!+Ho)n~r&8IrP0Vec9*;NW3-wx~ z8uj+KwGExviYUS#nsT>H?21C%W{CDrKaVHd#v*3%-3tA|ZA+3@7d5fWsPi$OW_a^= zs8Fddq2AmR3VM!Zca4wBC3UQ2e17sSjk?%rd3QTehwdMmg@eonfm-u?&5|{`sdmuJ zuBKD!vhIl%S{>gVKYG7)v&Kw5U}=4Fj*P_BaYR0h-`OkDqo)$cbNIioLXw# zIyDeO)N~-fU6b~B`oCbY7DuA~^sijcAisUi(6g%uk!l<5ehx5XO{m6kT~JxS>5z5P zM!k6#Qr2q?&k9zpJN%h%xw}u=bx*vBjz&XPwZMxf(k@WK<+}FPu?jErsG@az|v?%H!mHcu(_V* zSGHQq^>QPcFL&$Or{MDZkO;L zSIwEj6ghfG$GbpP+2%h7kFXDInC+5cDT z-AbpvOoNt9txYcWO~*dw7_#9_CRtsw_H6G+lkYzrd zNk~kdMjkxzaaoojVqAM9MZK?HL1p{mEIMeXjT9^O9JD$vCCr&}ht5;zmAo#uZmH1n zJ+(r8xvLUe>P%nFI&vKMryrdXx9CiNIYFEpp6b@1dP<5i>}q<`>|Br`eKtio!%$%XszF(@$@laX#^rIKBcI|MQsxsREw7t zNW7tnn-reDh|XtTqVlW{C`mPmzOy)0g$gK%_|8MX6 zXi7CV$04=*5tSEKyI^*AXJ5P3mNlt~r39Jg0)-YQ8$I~NRz#Vm-PbBf$2>J4rLrN` zSf5pz++>dHi&>x|eT>R7w@X2_ctYQ5({$HoskGHki>PCBS<;!}wJ04soP58fePeVY21@}3+862c#-em6_{378 zJ5^rK^Jy$)yWCrv-%p>)4AO#M&1B>ej35?V>sWUWqj>mAfu_2pG)u2_oYx*fl(%yJ zVht|WI*VEZO3ZO|pARR_cQR@CB3@M-u}7eeNri86W_cDHt$CWIXtY|p^+uOiE)dn< z%H-ljE{IQ{>f!ZSR5Oh=Nn;!K;FijWCe2UJ@+DL4IJpf$H|U#1orcXNz(c>5QO)vJ zEFFrtujd^4jz$~vky>pnkmpYs$GlEUED!od=>C~cCL^rDJOoui-_2y3=f`yRl)baQ z~!WmRFOpE+C|;s zs6Z9aIR~a|P@stf^bPR(0xQ6Lfa9Enzsy~ik-|&|IO3dFoRK0agjWEm9-euH^~gb- zpB*IrGHGwT%a|<9B{$i|1xmGTwyvd2w9XxL5PM>uX)HiN{r<`EDMz2?eX}#zv)xgX z%ybi}9?`vAch+e3i?YQ;M^@y1!d>IOWM7vtQCFzgdZ>Q5i%mvTt#T%?VmFSy$iaREgvlC-;)3duubF-6E0j9Xn zr1lr$J+Vgg*QsL-=X+59oaj`QF@#+zu_7_Z^TI`7<5Otg1 z7k6ti>5OKLoaOLPK9B3f@weI9LJ@1wVKF{k{CuK8nwQka&czhaJAYX0i{U1DkWXA# zU|HJ?VmqOkzJ&q}ZL>mZvz#(r8*(wrk(m!A-}qeWAO6)4su`kGBD@_J%LRI07pX*Z zGal4Sss&m|FG2l=^Lc7#d~Yo%vavYP2+@GNS30&!jZ7 zFp*MFmVQ*~FNN7W>P%H>Y(iC}l!?}%Pp6UGksM9lE@>*O(ujY71HCoS4GkL=V9N4-#so*>F4s>|$B8yiyPr1v3U)CMNO$L)=L$I~4Nbz_sYtVw>rxi#KYW?HMPu|OV53nl zXB$}GRq6ln_Ac;o9o7B#wd~lA^Rk^62}w{KlZ22se#Z%qcqOguC3+#P5}T%6R;#tO ziKJC_B|icUfdU1}yWtI?&_a2XLMZ`S3gyQeN}=$h{nH<`1b(!%w6r9prR}dY|L=G1 z%-uWpajfB9MgGXEy)$>dbIzPObLPyfv(R-Xrn`Nt}*BHj9Q9w#JL@%XgdFg`&x868eFWpXF$7B zEJaRVq`ebEo^DJn9raUPLhe*&^qA|w>ANzqGYEG_&#;580s7}+Z9Utn-`Si$>ep+t zvs1PBa*Q+2GkWbdp#B|qn?`s}WE?#fgv}W}L&kRi{Tne^i=bzVoHOU8+4W~*oNvOh zn#y!%)V&#_!ge5D#JxZfuIpVbz6uyS$Kdts<@TWO%6Dn++P}~;P2$^t?i6Rt?XL&L z3p|e+L7YB0&&I}4cl=in$E91KXEX4p8_?q|T%4EM=&n4M?n!86)S!-G3wH&kSHQgu zGIrHI5pD39n5<*Dyiop2{cJv>U)znj7H;GK$9cVZE2q>+p8iiqC)S;*6Ft7V?b3SGgNhx8I{Rqdk+mAvEUv(wyp#v86BP7TlXbBggwK5i6as!t0i$ z?oUx4=W9=C-_<1|dQMz{>WkBH_2hb`seZhOo{ws2lwVEHwvjEIhb(6AtTaFBi_DK; zLMARTaPF-cURdt<{}g@=bu?F@Xz%Rgk6A7t{z)ogeJW=Q3iI1frXkvJ&e}oJx1WgN zB?HVjx1cay{(WTb5sb}B{lyoMohg(g^pB$yrVN*^^hrA!J|4l!uU94OY9TUCVriV+ zA=ow;pF}wGQra)o6VWf+=gr;gq%-bTu}Tp|wZPHV?inJwh zg$c4VuH=omDl$_vxY<)7Dt$T>^9wBq@(6wa$So_WW-49~>lf%nlEW^o=MDZ0U?nC=9FsXkLe zRyg-*!S8f)WQNKX))wKT=6CvW#P1Zr&)d3!-tNT43*&b>R-0XlZ4h#nbEMSs^_ z8My4xMfrLpe^)yL|IzbzEoRi<(ernGB-XPF_jhG@^m~DOS!B+4v_8kxu*KR@ThLv5 zwzT*8u}M5E-ZYQpM9i2|(_3<060zODB&-wbR?bukT)i@hnK;JijF;gtWgLQQl6cMe z6+Pp9eG>5qAUiX5L%Qp#46btZX{h#0gQ*Kbmp%hLl&M)UCHP44-pHNCjg6?(My`|pCUGeLexf0KAuYR`UlWw zjOVF1ipSg##dVV1@Tqb z-}(D7D)aYFX(ajc$a+!n>nM`v?Ms=+wg|auc8S_ACo#>qS-`51MD5oykynn|b0g!X zy(e;|ZK6N3s4Z?crWEDz+KA^ztyn|n!#Q4*-WM#uZ$zmrau;!i7leD4|929zsNJUm z>YpZ2i`suG=>4mra{MUFLoZL_6)_JL=4e}!hy~2iBu)6ZBw{#Us?Y7s8zn{PEf-`W zubd`4KZ$Adetl)By*d*)AGOka=?O{9{PQKDMZXf&3RCssc1;VIUr%D{7R||5!7}?` z#4cR1HX`nKoO#6ivE^v=u23Dk%^v_wy*xZ9V$8+vJlh*70 zD+{@xorTi6&Gv{yh5VkW<@Z`;=zZ>H+@FTYX+}}>3S;?wX}qp4wcFUbn@_4GPe(Zw zbs=^sp{q1Yh-0aUa|=0X6!gSGME_D59&gw3q6yYfJBGG2UjUx4gQ#b%(n~{;sKgWb zqrOU>hCP7?$wpjJ5BBOb8j}-oXYY};3-)xit~oj~sFeIX?yEXti>Nc2w08Tj@@*Kj zM=Sc@iI7GFLh8V=irt$wkwy0Wr4VhdHN7<3=pYzU@`68SM8RV;pFkv@x|Pl*)4eSP z4e%?es5YQ8l>*+I5_rk3;fyC}oK6xiWjV`o>Z0Tc|ghx#Jv5F&JlUL|gcs`6&5} zUv7|==6RJEw%v1-t1T|J{d#LDuU}8{+`cgzdFrG;+V`})RA=;gdQtBbu}3NcIkBa6 z{gav4HmIwP+nb?FIqn`$!`!asrhXc;U9qLJOD{`cPh-O@&i+%#Y?9q2TcG)q30zE3 zcLbshnio&x^dm|9ZphdP;dbS>g#Cvyc0#yau_X)rkFv3IwzT92UF@Qop)N04#`(>Q z(3d`-RtGQ|U@Fk4<&8xx&DuY2=voQQoG}M^0w{b{7H*oVaPPAM^2Y__gy1?OOV-l6 zGmvdTa_uY9$oq~YVv!nI@HsbQ$OY=-3?DG}+kZBOTCg@2kROnc^Xp;(`4bXyLZDrx zOIn+LLl&|v(C&RGqxbUemZMS3qO9Z$D~>a_*GKVIkgmHz9GJ$_jm26r+`Bs;h5q?F z5xgC^(GF&LyW`gz?Zw=?-vvM77cJCAe+yei<`=6c7h;oQXDJoDPp>nWIKH3GSXVS@ z&iDa?rkqdp_H2xu&R7}iGM7R&|JcSVqV0s886URL#)J9kc;l`m#QCy2hBJ*BsF#4o z*G5pc`-}M{MbIt3X<_L;VUy8M*7XEW8P& zXDSFy7V8%7e9e#&=2QRX-$yo+z+MGd@qe*=4?q}jQ_O|skT`2i;x@12mP5S zS|$IfWyzlSlPK0;0h&dyb?=R0*^T8c7a6uE@5%X9gHwKg;k_IFL|VPn(+_Z+|K#C zZbNgWU`~27v<}ZBe=tIC6uE#gFawpkZplJjS?T$08!NZ;NGkwuwXnt;$69q2S(`?7 z|4ge{&pD%)WN6yL?gyRCBTc|J0^r!x!nMyxR39_Q-HD7@uuYvxxnfIede6-& z<}{21`l1v}&WrOQN>Oy*mWD{PJeZCbpzEdf{a6Y*968$!dOQ%KYx_#rFEpAlB3mJL zZE>lcw?}1Ieq5_w%EIPk2*kJ!k>`g!(i0$-G;|Dy#aC|UInS|zDJ-tzg=}h#;VtD(EX`& zh#3qnp(GUU8}#B#f6L(NCTV9l9qc?LyyQ6wp%x9=J=t(Dz@J zj;_Qm-C%X*e1^}9XK-fH(F<9Pkvy57OV@a*>~^L%!|S#k^u9VlZ+Tu_&)b;31(Snf zbgiK4?ve4+2RdhYlWfWlML5q**?Q5tfZgYk_5A(})c6r|=e8F5_1iNrRU@mzZFzON zG%uRUK+nJPUb11olz|$oB5k*osJmQcNH%Xi=osYk{ISMtYoQTL%F>pvoN*i>^Ipi{fU6hlG1X@23{+ zn?%sA#rFJcBjGv-P}VkVMmaETme_JvfqPd@tI{ z(3D`Fv&>60{V`7zl6&pOF`V?sYflPx-rJ2t;3B`3rRhC}d&A}7q%+3V0+Mw7?-+?7 z($RK{_e2zM`?R3z-yNlmh<3+vmkj~yccNHD*a8C9yA;+)5Gl!T&Bp}Movw^E!V7@& zxgN^=2tt)D<-AFDw}A3aP0>4 zf4tSs*=oBpY_;>zV!x$ZEg|O4EhVA6!=T)iH==^XwYM7-9D^)?Yr?GdK`nW3d-{m` zS(}Twwp}Goy8U_A*;*EWHQzXjos!35iq92IvMPQv!o#Wj^DSYlf15^XcV?PL7I);- z6H;WY`z<6J$eDM7RJ_&TaA$HGn_6Sry^F+p2XAJAhG;WV6aG7zS0;o}>Me#YVCCbU z8N;C;pMV^PP-YDo>uj zDT8)vh&(4_Ab)`x|yD^ToYu|30xFXSx#nE=|*}HOR|E*@J zXfeadojX^Mw#{+09XIaGN1J4+z0SyeBloOP(1btK_U+u#Y)VIVl?;iV*J^rzWHZgV zZ%G!$71|!0TWIc_T0xK5eTEuz-~1M?-ASJ@b)f!m~#H&|2(M>TFyA7N~^znushCa}Mz!j<#@}PR^T8 zB#yq?#>^=t(k_UnMA~jv%}~<1fUBmG?B7>JolRQV=HlsTX=bMjPL zcix^rv%y@sDaG7-RYX#n*dmp1TRZbniaznm2pXd2;>g$BLOfWnD|M1}H5cjc#6y42 zIh&9qv!-We)MG?rPfr1p;-!X%wa%St zDw>mvQhU8bV-=*Eg`He4wvcR+Ts4=p%i=RyF79k&{ic3rJea?8OG*24UZiJ*2;K&l z%Ur`hQiJ+nG@?fAP^v41lD7Pm_9-P$ZKgU?Dvfp@&~wBPGftp8nqWcynwAxVW)tSh zOUYt*Q5OkLA8yRai6wYB59l#9|G8FarnsajnrWO^(V5~4H4b(arVQ0Zw$b-A--uMm zT1bZOeLN_7j_%QFucUIn1RXo!%5s)>=?uqe-Miwb371x(sMlrCns99uiu%e7S`#j= zLQyZvKux&1+)*=p4p%^$?g=@J0H)X{tw)L6x>K4dyddnCQOulLEyKd(`tGk9yn1fm za)u9^yW*a&QI51*bIOKIa|AfIowN@Byb!UGb2cD(5C2a4DKP`Fo5-COp^fg)Frxe?9T;>oZ=xR?5F3#))#5*eD6 zE4e45Sb1e!@C5#*_VG+1s4pf++*XhmP3Tcuw1$|P--#s?8_2n(1f1iVd%%Igy>d7| z(i#FdP!cPLbD~SnR5R~7lfbuQ2B$fnU*iclzS>zl;@3I_XjWlFTGaH=6P176Od63o zT_jr!oGk{)JNg~1!w=oKYX?rzM@`8U^=I2HbIxCA&7Ry@YvUGTk{V=+m^OZ1w_TC#cU~Ng?yeQ3@Af!Hfta)XGUCthUiqVOwA{2wXLmjxL(55*FfKh9 zMFLGbIsV#k&U#Fu?B6ZCyeIG^AJ}UQQhB7m&&TnT*p^pU>6g~=Kdo1})zoOQ7T-qc z&cTdz8b*ITadP#HPkFQo)Ja+X19x9cmlrz%8ToWbq7(+HMoH=Qd#B`?n(=@BNx zvf=kIdHMfz4fMm29tX##=Q1d^W=$xE1~3^f-lTi)aD+f-*e$TqFHz zoWcOp79VGsmE`BlIF;O@@hHg8%j0rO+#=*h7}ftG&fTP{bLOoSyX$0}#vt-yumdJ% zn@W38UJ`FpEaPE!b5eBOsTJlbe-`JiMzslb)d$i(sW~-jRYv{e?Pl%>cEXw6m#K9x z;2i7Bt8HIFT_i?vz5(Qdc$`Xi;8O4GtEz|t0EbjHFef-*^Jj#_9c(oa0Fm9x}H z^RS;Po11+iRed>QNmlofkT%*8^#y-^x-nbJJ$Dwg^S`K3medtwK?vIA>QK7?t8v0d zYVws{4R{wc~wItHd{^*iCLiiP=i#}q8Go6Xq3wlkPH zX_R&ZPDeOu!#Iz48NP7t{h10;^eALQIdf1t{qd|W*8Ec3nd6Qm*b9Ca36a-qlAO7h zA&2zj{BjrPNHcyw&Yhx+*%tRr-5x=TP0`(Pgwf?Ml|4=kr4+_d!~(L}=Z+@m!(ZxB z1q&PpXkv~d=e81LV%0kC6I7JtwzH%W>=|8}YV~?!Ax4rr{{*QxY_RCN$=gl>&LM-d zu(TKp4OJ*Tw{>wkGkNI|wBDE0{139Qu*l%l`R}n6bi}P8O^kIPn~u42FJmVxWBg5q zNUhlRZs&fKVb^okcdO|~^J*%)-EJmlB!P3|Hj)kG%sI&te3P*{5sqgH@ybcrVmwr= zJECBny*Y-M?7&5G@=(Z0;>4QFnJ&rCQMHilCUd4p&`57J9)bDBiQF1i7!RwaPr-j% zjD;k5jh_*64`{Gl{Hdjw!f@uH(7z_4w8g`Bxl4thZ^td90xTtgs;666xkp98dg(E? z5@lmLX)3w4l_VKsQK|~Dm84n!hNv9ET7nz6ncIIN^s>uxz4D<*GXJod<BTu-hOjFuSaILU;_*p9%4N%@2o^R<9bU3XQtIzoI06bHl*FHPmACM9&`L( z>$GAAWSm=0qOp?1goe!5wjM>EFKt&o>;RAvH;B-Q+P z9#sWfq2FL~k<(9XcXOss(w%)#tekw5R>n#p4*Eb5BY1{~k2~h~hggX5SloJJMvL)e z&dm|Tf>#@bQT98gw;#c{Fx#w6<@Y=b^QotVH2MX2?Ik_^8^$YlL@kA@MR;2@oqL;L zJv_Nf*Ie#dVup-xh2=?IoI=*cq*3*zE*3loM{-A_lCW-!VAVQ}y}RwEa@SUZ4ECBC z+YubCosWfic1IHChWiXv2wvgWXKHy*B}-n%j~f5M^wQjdHqQOrei#YyE;FNwBGzLU z!Z`C&>eF`{KV1aT78K_`oiS?DH+_x8(KsuMMEbDB$v6w0kpw+;LsuemN1Tv$SN4Py z(Uawi!1#|a9S!YCTS(kxGGm>j7igy&?-o~n{NoGQ+nt!Gx>C3|1MeE( zwJki{mJ73)et7(M*Ak*r*rd85OMbld7IG?~&YazwA*)XWrDs@poF1q(BLCj55hk=e{A#77iJkf)<6^kkx_7)QnBji$okY{@D<5 zq1{+f#5*h+*&kP$#>ZPU60ryxrCmk4O#drp-5^6^xC?nI@S~<)-RmkR5=Gk-MYymO z+{=G&uY`1+Mq2s%Zmu;*1>Q0%QO428?;9-Yepz8Q&JkWA6?ZqVFcbQ=8U+UZf^G&D z_B%d7(^cfXz|syr88l_u6!t^iAulUKRPl|9WUX2$0BYz&uF_VK;0c@ zkirCJ?px`k^EEF`r!#qs!r2y+Y?Z$!YH6~1aCE#hmzE(yCNBvTNe|e$^$<5GlSAo0#W^*@+o14c{j1VuI z-U2u+ot!4s!M(3Ijn+I8I~3qL+Dr4_e^PS98)ld07r2eRkabgOt?zu=G3rj+#Rl&6 zV5H#ueN(XPFI3V)3PZf+&X~)!NRHl5J!{iffV4;)eP0rBdS~7^kb+P7F3xoW3TsDq zLSSsg>a5EpKkpB^tp}_EqJs(+_LX6;>okwXmb;xLM3~wBDC~2c#$CGK*(`KLlh(lg z(L!S%&xa-XTe&I~NCviQ`>m-v^6#k^|>0P-{iHy zNwwvUm?4c^PyELe#H1o|l@zJ( zDjWxJfPKzSGm8qv8?*5O<0!9;3LL$ed)HLoQ}l5F!qJeJJJ6XzX~z42O<{7#b4HVN z%VqS;b?H+__HA~$%BMuz{?Nu$+)NI7&a_D*?6YjN{MM`>C;t?Vd5SXZ>^kBn%vopZ zq*a^?ZR!A4z$&p|uU`|6dx}Eh|VlFAkH_2G;p$o(Z2QhvGLn;{w30_Q63gi@9=Dz z>NB|66Z`XyFtASpONx1Yml?JYyi zdr7N_8{S*fOYtqt&WIVZLx0%I!nyLTm5EBP+COG#(X@zk|IR4nE@dXoS zN(Jc|4E+!`W&u`NMt|YR_nMHulhwg}SXKsWj3-Fx>mz+Jz^h|7J8!l3^X_aF zq=x&kY^hPBbY3|Xq~^`x7-?FuHho7bFi&0ZJQn|G}K2aLds&%nd&>FF@ z;(vcQN>9en3+O9?G`%AeH*cSj_Eo$+6E%O|k#KJaHGK8(SfJh!l@q6#3()bBg}XP2 z%X8?3VN0Ij+qtV)S=WZVkIX-H*o%UpWT+AIcHmD=s(VCdDnELEt6`%*&>l7XNdc>yHbh)G#_Qs8I4+~ z>y$}}!6fjv%wmajn!~mY?M$b1a{OamIwf<~8B^lz-*zQdW7-6|_DX4u?Iku=iXrQY zCQd!~J{Y^Vn9%p$VbfJa-xJV&HC*>qlub8}#9V;Rv`G^3 zH#Q$rjMgG0k=&&n+d=exMEEEUvnDN0!sUz3qgV z)w*umg@|zyojEG_Ro>L?2O(avGdLq=%sIGc=Dcv!GgA$OTq?p(Cd{ke7E&3(v{kfw zD+*kFX*gdscrBkk9UIb>t9vv2kJp2v?~YT*gFVG2w=-y`@AWHb*i$F{k;*_`R6(YGIhm=iU*GE3brRtf6lO zeNT+HVYP%MN=(XQO2AcaB=6A=;yNI}OugR46<1ml{aiY&SO~Tm?2IYM(8;dMmaBeg zT2#u?o!$FPnbh)w~q zS%op{jBw`FMNACM?lcOP$8}*lb`e){uD2naJ$LbvLzT0nX81j>LJR&wr~^Vot<($P zY=#$?J6wL8Y)g%sm%oz6dqpO-1#nrQ_Uh2%Ii{`_hUJ6BokC)%2&nZWDmU5`5y3^6 z>wP)YMIo*8b7`RNJyp;~XC!GYf=;35d@zYv=arQyu+Ef9{@&-c}UessHGMq55m9`~^^qHiQ;yGfo&kQYNt3{lQMh{4^9Mh9`GC zL90xKGiZYs7Z+EpB2fo*9ph%gf#yz~;2*d-!Of(A7D-=U0xvQAxzi`;&G&`lpJ~0s z(C3aP=*?AK`bv9>^Fs(N_>RyIQ3(-qOQAE5=(P2C1m1$`g;so3NMYab*rQ?z{@<|wcM;=a<4mC- zHK&I?ql=epLT5x_1bciar+t;EM-*{=a_%ya_NjfZ+mbeFV!NX=tpazS(&es&YMVsP zhyr&%okk~a5>IaHbVe2Ed}k_Z-Wbc0<#%fuXL%K7TF3x*4J7DB!WMo%;+!?Lou6-w9ULzo{rQ;3i`9q{F$= zCvozxjI?M;u?cfUlJ-zPq^v2>)yTRK!xc@U>p??T>V+7tNRouS%18*VB`Q!tgn8*F zLc}9eg-N7<_q7P#j&zZ9?*YQ7{^}^+qtfTW-uB=ZKdZJ)^Pa-36Tw%{>%$)}Ghg)Qes5#nwk9{@Z{1^(U{HEr zHDAJf+drlA@ftbx!+hV+f18i}-u6!s|6Gsjl%98Hl&Gt`b2ow;9!|%rAIP}(!2O$t zoAq|9(>k))d-eDedWR|_x9D_lf4w!g0N4la|7-7&N6d@F5e?@Q9S)4jfIa?o=zhn`V-+P zul!O!Jg@jJ{kQojmRF`!elCY^Dk5IMugdV)=y=sP{cv>LbMAG!Z!}$?D~o5Z@^~!@ ze^U7-$l}i6wcwm5W%2v^0Y!&=)3V4bIn@tL6rgnT@#}uC_fwRSVq}penjZ=-YeHf6 zJj&xb4_nr})6`!^7`IK&&MvPlG&MW-d!DNCj2ESkNUP10-OPgrUYKW3_X(df>X`W< z^`6JOmd#I(SH+*cpJ;O5)EbGZ6D4v8y=-Cvr>GC_+DVF|y=+%F2T`3Y>}6@^_xqu} zI1k#t>U7WVbY^$?!6nokFIu{{A^L4OSZNj@v8XprkQa;^jY9niTuy``$c8Ht?KsgG zy|y^C6t4?u+XAHb5v@8jag0|+wh;v1pKC16w5IdXC$-#ryNGE}?ky)!_q$!J`fRg- zkU(jW&aIbXJCL7Sfp#0Ti{|IfLOB}tk!Qg=;V3t>ikQ^T&x~TG5$MiSfx^is+M~qP zCv`E4l~aMMH%2j6oU1oQ(Te1%&^wN?cR=`$?J87KLz~H#RBG*|E@Ckp6{uV6Vm(Uy z>=?vid%nQWb{BEQ`FU3tt4MyPc#o;qt^nFXh$srEvvy0{eM(Hm}RtWUX zN3aBzy3?1@D;Q%Erl#ui!A0gdNBIHlJj~@wfa8J4o<4#Y;XvD~_zin_}x^$YY zc^k^LwbJ&lkfN)B@&)3b0`47IxQy$T7dJyfX^}QFaBava-OJ%{+BzUxmOF%I zqKJq~I@WF;1A}jAoGgOJ67tb(Ad&TmDLf*bezcB6y1VKysW z+cGWA6ESH;em@0sy0Nf0V?(-gG(&#Wj68{%7tJ_Md+k{jZPtH@qAj+UI(fO7K^d(P zdbxuh2w7P~VDxsU=GSYpvs1hVHrj6PJ~+wxIy>x<8n;oOp2+}?)?zuffi!x2JWlVU zf;weUJKJfTSX5?br@gpfGuf3^Y3_4-6tw^io3{GQUU@lq`b$y1!jGHkm~-xvdsEKG z5b+wIl`QJwdVS$|KE6tp^nMB1hIOVmT!@P41&+?|uy|a|IFc5HogBUvSi3Dc8y(Ka zaB)KYPHyOd1lOl*VqIldvZQy)*fy{;mnF@#D-F5Rz&Y8KrT7z8>uPQzC<^X)S_HRq zQY@{9JR=3!hI4J%v>h>&Dq1IpqiF5i)`?)VAF_}dwQ0XLga2*PoMk61LK|u0{)V?l z5${@RLS#C{^i!$*{wa#Ou+&~?;j-*#lUZMuGlEKb_nK(`px;EVGo>31(Q4#HzBZ1m zoovM*OE%{jQRKPK(F{YyU6wMec-q##8EsWu?$*ixEt11MQ98qG4m+VTvINQcvYfU} zyX&1jhc_(U7Ns_>6x{i0Hg?2DQLg^pA4Nh;S{0Hq%0zd%1Y3S0%2Bm5$12|XvK$^t zv$0#FlwsJIZ`66r6W#+0#`>}>%#3+0HQuC!8LY|nm;BjgeA43Hh8cbX`V`e}2DBM; z4+iDt!VK2AlaSFyT^5~!)Vw6xjw&iqUh791Be{7ioR#r1$tWq-mu1llIszt=RU9DEzVzg;kRAC~dWR9aHx-A$6A*q4l;zsifQ>)}6&h>&tQ|Op6RcT}E%g zo(S3wU-_A=^4(|BQm;SSMVn=ZpQmZA8qo%IZbPBhKi#xp`xMSe_g2i9@$~|6EEP2; zl^MF5{_WEZXWNbW#?jVdlYZC*T(8>9>w}f-t9@yxwW+Cg;}|OtGhdxsRp=$7A%DB{ z=Hu?}4C|aLiX&aL+%~zSONR|kAuT6SG}J|EGt%KV<7VB8vJ_^*pozu*zPo$pr zGlR@?iMiJyq&}G`hbvhSofCvX~VX!6qC`!NeWdd1n!V zP58Gdh()aFNGk#56wHD=2^pi_Smn3M$=oSS8Gx(=h2bu~nJ#NCh zvvD#nqOfN2kcHTQSNI5Ka-EsnUK3#l%~KMXkxjjMX%%$slT&g1`b@1E+g#?VeI#r0 zol(>RSEZzV4?l@wrZ=dw+)8UvPqOf06J%#3$!2{|6bWllaOlAGFx@zjQ*NZakROO) za{bFcv}gN`xQSqNyiC_Pw!-JFfwW%z`ji^j1iMPCWH;Yrq0x<%4@;U;-WbI)Hwg01 z^43z!o#aZPG^T8h>h}6l8}4du&{?R>7jS|i!w<uGUvYJSpSp=8%Ijs#qccV?uA*&=pxH#ZqDZ~} zS3;DQKU15Z?#$Hgj5*TXdw<59>q20$PbzJSC}6qUO3>Qe9~|Jc7ET(i2D>pICndkf z6T66NXH!n34BB`qiMCBZ+iatj*IE>2t30b1;LJ4YcQQyRXUHmIVN?VyLYE`;QXhMz z>D?-VW+Agh!FG97h=y~n9bes7Y>{JqSr%;>J-QdX{AtKfeSXDHc7iBlmxCwGEDnX# z)xb?08_sLvXZXk|Cp@vNWTiICs~qW2%{~(7tWl&HKTipzBU_DUeOV4?r7?)RZz7n} zjZXbhqLzCa(~&I#tuM==_J)jJ!jM;g7-CN24pgknDKi*j{nQ;JePbtJV_YfsU3(`*}s4lm(g>1 zYUdWCB__tl0_RHpy(N;xF&@WTVJr0|hLbvy7K{Ptry_hFlIQH#vQYE3q~LMAFAcMh z9puvfom<293?h}0zdK-Qr5_A()d~`ixzk$p5!14;P~cfQ5<9Y3s2;dH71M51XBsnf zFHZyX#_{s+sS_mV#c?$HJXXA~yeJFRW~+NUX3Rs_hUdqnmXyY)2hNClGY~m9cy}6= z1^U#bnfhxou=AfSku<{{X*@Rm*95bjdyO!2siq*q*MtQ(Tcn&Zg>jT)silny7}q53 zzRu9d1rf&T3C_8xHLn78qY7TF=Vl|@>~-%y8M9u_=C6#S7Q8ww^<8RW)wYJ$5kGLs z)?atJGuChEd;S{qe97il5T8%VL{C)zj;D|NC z_;^-yd{lE>U>6v*M(RNyOryK7$Tbr3kp$I6Mz2Y`&4;HbIrIEbg62Ye3c~E{+&Cil z=NEFqTQ%N~wXriX4#-rq*D} zueD=GC!Fb)?9Cr0dUkmHE!~agj-D}d<=V}wB0 zmo(dkIDUcAa-><+WpUgB_a^TZByN2ixA3SrQvZHsynh$78X?HnE8>V|muqOTEY8HX zCpyd54H%7WZzO}4U>*n=UPbTe>R=67PisiI)X}bpo`)XS8uiMY&ML^ zn7emN3N)y^wlk}f}8ML>3OkH0vWR#QbFE|8R1^!>T4;-2kc!OnOmSFO36}KJV^UGoL4p{uuBZ~1FHfKn z@zLP&<5H1Vn#&iaq87nr$#;KNwC`x<7Ibig?hN8dH=<6dJCNQOMZ^uiBnwUP9s60UYdfNob0;F zu++A_aSj`QTAF$4Y*R?cr^jh6cHSfOq7NsKNo*lA0KqDrjd2<~sxpEmxVEnpJ>~8s zDsRTI9T?8-D)pTgB@iRqeRAST(M8rrTeX1QW0Li<&cd2q>de3tFU0X%%dum#1PLnXSb`0~X5RUr$4YR^4@MP&<|`2tFzoleRWvTh;zx|0=~Y? zYp&KoxEE+kUVCR(z?EtVe>8!w&HV!LrL)pQ2EV^HTlY)FL`%w$sjJb#R}*inJnSED zHxcOr0Z!HF1bx0XAD^XJ)eajMP3RYcDUA2q3}%~=V?|P(Wm=leU1#BDl3FMxAU(f4 zKJKe^9AXC7b;s0Gp_u2A&VlOC#4$z{Q_g|8#^OvXrlg!PrHCh+BA97luDU^L$1@{X zMk^FSpX9Y$ieT<6l&exqp8G7+Lij3-H1}F)g>qKdd+}O>S}0egcu}nou@H_5v@L{4 zg>qAvo&GBIO9u(OrjUtRV6X=t+Zogn;=d+_}#fJI~rMv}(1-vs-_O@@dWD zXVo@!_<#-WR;P7jvG?lnC-e?gMs885 z_-{WakAQvP{=fDfdBnU(T>cQJ$K&bs=Nc4$WO8W8uO6Hnxy2tSRZA9wukY>c-LYpk z*tU1quF!VEL;M&{?hFl9^0Y_s^p7+aK2mu)jfCh=gr~dA^Yie>yUZ8;SuC%jg)fJ1 z>fC$4ugdV)=y=s1C{Of{SH=*B+C2u-?i-B)>&oKU(9B%*!%r&T1X*NYF7-pcQ5L@+ zd{v?ok;T3Gv3EBA0G`Rmulv2;PfLLF7 z);vyrGSGbFN9E&P?_1}P8vJ}0WnK1O&-?lNg71tT(CdvoYg;TIcXa*icY{3U|K5$r z7t_Fu^wxvH=aU?O@I!gozY!X^y;$E`8GeR(i2o>2KS7?K>U<=9|Hke6Rlcg7?|+b| z2fX8t$p_Y6KTsYlO%7FuDt$L?Sz2mNZ<}pSZCTc1ywX2h9f)Nf9U2%Z4VNdj^s;sj z;g`O?yS-IBj^Xv+bo(UcL7m&D8;ynA2U_)|ImAKl+&))B*xKo->-5OlYF}5sZr8T$ z+itwB)2`n>wbY!QzJ1qD_>yi%^>k+QQee+*LqxpW2O3jLNAa8^GoY z0%vTZa#_N!iaLm^k?w9lyWP0y3jNLkGWK|*`2S%%G4*C5|NaSnsg(xs%b!>Gc=rq>b@(J5ug53%O>f1o`9Y^rKc?bw-q3E_7vl}zVgBpz z`=_bAfsbvm-8$*Hu!nrO044ILY4KsddKUagZ1RDs|Pyw)!1>QXbxo&t81K2cL2J zx8pf~NH2fl?S2B!;`H+!=D!lZpG~FzWV10louJ=f;I#z(Z1oF~z#r4E z(oC(@oL_1vvW<#C?hpolCdhsan*F~YdE^l`w7F&BNOKCxE6R{10P_1j7Kfjc`unrg zw=To*l{`DBAM=CtCePO5_sRI>&-=j>((-%w9Kq)Y@Oc|PKZwsceEvQ@N#}>~8Rwmk z=j4;&-A}-~Gx5#vjyKIc$r}tggs&dop==ZD^I=Lfy2S1T62d^2k7W zr2nwW^jD~1kZGb?s!mS$gUDYQIWS(H7@ZvNFJsQLZWA;0sFHN1{?U<o9!B1*xAu+szQU6p)w7wZr&?(-gBaP6%Qv4kD&VH@lv%iIucfJV>BOV zuyYxHY>MVmrA>~70&uy8+#Jmmq?_h9S2K zX)YA^^P+E$jgMAG`$vZ~Q_=4Oj-MaRgx)gBW`T(jq+SqBy|p}E8LX5Ck{ma}bzwAn zfD}mB&}e_aM+5tqXwHGMhBd8mQ8bl|L!F2k^zU)+T3x-1qxsNRs}S{p%EZ{{M1`$Z zs#YO}q3Az0nj4}}#rj5>vvfm{ca<*pl4#EUAqZiAX+(9Fk!qz>?MmXM(To*%NJh}r zyV7NJ%4N}PfySV^3U$ikqUqzM+rkQ&zSA4cfTlcjc%WR>dZ$-c`toR=Qh$GWtU6vA zIZ&PmVYWnb^pB3-QYmBAY^3TLO>%{uVR)?6U-idEhbsMteWp^#N*SlK?Rq6&90E^S7zo6s0lM(m6>t8{4{VS%y@NXM(}WWtO}DVkn<;G zX2b-3;vgm0{PIf3S@A$HUgRE}Cv4 z7VBmUTVtE9*|unAsI7_01bc%Y&u^Og`e=T;@ChGd!su;iLnB(-qnVW^WoH{79fCI? zV9X9HN1`Vh#p{{DWoIex`JGBRA57%o-OZB5(kie?>~>>H{~U>{1ilNmwV z9nD8AFjP8hD|<7_?1|=tk7n|ak51bMC3OpkHp*qMm8(1s_2-+8*+n2*} z^nuj$zA(LuQ5QDw1kcLYAs0Oiqpse??()a|fb1aRFj#NNh&-1&M>>71&8bhr_pE zAE~z{%Kek$mFi(13Bq{5D*KfQ3~=!Nm&Sr2fmzm@B5ClbEII?tB4#*UXBaD05Bh@`qf~WG>IR((5`si# zgM%)3_Y9p%9fi4b@bFCiQ0a*A@bOvZF|73AQdq><=5Yl!jw#|C{cvD(80tA>&qnQLhu5B|q-AVkGL#_}_A?Z=%EJU<{IFj>G*$^rajrp? z)ue*yJvzM#qW#f9pL){ohn;vJ;5zfH)_Jsn=!aG=C5su>#4>OKsVx4tZDb9qxa9&P zVqdBM7HH|ps1l=*(edHZkavMD;xt_Z#&;;>gK7|2uc*Rw>A+AQ2%td*qtqW59T~0q zfhp?`VnJ<4^%z!UZCDE4f`wRClFF2Iri!Hzj#ZTd#tLN>SEpC8GIA?ANzj2<#(G`G zB!+t*z4*4#@moUZ({&=mHkiAq!Jn^f=%(oTVj0uw>Uc1-V~#VrIf8f5kD+?T#I0se?;%jTVX;=b+v0SNw z_R+qlseV<06kw%A)ucQ!Ijs5>A40IyLzr?4gNG@Z~ts_YPtJ&n)T>gN!S(nR=loqjqw!ujr{$Xi2Rtk$9} zVfsu^bcah%N> z<&2kat$;loI0%EG$x253MhBI|vB>qhNXo``G0S7AM2N`_hMM0LCZ58miVU|F*O)Qbf`FPQh)HJAcurcf>`{b~ln zQcvraTJ9SK^61#)*l=m2bfBy(1}X{WTN~!e zv3#wpFg0kQ0>kCuJ`B&Mqdqo#O-;LD?~hHY(&3evP`qU!7(2R!3_!tD(cx4%)NIUw zv7(z}qFhzW=?aCZ(D7EPG35g_#i8|ws;U_6v56fM4|Mzy46Pgtn6k=aiq;0y*(?+z zM7Pib9#G5IkvcpfC2eBx`qVHgJ#rmnJ56?@E! zJysGrn<|z<&KFl(sbQTdSWI4HCszlQ&Bm0|tdy~eGIFlNSd6K^+WB5uSeR`FQInJu zJWr)nre_-yGfRupEi8AR4U|Vv7DTG*S9XTqSF7*473aQ=bhGNE=GB3VG3a4TG^<@I zF>tdgCs)vsnZvAisT`1;@lrS^WwKfAQprP@cTHkcR2~Y}Z9VJKhsIZ?2=kj|FO}cu zbtO>De>(F+2A5=jdLzrO>`-GMUogvJ-4|4+R{j7wHJHb& zi3RnAE5sz21u&IR!K~4U*LezMpYo}*1hWFBG7b)v4yeJ_ua0UnQKc$Cb*ke* zJ~au4{xJ+Rt6(bEA&gU)USr8rDMyxKmcUfHF*lUogPor_%rckCp*=ZDL=C&m5|_%r z*-8bTvCtz;vxLQ%r7o2Vy6X^JMcV98+MBJpmAugNHHym`)hqieW0cuj{6TD#RXv%{ zF?QiOTX%ws(IZ$mQ&tkwFlr%fqn@wQoqc@3JFmxe{n$yO!(A;De3`8u2 zb`kw(n0Qvb9Xbu;5Ym(E`S1kh)o__(wM|JSA7hRjJZ5uo*rIA>0%plUg7L_QDVQjCUme49?*UfKF2&+KZl2h-Ip&>EH)$2^CsI(nmw=&Fb0=+6uY6RXwBM0nbP@Ekdwt{iY=_x6QqH{vveO`b~FXlgZfRZ5%Dm z!&f>5eY^v=ASW-dZ_mL~JoJV}VN+mrQ)Oe{MJ`(Woa({uJ{{Sf!l!dkR_ixyVH<|8 zY{C<|yYY&4g+p@IZ(78oF;a^4zLCi>{{Yx9hW1;pdYX^UGBD&<`dibD$~-m^&d&PV zw{PD89ld_j0;>(PEvOE+c7)ZTcSDg+cQ|zt8x|c)k$*YrbsX2RwL$(FD2LxUw^50A zus;0(GcH3Sm->}H3MO(i$7uE|YmAlH%u0|*^){o>h4-oj;1O=qD|$GmI3 z@*#~k7G`VpMyJ2kJ~-VT!7kQzvp#@u7xRsd;vfqdP^4dpS9(!FngCe7qgqQ_9#F!0 zJ6RMJ&d_|PFl{13Cg7j1Vjv2H0C}~tRgzEPj=pYOyGm%PEeJ#bM-} zY69|2n=+6WIQ1sr-NWd#UTwEB84olT`*4c-Q zW6A_;>8s0X_wEL(SW`~NSkrJmrfT{nRE`6XVm}w?kOeDriv83{m*@r@BQ>O-?J*QI z$ffwoP8OB4NFSrVd?)~==SdYwd7;t2L{%4M`KvWtFHLUi$8JceNX@NSN-Srul?Tqu;*3O^Pj)sO@H(2*B(4EchB#?_WN%g z*@k`N>iN5mAG>??gYVdU#Wz2(?b^vL|K)k#R?kO2`tFhMKJxy`zr6Q#Z`km@$G_F{ zt_8rxRoA`d$)EWCEgyUM!v8t_oj?25ORzDSx2tYk^`!s!+I4?=^oM`@$?eyz+kM}& zLEj&%=jU(v?2~$4{e-)pUp?nj&%5iv-8faDp6|P3%loEB-uQ;zFMRs?um17_=#Be( zSk7mjciKogY`*oOPk!rdU-`<{&idMCUp3}=|3^LF z+W+l~zVo>k{@?Zge%1&6;eYwsmbYPN@K@FIcfS6}_=ng0_^&_lTUS2vru$y}TS45to48T8 ze$(xU)P5A3VtaWHZm0L^6Z`f);r8RuY^~#+-a8SM17_+Fva2|MsUVHC@Ei!*msL4r;aNEsFjZwUZ4}L z`?l=}*}pW$mYJ$`mP=sr<@v=zc(VwLcbNr6>(GJC*O(>|7^Pe7U%UkJV6ihD6z~g3 zo^?FP9I)9|UsiueAqXv6n{6JQ{{;vN+O*TE-??*{Z;So0vpC&s6;V(q{)LyQ3M9{u zG>;ZhQ>X4EGSARF*O;p>ob)@W-PY>%-mQ(Ph2E#&qq)$_@4I`S*!xWN0MGd#_|gf! z>_h5PdV9C-+@&*Lr_z7nl78VA!z%39*_*QtVNv@`NuKu*h7TS-S?djLx(_zdSMWE_ zdaUyvgHe`$o#FAG9sae!I~G1;jN;(gtHNiDnh`wvd;G;SS?j#r7-RX@8Qwnq*9H&g zCG<0n%uLhT7~O#X#8 z^j{mi#qimQ@Y&14XRivMeG`B2ROdRc7pGPD*BRbc{nrNXh2gW8gwI|ZK6_*MjHiTx zci$5}`&9Vsv*ELi7{M=AXt(RX&hVb4|JvYvG<^2)@Yxr_XMY+#doXhM=bq^C*)#2S ziB#J=B~9cd=kDa?7r@KS-m1;2zu-IT$zM$QHu96b=zQh{k1ycoz5IKXN(=a~YBP$! zli;0m@JS9`q~Ez%zhf{=`Kxt)gK>$@e`zfLWAL57XW}eS0mT_@6D+Gb1m zyk{f-J`*XdH~DPxFhBLeTF{R_gYv0B@N<b0MF z(1sw3za%k>{+ld46m6x#~y5_)h*WAP>2Di0RQ0EW_0KS>5NV4o}B-zE65thbjGjy_-+zK~sl@ zes1b8f$w}bT8E>$jG0&&rVe*>pQ}1d;yd409TRn!)$h-B^KIM$3{!`ees1b8fbV=a zT8F!I8SPjZrVfkU=c*33;XB`Fdyx;v^!vxV`8HmG6jO(j`njpYL44=C(KPsRGnWmcE{_2=fMpx zXurMM)_A>o&a!B?Jb7uJfqbX0gDdx`%D}LmfHv@a**0I)4G}mIly67bcy9pi8}WM^ ze1?~4nn*jWcNOEEb}RER%D^^nE$!8{Z^rkOI#%O#q}}rtUH&A>|2>r7L(9r?^qVCm z|6t|7L67P3X@Z9zVjiq*r=2*!kvvbOpJKbel&2rN3af0dK5yOmm_qf?uDBm`q_6Tq z0&m-$nuKOjJmw-AdAt)m_-Bj9w^BY3>o>4je+_xCPnsToB||U4ckB|FZPezM77nyq zOAEpCm*M%D*7N?_e7!N-udhWhvPL=I=#67pabR{d%nhpVsAF40{`W5$okxQ^7OZ&a3gu zReaVjnAe=i0}POwYgC`<~AKeVyO5198&dS>ydczw@{HohX0F*KD4w^?s<|{d@hc!6Q}{-jDP< z|ES+FykLIvG5x*MydUfL{yFxZ>328dd0M~wiGJ@P{T^lRsr>r|^t5*6^k4BTO-_HR z-~TuLew06yY4Rr>d#(2~{qBG0cZt1#{KPhN{}<9ocRK!Q-v8sfc<;aYc`ss4Mda4t zXV+n!_dojmNA&xq{suQ28{QC1-iY19PhcDQORwu{Z;j4>n$BwQI=|6_CDe~PmY>vE7wLQ#>wJc0rrUXYyi0W6OH=Z49iUrokM}s8 zw>Oq|Kg#7V^YW8p_ZFS^idbIabDWEo`*@xA%9OmNSRJm`d7q&3QcrWfY^@iX z@oVv&Si#u8%DYa#zpb0kdVf2gqtBVPF#6t<6O7TTy`8$8UAi1%P@Y&5gRv(}3;b-X zr@<9pQJU^?@$ z4cX3pOh=#Z5A*eGRP6%!F@2L;qN49Gf*apC5P65?QRa50wtaNNlrk!-W zDToh0M4TS9^V9LJ`GH*NqLVmSw^+7MK(tGBQ?s49S#<)xSD^wfb!U69?vqyC<@O*R zx499o7kEaGnDIBRM-Cw$+wd?y?`4|>x`MK1=k4)+N$0&?=S`QF$Ywf^)&}3;*29M%f-S4^_A+mM2G@8tr|UC!`t|KNDS*4rgdL@2==1l3)drPN1H1 zT_Q?XlpkT5c`3rH<2DX9<96vXY5FxQ?Kv?#B!+Z_Y26n?x=g!`*N&@pF?5BzR|yY? z`3>LkSn<{54|x|PJcNE?@duAXo`v-DA!s*c82a#7(Po~9^$!vrx>A=-KUj64GT&Tm z(yQ1o9>endv1S|Q5$0K{4)lRl7bYON+T~cC;SEv?bcUL;{ve*ma*aM5!;F+=x#zq2 z=o_;z=_+2km=V{%seh1XAc#M0=roJ~p3w#L@A!cV zfD*?pJ>CdEzj(xNshi%9b;)0ZS=SJ{;`gEF{Lgh z$)Y<}rlQ-_g?=9tSvN06%Z#V-MZ+)pVpx?pzwGBWzvzd-JM-a7XnRwSSemN8!J;1p z?Hx9^dB=WkW7%n}dAHx|G*k7k4%TxP7pdQW>$-=PK$@u^eF~&2NbAZJpLZX3^V4sE z{9#ds9*v=&+w|CJ0X^ou9t+=ByfbO^s{pGWf<jl$|QnBKn=*ioi_U$*m_VEi15)Sf6}(Y`Y_TQCP(?R^E$ zOc{S>mk|WE2aP73_F9AoVG#6>^aSgVsfYdXez30CJtV0PCga!+kIznk$4t*S>95k# zkNF4hr61`J($bIa2Wc6n^c7zE5&hu3_yK*^J?k7k)8ym!L7AC{?KSVDv-QMCoU7OG zC63kW=chbHuk*===!3dv9ieBvvX9RP?`9sJ*ZA_;`JfEx%jX4e)qy*aq%j% zes7<;)1k?fOr`}OBYhcx#&n;u%L^ih1$-0YhN*W`gM;aI$q4wR-b;`66<{I)r4)Zv_EfYH*SV>$z6pNWxq@?vs-;pA*k0K4qV)H2j#d*EwdQYWABl_!ijqX$F zR(yRGhF`Z;Ahs%x2~&Z?=qg9pW|2IIQfjhA^BA3&#A2W)6}Vx7ykNbJj#PQo-k^9W z{~({ymnvTbH&UW1&*)H9I(XT3BO5A?tF}hae0sVH&{-91q&vwg+#M;-i8$GM?*a7=hosF(F zIFS-my3w^N9T6q0c>Ef}=v!Tej*B1E(db!~76kQ33&yXojLubgQzP*QWv0jB57JH* zg`d1#UIhN2yi>>D5AvNd`o8AXDT41SK4eASXWcWS?(6bSeZGHrG(8C8 zqXX^-bYzCx*X3UkeV?5Xy9X1|_I2K^cHVffeMRf3Bkc$EI%S-Fjd@iXri$FJ!|dyP zr;M_%^PMWlK6$#F0Q=0B8C+juWyRL#yUU8Jugh6(SbdhetdRP;-0X<@K^rYMo<4Dx z5ldgm$EgD8v#e7G(GTh;htLo5EH8k5kav0E^MkxrVEkC{e9~a0tHAleds$)g`A$~I ze5PfE%V%0vsC=eng~?}HR)~D2WrfFQ8g|F3KsQRSGXRVV{eOenTUts@+o#g9LgKT` z{?zwM>b-%~v_6%V6$YPWW`)3K+JV$E%c@K(O$GDD9$JKzEyE7wTmi8ZlpXpl*nr{0 zfXs-^75Ip@Cv8TCR7FH958`F+1^*G=LGl0F0so^R zRm@~9@(eA2vU1GV<~k?lX#J~pWEhvf#_zLX`@aTjkEAai=9|ybLVWXiN_cO@x3t*a z%%2_CJ7|N`x^cgUONTtHX|Gdjk(?)eSMx{5AP=R}1RSAk=HN@K7R-tiUmgV3_wf5+ zY@GN@E#H`{CNE3S?V7kNK|fEuDnX~E-jtxz5*H=t=dpVd6t9I#5>$HT4GFr;^a~P# z_DH`TAxN_>N6=-(?nY4fv5OJZGwW6a{ch}11eGswBZAJGbs+*}EOr@!D(76?cH#9A zD2IIyZVJ`+{x8}(9@9p3zSu*f{}=;@`tMsf&^;dZ8%DN8OgnR?MEd}&h_|}_(U`TY zGXjj_-7re0l6x!a4Mq{^!Gp?P$&No`6#mo(1m$!faPX{3|2hJjszUE zZ+aZyAWe<}9OOw2>Z|F`is{QbXUFah%0-;SFqRae%^#vZ%#s6g%}zPpwo z^(-1UUh_jekA#Cayim_|_~+mm0?adbcqshT`Q{wWPXcq4tCRYRaaw#Si1@GffVdZ`#+qe_Lw!`=B3~Jl)Xud@hH* z56VAP(0i7X5%6BM->IYB2RNsSbx)jA#kpr5A;!I`j}+jZ?=L&Jy>446wmr)evj(>2gx6q+(Ln@gMp#|Y$uST^xEcfhUCT!_ z8fPdMk%vYeex~K&XRzhAgkxPdvS#cO9%XA_xKvpGiFYB2-OOEEBfP|iI62m9>a95j zC95qo^%@&PfBrxG&Z81$U7q^`aW?Zj4Jn)*BNf2`%-xC)y2*YR&Gy3nV<@7*Bv!FM|d zeef(2WL~{<2Fp;FAUO^j$-;__+3Sf4QRNC-%X@fUAK$*jG>nG z_s8-(gMOFB$4k0xF5$EO-~r3Ml;0Ty8y5mXFsS!_KI8HbgOuwwE%6zy7U|R9`}iHm< zP-`xeqeL`K|9;459Bl45}v}pW_FFI0vN+f>83n2`@N>7Wy z&vG5&@2hf_6?|XIVtVZTKz@>u_k-uB$0PDX$#D9wE&)Jj^{1hY%^Lq|@ZH1+PDDHp z2B(a8=#T=`k?qG@0BE6oYFFXJztj^7G+ zYW6zwTwlG_QF|r6(d8#Do-^0Zg?uqL@+sK^52E+&b)V@A;V94O2hrQ|jO=%>%G0t5 zxwkI5ef%?)_QXTbA!KB7d-HL%Sa^)b(R*2X;dJKjUTr}xx(_T>!L6%eE^mJa33JCD?D z3QER;TN=7oNK94{mL3uO&A1p`*AS-b*!Sv&3B`lp+Jo;aVRhf#VCM;vbUn|o z)5c4;b?HCTPMhGJwY;VdgT3Oz_g!RYWX&by_% z&C{;VW^8!s?8l;$MRiK&uJ&S}*MohyJQKXoI*vF!#&^}du9|gR6}hUK-@DgT2Qs_b zq@(+>PaEBOLC~j7WPQ`6_4jT)8G)aD`kJ$Yb4n&wlc_Ufz#$y&{A^?1qGPc(uXH2N zHkr6m=ACVL2LW#pPuUC4j`RZKNV{=j0d4Y(aNSUM&#bE{cqb0-vB8BqFsF>ZJ=Htt zpX%;++|a1s!CIAk1qKb{@_2AVww6Pecl=4*&O44u4&e^OaddoL2CU#^gp;6Q*G}(N$N2m!3 z4{RB;FMK~_BRIy=9Y>5T@eHrNRwA^0Qf*hYE50jlJm-#xElS=D&LW;wI>9u#6wHz_ zt_A&&<2`e~E9{5*9;4t6C8c{37bu0YqVt;lcmF?i-vS?3QT;!8vLEii(Pgf{Jfc_*s9T zqN1YGii%q0|NWjhGkf>u?k0Tz{_f|qJLjG`XC7zHoH;Z1-Wk=qv8N}wamJmIWY11w zzm7dONz=y}!}d%iJB`B0B>V;_xAuPmB1*z@tM z&1vXaJJd0>DRlk^b(-(4ma1-@Z1W6J$Wb89&P4Fm-t2)6S)WbkGd!JSHh%XkH0Bat z7uw*wgPpX^Jf5dI2`+l16YCs3&WSkd4@jEnx+b%oV}g4=F$eia#)NrR^iiy>JN>7* z;Nh5X8pZ@S5BqVsILfJoIxn9?WDvkOP^F|F*GMAEJJI-peF(a=hBs$ieYyAM#F(7u?t*UOe?6|Eze+Uy*lGyv0>2j#D-Iblk&(|Il0l# z#LnjZ^DuU}IT~@;&w6mvFbs&#>&N z&2KH~54t@{!((gjzI#lkf&tXsZd@P;&oR9jF8^=*iuP?0Q zy1s!f>VdPRvHpYF(#ZY*@~s8sv94pSd{66q3GO-2wy|fVbAwxO&wXoqqR7Pdi0oho zj>752$w%3KoPZ>Iyfcqdm4lP*eYl5gaY#hYhhe@QScG8NoxF;S1DIxWPjWYpP&0uO z@^E5ieUc}RscvEp?N86kE?w5p2tMj3#>FtcwjFrtpR@Zbr9XQT9qw{GPXBm7AMMfA zut!eU#K&9Trw*RoBk=~6!8|Q9-m_|J_l0$3BF-Jm&SU?w%}ouf@SbkY7rBV#f}zYE zZfLDb80E^wgAiG^XYkCYRG*K?Iv5@zEJt_kl7F2@ne7;RRy z;IWd9Tjl6KW6F$y4d>dYYTE5*GOp~oGf^9p=QZPQo-H%i>LPJs>#^n(#;5Vkmf%?j zyr(3`hS%A1QX5iDOR!?$Y?koh*mf?8>q)9g!Ls0eP+J)qD=tE1Yipc7J}+sf8yZts z%)uHy4$jWD;h9c@(D92No{H$kFWVT*tuehcYk69iC%q2m$ETL&;wnvkTn*B#l_S$# z+POMprJeI+C3VZnJJJ@^Rk(xILtIFLZYlqxyTnQ8EtlDNBh0S{PW3LIb7pl=jCUsAeNF$(lDk7$yfGp!M>q(pC8A=aitF1r?_{pTv_AmZYRBt zSIXjSEbRszz}5Y%D_FULc1(+GZ{bD78xJ2Y$uLi*Qy-C<1UA)aGssrJ@TEu zE1$NjD`6fj{DZl3khbHWi}dZGNxAV*aeV{uOPx*>^ZmkYv558U>RGo=waVoqK9IC; z&Yz5zbBhCILC-ny7ec-=_wR%2v(EO(oPWfw;q>5O>Z0xu)G;zJL?6z{M*0z*DU{8%A@}t2 zIvr}Sg-8efi>wna*Kbs7&sfd*haTZqH^C$P){ge{cCDU2Z*9-W>fE7fECcq47Jm%s zw&)Rq^`RpM8+$s328IXLjZ`o186NHEt!^6`#il6La~I%f!R589*Y@1Y5-Y>qPRSK#@N$S&M7JCA$+hclCxKPPSv}aY;qu*10q;s%SzL+YRL{ELwCY*? z1F%D=){6P~t(;XotGNrmwR7;d33qiX(oOSm^jTdN0KPbG1GqE^4-NhuPmtz49KXh7 zYdTq1gPRQA07=#XP!ylsW%Rh!vsX`tvhh&N)zd>1x^N*UvVtVpShsM25J*OKI3G6E z1oCVxju#iV7$bRec15za2@lGAfk*{)2BENJ8n`cot1qzh6`Jd_JleJ8>;*v7HYS&) zxDH;IZbi0r-PjpUvduQu)FRm>eW-tHrgm=iti}w4!mQQ}o-v3MEqjK$A-&Es^!#ms z*9{D{VP8CHOp4EX3xcroBdpMeY)A9?YjqQb&T}(t?P950PR$;RN9u+%k+TLbfE)IC!7dB-*>5u_Dz6| zHu7*&elYhx--@x|di>sq-<$Be0l$kOj~fx%GKQ14Z;ebKi?OWeheIRa#5X&8X7_V8 z0Y|`w4$$1O{Z-nIdviQN9z#7HU28jgd$2Y(yQ^ntwbl82{9xBw?r~KHnO+CUy#c?s z;P+Pi-i+Ul?d@BiUVh1;mzb@o%9f`fcXQ1HQ?@?4wXyR24ZPdhKBe{fg9x4ZtVAQ` zy5y9t?UmPDiS1y^=imQ_vTGiC{^B#Ame`BF#`KWZHCG_ES`ylNel&?x<%5f-FwGp> z!|nn<*ta%LxvmnKY)wtQuBM!&(Xy5MjFdt1dvNhoyi{m3!^-?J&%ZyH5$LaZx^nr0 zsppu$gQ=YiwmzFz$JgFJ5=eg6rJno4!AKLb$s+)MYvXg*HSUxm?!2z1vS3ZOE}nYv zH4jv3vA6#EqOUQ-+=cR-kJ8v;q$;mV?PO9rx1L|#x)pHc^FO%efpRDN_MH#bz)z8S zB64Zv`FX|q!vo05NeEeewH&Xfb2}p*h4C`{bEEyqc$Lm>F+ACv42bw?c;&}I8vsEw zKsVrVS9|EgfOrt&H1jEsdkhe~DsVjEaliM_K4=$~8QWh2vbh}wXn)|QnG*p`li0aF zwiS>~Z8o&b9jVI`$qgw zeh~-)^P_{!X7&?`s=};PC}CDB6qwsQ?sks@AlDK2$CFgO@D4ie7UNa9!Pz}sH(y*{ z^8E9x&Ej?VUS{^3Id3k(lUl*d?!uTjf+-3vmZq%aVuE?s>@JS4GunuR#}Ar^PJ{m* zN0T9vQY$NYv_FpkH?v2&uNaxpCwNM}tmJWINd^1Iyslqb>M#vQhO!dZc2}MH^Ff<` zxIC9)CpE800%i4)zQt8bxovw}8ix^UXNi<%mfkU7Z85`@fBR=K)E9SI47-oJ zEar`RTaK2un0Euyf?p2vN!(Ena+n8jcYhw{C%Ahi5Az4yZHDB?MOg#FoxNOM2adr^ z&%?|f8tI&oZoGh8-1)Vvge~Gpw8X}+qw*3OBU~BFRS9e%uBFN)G$xC?Y_#8Gvps!- z*=+t3?!|MkWFq*y)#}9y96GevkVA&P0$V(Ho+FKW&zwA=J=A1Rw=lwO+!n^!jo88% zyZu}k<2PdqBXhgXNm1dBW@|TecV3zr9z+>=%MCY+7 zULC&Xo_gxsxu-5XZQ;Bywz_)moH+{@E=0KK^wSm~tgc=YG?Yv>hks*a^>4p`??<%N z!Zv|zPm7S#Fk)~8Q%$%Z61C;W*yRps{Dvxv>p>{zVl%Zy>BKe=zvft+D72GM?h?9? zePB!*mieYkFE!b>+y3(~{V7Qz6d*hum zj;bzUN2Vc0)%{JPil&91lknttI6aA~ozFl2JQN1IhY!PgHCJ)WhxyONZ%e#9Xj*nv9EU(0bS11fI=XO_J9bSU9WE#*j!N!gnJ6b({5nPc59-Tu z{v08ly8lIZG{VOb;&lk~1j17g{sJNE@=JtK`7A48@6DIbF}Qd7aya4_MdU*s(lGq< z82R8sfS!?%!Z7ui3ktKZnF3Yu*Dl>sx7eoKuOBYL<;Kx}flKQ;ZQp!JN z!giwHvq16ho@_Q#UhhHpG{QR({z>ouh490;kG2a(c-D^!!;5-54WVn7djLoKF?mRH zG{R>Jw2N0<*C9Y3zR)b=ijEm3)OjlvNU7dy*G?y{I5J$`(_@jRY* zo!kS#p`1}&WBH@9+gxU4cQwL85x)f?`!MfW&(|W1%B~ssYNYRKMqLZrfMXD!jL42W zq+xjTc(Til9?T}@+Dpcuu;8OZkuwG@d(#+1+lR7=w$BjcPq_^v{4>I<5N_A|{~&y2 zO#6&yqmMv7XGGd3Y@>HX+h=H?7vHXQUix2brJvc04HIpbI2-*n*c7(Q0|;rOzk`rA zn)kHP-$fYhH{;pp&w%grNV|k>^j`|L%S&yg$J&}WJN*O5g!c1?2x+H(%zK2qr=9)@ z!l=yJfS&=L@VG`_#f@tV5Pw!gX5=9a!@oymhDTZh{P-}>=U@&o*IqI+g?)}`Ixx~% zV8N`n5NCXzhD-6+3F`Q%wkq^QepSd5iRw6I6}3ITLwit;zeo5i!e&M!uxG{G}x!Fv){srM5 z5&j1u$6nrZ!Q**^(e@k9w%-fBGb8O6w(ZYF+b?9NUTW(ewH0x;{W;hIHs?PO(zfs9 zJwo2ow*MPpRA!WYHFyg7kw+muPUoE;`Om1#`mr*d#md2G?~6B~+;t!F-xE~mc@Pb* z;uFef+r;Vf{uS0&nTn8ld>BIdki4f4c{svo+w7?w|5vfL*#(6zEZ!G>ZgeE%LY;m& zLfY}85z>zHo_2gX!l>L<08ekCkiT*=;-hweJRD~k_DAJ5j2H7dN3vaOL(caL>#h_Q z`Mx15j)&BR{FMDCsNkof&bW5TPoa#We#*hResu`Kzazn;5&i=q?2HN$_8k=aP!NcN>P+FXLB2D}d%JB-4_sx%h?OHuUk76GRt zp^!=!UIdJ`4`mZ=p9Qcjl-sEYOAvn!!ZL)s=R^5(5k}jm3HV|<%{8s)x(s=!2j?LC z&$#Wg8>&4<#Cz9nv;0xn)j&3^Q!T<%5MPgwJ`3+z&m{<>vZGxoX15oSKcd^@ad!LC zF|xx+nVlQ(Ax-jCQS?ltW&doQOg}XSk>a~~Vn}ruvXm#9tlSRVINr@`fmDA0^j^W{rU3i?7s5(?p1-zLj z(G&Q^@I-n-X#V-LiO)ad)?Id@y(s5@Bcz|c57v19qW1=}4`SAQ$D4n~t-FNhpIeKy z=PvYu!cDR#y!}ejgJSsOl-@-%if&PAa?YWM?JlwSh9lY)+QQJfnCB*pA{+=tcd|r>IsBF`jz|-}yZ?$IE^>(Zu`-qxG z@e%Y29{m;9ndISU)YehHQCo-C3#D&dfbeg~wFlvI2zfsV^myrTOdF3kPJABxQCk-t zCsq}0<6Y<+gmXDdC$)e7e6?B2lnV{jHhzm64 zSuEug)$LH^#EP4R8C3rbyB z%zL8L6Vd4fkO%8=Dnjb?B81dw-m`9}BaF(6>tnQ7Y<^zRb@p=+AALSS9@=|`mqq1; zZ7#a9QN?Bs?qYAz>qS;<=kw4yV=t}sBix!Z{}n6RWiGN$o1m_ToSerCIyup{quipp zevbM$=OW}9`*{etHpzRgu`fdyZM*Sw{a)}z*Ve+iK2)UbUTTGp%8ccX%B%@8p}sdG zq`tQzq`vc>`rd{xDzowQy&inU^!=i!%*4O>Z_#%y9XdnK^&2=`IahxIYR?ln;@pww zyIm7fd$I9%qkY`v^qwNTLy@n;I7?fy6(Li7Bf=!YHz8bt@CJm92yaB#hVZQj`Fi(F z2uBgV4dFEi-;VG)gtsER5#c)!-i+`zgzrN5ZiG)Fd=EnQuiFu_f4vXkKM}qkA^X_} z5Jq)oPy5-LB0BSbp`YP%73pUmM#z447ee+k-m{;53}IAeZ0l;slVdTj=sQu>h>y-A z$m5=6T^^Mgw!9hYez6~B6@GvlH*j!a^sosI9P_MLiayMW+CbNTFeUTvMs~x-QD*B9 zQlAG9(ii1DpJfdqjJC~q`aGWhzo}^3?1DxY7Vn<8N@IM>xUpjxa^cu9f{;4B5g~P& z_tfbt5Ju&;0(iRUh5Uc!6MaTP9_RnRWsKZ5jE>;r-jBc6Uy>d zgw*r*Bcz`5o_c-C)bZbUN%8}o@Wca$Meg5@oq2Ym;32EzlR{?{F3*aUml7u+9u=a^C!Vq z%w~TiwoP7g6`qhE@-oPSI(!5|>fTWZsl&Xd4p$?L%4<(`_!Cii;W2CYS!*@Q6Lak) z9o~jD!}u=?3hD4GUSu6!0hv>WS0dyZNe4peFz>0uYY|4}4zEK<9qvI$9p*iC_!5Lsd0k4~22VMDyrS!Ud`B<(Oqo1v7lv0w<%JpJi?-ZH ze}YaX4>z^1%g6c?T;Dr-0=i4TJA)staqaIMODF%71AV|U{MF>>j~UgO!JfsHSkgTSNf zXj~~`%5wr5`d29Ncpfh`v<*L8MKyHndq$K?be{6%604*4BRmT6KSId&i+Inrdjw(B zUNiyEb_uVghIRH{#6{Oq$wQiR5UwxWHWScTj!ewGh>3PazZ5 z@EC;rrkVHrrg;X!XdAH&i|KXT zT#h`{1@@V5j^9SRpx=eXya(z%Ms}jND1Z35)bWrF>ogM~-#t8u_Xv5zmR%gz8BRyYJVuBsBX`L4@cdekB~m` zSqSMX@SZ;L*$AWUGoDZUCGbVRryvjYfPUl0#%-TnQ0>AZ-V@axquVThRCbFY8`dd_ zkUm)*Li)$NXFXF0qq2KF@H4@~by;4~_pIs=AAKH99=;pF@H{jAl^f+>4W2?eeI(+e^X;%s|1?%^>tu47`$B>_ z#9S|xMnAMSHF{$6%6CBa)aiF3q)vYrA$6Mf)aj2PjJC~qI{jIs7oGEyhdRLaezZv2 zywn;UwF4}7)DCQIXc=}AgJNnEptk3@wE3=p6g}s6f zN+Co2oxP~m(e|N?qV4klh?B-QQ5r$_-gR%imfIO+lb-gv9gP9>dG8quDxWd z-7J2L%U4LLf4CQw8r6#GHRTf3>pwyEl-ZvVazDL)BYZhR-k*fhrIQw9Wqo zeLe{?p+29CkotUz%8K{Y=Q#+YG8<2yj{#qFY$K1e&%ce8*^Bw`kVcqRte_bwWTpRi zZ)$ba-o)AH8pxk=t3^niJ|7`^8BeF<_D~7i=%>bQpO;#*$Bu7twz?g% zp>8inNZnqgGUGjU`vQbf+1&vA$>1R$ujrl<+~+10`IeqMT$^I}bgb;;1Iyk4yrtBI z!=yt?+RVybdw=P#pnAJeauj)EF|wmC+dta37F$fvU18PbBYG57mIMz4Vw@#GZZh$! z3HFUvTVbxB6y9Va+BYcM=vaIi+K+M{LO2WY*C0FvA@9#ZxCLRfeaGt?_anW!Nc)ES z#vdorzAth2h{`UmZ@eC|VMAYwkbPq-LfRAFvu|9FFe#OHvJ z?Su{h1*^!;K?GL9(YtHy7N;_I*^$+pBdo|{iVh{L<&EDC(< zxjBvdW`ykA%Mo&+e+5ETjFTK)4>^ zj}UG^_+x~ZAbcF*r3jxw*o%<+W%MEBbIN{%T*n(gcm_h0VRH)MWeCqhIE?UogplXv zD-oiRHgmpzIl|W>yaFNZ%qE04A%sjf-;D5;2>*)wX5i;8%7GU(hZo=9DMN@r-rxBE z!iI<)ArEN|!ml~n7kJ_fcHPHXBELr%9mct;UGnKV?oNOKK-ZDHB)JeINh(Lhqzk__iyidbADyJFFnYD`b`oW6u*(>GQ&d3)3DU775=$1<6McO==a`y!-F4n(-O?aJU-ndI*Wvv-AZ zKrx|2^(4-&EKr%8if|2Na%PN7h%aVW;>IBIP}Z&Z4Udt@n7s`4Oe*%R(44hBq?lCf z7#+5^ENis?T&QwcjgWO%8zYw%;OQrDEanw`@Awwr>La#=Jk#*2!SBkbT*fThN62>oqwj{1hcpbYo{${G zL#qZ$%mp=wOwV@d*3IP#p1wz|;uioj3rI7%N6tK3#^SGbj2Y)Ci>Mxc4)Ug)K97)d zm9NIgpYtvD57$Sceeo{DMbGad5B0ke;cLc|{{+?{#)yzhLo}Rrc;Dr7&cgkZWsS<^ z>yQJ>{|$t!!-Fw$8AW_C+kGeEqc(~>wA~!*Upq!F(S2R>`zG^>xyINiE(-q(+B68_ z@bqCpo_6I=A9jE?EEAS9Dw7?M0n7duge?C*Vq`*mF`2v%@rxriEA01NAC<`qHf=bo zh&0BIV=QA-9xp4i@;Cw^eV*wEqdw1g^5Fctwun4#h|0rnpdxSc?7o8JR)cb5d$OoV z#@LfMnbfFEYE>rb7@4d=or~$nU5Jm4Yvgf0&rMO8M9%|!0YuYOL^RR9!?H$oWrND4 z2VpDX2V&$hp03;hzM3Msa%)sBZWodlKpt(oAdfgbd6UZH288T8Z`%!dycc}u7Lmuh zqw>h@p|N-S&4opTfigz*BTgQlR(X6z<#FF`$YZ?u_WPsqD6s#+-W5(~QQ=HPHrrG- zKUdlODn>SIAm?H>B~Dk!<7~>EQQ73a)!)0~7$_=^F}lJsMr}zMz5!sl%MrFB3}U_s zAYUB`5WvVnb# zolLO-Vy;++jpH$&W`-TMO?xhnMwLgC$|DmakMYKx@qCm|N97^s2zIRj1=Agk#i|%nmjx&cpM-f240gV>)awobUJ#ftp%r}1rH_x$qxJ$ zTT=O_oM_wdc-HSZ`AW0}W%w$De@A#N!hh&J_qe$(rmao`o^#W1TXF8@+UhfaqkGDc zhcx^)=W_+yY626}@x|?4V%UwD>R6ev+)bxXw z?#jNz@qzx@=VN6i$4$N<-TvALdGPSdYSeeh%WJ z-(iu*_4zN1E0g~l-Tn=Evfi_9KaoCv2ik%%`~X7s`TvKIeV+I1^LHbR>M#32u|EGf z@JGLsA&=|x_Z4fam%iJNv6U=)wBLUUa$$Y$LCAjpS%mEOyl20^7hzOxYd}x^rfuZK zaZP+lz#P{;ieI{jU--pXxeX2tbaoF9cfTNA|BZR-nBVm$ zGs5@6x>D4=e@mV==680=D7;1;_ssRTkO9m76hfB&PcbqfzL-qn)=|jAbX)QJdQ>I_ z_Bz@9iBH_>{jEhLGj@%MGs!;d}u||#$mK)ei@qxsmdj6K#Gan=hzrzOoy#8Bbrf z#mXl1&E)P2CC=!6znD-aqAyRXOn$90`NIn!lV8QkB=p_g-j&Hu_f#hP;hlZj#r+Y| zt{fEe4nOs)n7xf#zYh1I-^9vfoR@%@Va$aEIrrK!mfnqhKQ~TWwiT1i*fBb;4=qyJ zoUXDtH%2yBpp3<2b2s9fB6B$MQ090y-TW?AHgVtn>|MqAMG^5t`x46=9gn(IHtP_w z9=$QLSp$4A*}Na|$%t&oL)o@CX}mB&pgkGCOY z+26Sv@`zj8XI@So+oSRr8tCm^+tGRHp04f3N#sw(Br>-Du$)nud`@NZd6miiF*4Zz zzG6BOHwKZ1GQl?@=GmxBIz~qZUN}AZOEIbJKzYJG3(Fam$>S=MClIpyzlo8_8sLk` zByOHa9;YY&h{~j&--%!h8tvWV&J*YM|Eq{lqB3DQqcWLr!tI&+l9mxbe7Q+4T9B{)_I%EJUTsU^s#c|}u0bF!{3nMwM>ObU}Z3S^W=G&xL! z>Nq+fI!QCE2ovRHSlis#(%h74%CuoaK3l!YFmbvG^=xQBt|7`3lyaXiWhn0uDWy-D z1!2nPSnKq3zJEK>eCIWretF(M|+&o?jNQV8MduzLh)0r$xOPr z$ro^Hm=1Nwr*iVB3R6jH?JZsbj@B#>2ou?O*Zhv;z%U7N3#D=xQu!4`UuIecHg*rS zFZOKAox? zD{-e>hlI&(PFBMjnrp2bUABjYDeF?2t!s_L!m$(_%EVl4|8B+Cb++(_hw0E)Gf?%q zbX!YvTbiww%w(X3UiDuVriLnHQmw72mgd%stB^Tf(>)?gS=#_5tW7paXKBi$lbM_* z9vLP~w>K?oLRZgem$NA^50hDoL38D8%2DC?*5nFbAlG-Q!vtu`m8fwGCuWCytFHg9%P$Ra{=`#}%Zswef_<7bI*=od>CS!kGmLA;ZR& z3?7wQMLMA%VM8j}w$wP2a$-R`TIMCK$-0!6_DNw{72?v?RJ|W*PR=8k-;!OL0)MM- zjalLNHb@mJoz-UZtub3`Fgr{Pv(=VvV{aHk@0$9QFnxaFZCQ*7%`4D`PPOKQiN%t# zv$Zxi7?=IrJc=E(`OhQmrt5S=TXhxjX99 z@~E5A_4TQ`?3fYE_2)%l>V*qx(&%Qb&2&cE%%R$%c{CUbGhT5{4|9WuWvk21@$qNG z#?STfXU4|Q^YLfJ#?SZhXUE1b@bTxw#-Hlr&y9^==;Ig1#-HZnldNV@hNOvP*L?NjOqB4dsSO@MY?J3LXRtPxcT$& zsMOMx3a&9}bN;z-wzoE10GBVz5w{_WxTWc)l%co4_!8sd)9Am+rc_4MjZvjOD%08y z+fnD4%6tr%Qmtfq8Pa?7AeL0qYfUYI$6cRnZ?Gvc(r3oVrOO%`&3v%kAbDy3gc+$% zFUhuHc!d|5$~L#c0AjGuN=^;QS`>qM9VlgQNw&77vY>5lN~3n^3sTr4!$y`G8(H6) zhM&~1%5%X#60WvXZF_4vvnq=M`^a*QY;A7N)HT<(H*zp^Nlwy8A90Z8HCZE)O|?s# zTMeBxmajt5;zXsg={5{-Db%dR4hbZwbV<_T5fUY!TSS6=l%OSfK7$wDZv4O^- z3O15tm|$7ngvQcFVXp*>oT5mv5v?A*uS3I2Z%q0m_H*bod>og={)((?ZiIRE;+d*w z@7mGXVI8VmB2MDU=+Zkt{&S%BEJfq^&ES#oQ+) zlM2R{YJ3Kj&NkO)X(zL_@DrCzbRIGg<4( zX6rE}Y>+<4f=u?QfD0aCN;H)*6|RWMCXQ9m~L8*PGUO{)2P%m+A-W` z(Ti6!w=VNp@1v1WTRV4?!JlkFE=K2zDNL&~t#)QdibRgW@}eKZ^t8075h2Z#aOOhg zv)(tyF1h-j z#h2vp_3cfyBoaeMp3+?0@+2$~q8wXUE{fX0Ij{(bY~{JQbYlyg<#YyhZ>~8{{Lm*r zG08X&3q}`OMAO>_-DK58IeLk9YH=Jr{r(-<&n4o6?z@ zBVyN#-hBW>ROZa84&_wF&O2=rklJ=$cAF7lbC9KOFfL7BuoQFRt!~ntXP%Gh*2lg zWGTuj3ZX$7k;n=ucFT%VVK!r^4peaO-qNh4muM+xtIXV zi{odOkN#On6EeayYwpqm+0soXauADW1-!$f==Q)|9?Lx_vzzR!w0fLsH@tiX{7a z5?B3P{Z3Ju{XNan3`TJbe65@jW}%{O82#$9DnxN7nCMi`(1!6Q%SD<@v(;N!RwGT7 zr;#>JV(!H{z>}(7W?aq(c%mh#3`KxpzY%NB4JmQ$;2CnM4fd^Ci+Z4E$RulOFrBMu zZC=5ZR2k8j?=(*#Q&w4%ApRhacPgQx=jejPZ7fpCk^*TD9z)xZT9U--4hJ+e3C*)_ z)I&UReKS_bvuKLeEc8R|t&BKK^iWT?vax}J_6l^Ek8wrIq#EFPg$sJe$nkF>PpRm(;Pi(t+PjOmW~nSc(d#A&aFKyHJRMmxBRgN(^Jv8qj7l zQH&6|M3DfuTXI!cEP8h>6;mdKu)^&&?IX>;Rs259Uhq69-rSm^ zt6Qa(tGQ9?Ms;J_`&hJVNMDU0A8(yA4pd}HL?Y{3lS?F3YS9rOz%i?h4HP4Nx~!8Y z#~a3$i?bW>Q{EOIm!OZy^E;406nQ za&WM>r?Z3Sg^7}!#ce@Nx~sRlZNunD*TBYpnAwV|ELfm%nQVHVzb}*f1tK{#Bx*-v z$x#vwWfwAS2V|ssrY4bgF;|w-Y(FQ3d#WZBP^{LZpZPM{JyVnD2F&i-F=)y<2+LN< zveY1N@l;6f9cOn_AGiJMU2!HHWj_6X%oBYu-MDn_df(aSzml3Z`u(7NpcG5#!F*oIzRWWRL374IIY7bPIKM zS+>3%ems3e;xV)V&(>|@Bkv|Wo)agEaTwGP*OXcTeQ{GSxNdD28M$Uf5{zshk(qOp z#N~i-imA|T;%XhHw;3~6*)dEZPSy*_j;Dk6F`u{-^57ZWTx_>^Aj}b?6j)L#`Q)jg z9@SjJ2NkU{lxDe#)7+ksE<|F?Qb62}xiXwFw0*J$PwT|*U@RsaEE)U-BvXSWJn3AN zVCiPFS!5{7UUmR{5O|zbys8becPz}~nVx7R(U@RcG@FZ~8ci!BFvYeJZr$IQN`@?e&2W6-)wboGUJOtKY^6##Z$GEptAKqS^thkEE0!F|9GnXGARZorTW1xw33 zi8TA=(@<@sSvP017v$S2@*OJ+mg^Cb`-XGl1PG79UsD4ayqHML1a ziN=DlL#JDoFYtIQ7l-f*p{n~<&60tI_3Z5J>Fyulp1cD?!zg-X)rE)~9?AA~4E1z$ ztrhDMlM%#58AQ-3__JvO@f8ptgGPy zAXbWDwirp4m5A&N@8k#-tE_6bIfph8z=lT{{Dx2$%hL$YIGh%?ZLa!P6|$GL4tVHT zbF4>BJ~@;Ny+qy_f%gr64DX|~`dXl7S9WJdFxFO9ZG{M>+S$JDJ{+_>FoL$Q)#&TU zvas9^qo;q}0A6jA^tsfRja!U_sjsYh2I=9^7}u|@h-~8At2x`rWJD03gD@GfiTlIy z{U4af%Bnko?Z#H-7LQE~<;@^&BhZa$Ph}PN0kbU8E!$)l^kI<~orjT*_0Dt1Y#Ox9 zH_KLZL&xw2Xkeu*WPpy#5fIgK!EqG|IBF|BeOUF%s^0?V<=iGR9EBzfsSJ+=Nrf-h z*sVIXWNiKYQL;Kd3ryE$ldY}ERj~V&RXmC@Cx@&%UsCxnBXrZp)`E^r!OLj?Xb9;+) zH(Jgt%yL~rHeEZ=)t%P8ljqEtGZ)@KWfgb7Z=u#parkRO>)s4nvu#CE4{*{7btx!R@K6`WtfM z6DO)Tli;*n>Tz(s5c|QC6D0cpTOF$2wF#S%_jG1EhK4#eiMIdV7gRP#wmW)hNm;TR zkfm2VsqXJQ2JgQ#)Jb7RQJ7I|r!2jeHRoK;}G_hC!aS{NLhZx)(}%J zD=VBIaUL$yBQ|Y0xNXAn$`=zjfbGNf7olyT80jv;?9n2^gQ~3Jkpdybjl4=7>KRPl zn*-U~dIs1_@y=d|J^Y4Xs6nYGmv>~jxrPXY6{}e#4~{CUra@xX0AbtgE}A%u1C>=z z18q|t9mE?;@+#)Y=&;m;3gOGbP2pL8+ACZCwoIe7Z6)C{4-9hhG7N{Nvg%{u1T-R~ z6VxE2W<+%Cyi_e@2+fiFYjG=M3YM;yHe(HfmhpX2o15ZdA58o5`J#mjy`<5k{p-84 zvP-y1iK829>}mzWs@1kHqRKcx-Est3`H)dM@I^jh*(FL-q|w{pW5({6q+~Q+hvmq^ zTd*nx>&A5#S}XTdSJ!D}5TSf%Xmr@68Eb`jM|%3YvBi3)j0#-XZ|xrJ?ZCIzwF5&- zyM~%Z`?`mEI_tXE_4K0wsjW<;PCD&zxVr&aa^i(oGw4jlJ^Gc}zZ^+Bt%hRPwPMkc zt3H)gJV_>`o8d1gv}zpLe+GUrf9|=RUz1_Qs@Q|t@a#4tI>sWxRH}#iuxoS zgFRxnIReKHz%(26;K}w5bawP|i04>NjbhVwWMvfY>mJ!K&^0V08NF1@^5i)W^}GzE zR?lhpB{RxExUF9V*Qjf#=W;kFR4eX@V8tMt+vr9YDglnN?0|4aU|Q<3SnQHak8y3W zaDnv3eL+JhwehhPAFSJloTB(VS1lxGJML@x9AI7%ipOq48pER9toB<%+aFV zwlY=X8J~{-WI)*|e=e$l9Ze$s2V3tP&yY7lP^tOZP0R9TnZH(6jUXfVv;8>ULR9`T z+^_HhC|lO|@3lSsU7~X|+d0(`pN&t^#0e9LWk=vYSzV!L2U;<-?6=c=!NjoVm5z=p zpOCU&%aikFdFU)dIUOor672LoEJ|=GN@5$jV|Y`4C(jq*nF^u=Pq-rGIptC`DKe)4 z&X=Im4ywen8cZ)$_|0Zb@~hzQfSlpZnw)} zN%u$%>Ktr6Edbwy=Qx0lK);R8AR(~a zLr5_~m-&Qc^EFM9Sw7@rL?^Akqw(wl2XfTNc4B-}dmzUb4UVqGYMXT5q6AbvuF|1I zp#?herzy)8pLukjNi6}bKM!RN3EX|ys}!7na77b2;ITv#yg*5v-DF9QQI`OnEZI#c zx2&AvvTy;kopn9hGsM_p3YY8I6s}*K7H{F35D}-_(i`~F6G-sZlk`4{_)9=JWpxu0 zXFxgKYxmi@T_r>E|F@5f@m;7BoP5DL!Z2pJmLqQZDC*XZu~6J}+Nsxqh~}}S88150 zd-;P;R==*%EJ=Kuc4$tl#2u#R5FRT+jsr_jZL7@Zgi>dw&u6UpPgwCZt)1(f7_3=3 zs;sy#GlAKx#mjT?VZ^br-jK89(?Q8CHLNm-Mb7PxqUEQz%=H1+(X=bu?)6vC9Qv#% zq(|(vIZKuu=^d7F`f|@^J7j2*t<3C)l)295T(_i)0o9^RT`!d?)9zBpGD?bs`F;(w z1`?@BHo(qhQ%kXO3W2rB!12yd2|Bv6)=cIP9PBAS@%At8xD+iUa|MC1;|NXLfzJJg z?clU$f1k}Tjy&qbgk!DiG3>~zop|gh?o^m54IU3B+ zd0xslklAH9qVXXd*ZS%)o5gEx?6TYzE!4c+=q@7SHon=lPd*Xcu9P`K* zXP?|Y{h!!hOz_R0y|d}@=RcPI^GDu(OYqTS--R<&1wZR8XMORP%kJHA$ba_vz~3Le z?gV2_MFvw#&V25Bv%bClx4-_6=fu@->@j{MS(KJm2wb2QO+(p0MN{vz~wKN10V8V$TY}Z~OYn|NZyy zS2m{p(eU*Tzi!@RSgJ2$I?X>=f6u?ok1l9T5{T}lF$CnZ~k%4orm4?=kHB_PbJQY7yJiqUe|h0`5%A&#rGfg{5x*C z_Wjs*8}h_Cidb1YV>N8bdYp$>y{@OXd$@Y$6^j<0uzDi~Yj_#em-dVdubw++bx(h1 z?`T&yz}a(V&z&=G0m9Xz7$sNtb&PD7y2$)!GSt(*eu8CO zG<&WW+Gro;xwd0?q7@v=+&?nGe2cbKCmquXCKN8iFqS;JyI2WX``!H%D1(vVE}HX%(}lHJI_3-v&FY*rA3AsXtl^=~)xAAymB10&v-DV!t^=9Mdp56G|AI@hwnb?(?|&J+8dMo@9s@JQYfq zj6#9A70_oTm3Juw`2o6DaCa#bn9l-&JA&N4pip4G0qE0$`<6n1IRy>7NO1EN3e0Mc zTjOze06HCX73LX*66RTj0yA$PW4<7%EL12kNkH6rFJV#&L8gE{FSv|Cfyn~mj+_b8 zsSubh+~aZgdfZMxwZgIV5DO(tgF=CM3!v{wDsNXP zFz*G#5g}ndpip4$2J~IQ-J?)oz6|I)g8Q06fjRzAm&Zv8p>7_x(&KIeR0rM)^OQmf z^Rz;Nx$!U?n=m&igf;?{5{?;%TPR^>DioLjKtGbQ3@a3vR{?rNaIaA)FmD9(L&3dS zp}^b*=m&zkU7^4nitR#}Tf!WnP+;mjZmGvz52zk=73NWe5@wr1Xu%_FEXEIoUyBSR0!#S1A;j`vEly$CTqNlrU2jLR$j*rIaP35XN6XzY<)h zLV@WA^b5faDHNDj0(wGlS1W|^<9L@xLZQGc@VG@DcNL%}@K%_I6vD`^5HxnCjZK(d zg6looU9N$RgZfTPz&fP%$$=flrRevf{uIKBOZ6?$;O;799;@wL{td=DWKm= zz8_Zz{wbh82=0pt!3qHSo!}l;C@?<-^pxO!rV!*Z%jT9abqb+>c-)}J-2mhrvbGI$D&g#g#MvWV6Fu8Cn?LT6bj6Bfc`AFH!2jETLAr0aJMNG zm=6JZT5um#C@?3@ae17g5Ii1_TkUbT1ImE6!aS`|!aSo8W(jj`Y{J~AP+%Sb)Gi#= z^DLAwGZYF;2cR8NmTraMF#`IF;6@Y*%&P%y7u+=p1?EkFo)O$z6bj6N^IaZ?D1;g#yzB=&yp?pb&f{K+g(pqeAex05La6S0Rjf3mxtVg#xn%&`Qu%n7b5$=c^Db z+-Wuz9)&^}y8*2dj%^CT!YKs*V39HZlzdN8C@>2F{Y!9XC={3!pnnK1tq}YOK+g$o zr9$YTfS6mtJfcuwc6uDA9E`=-4d?ZTW}{U6qwTh?G)UZ3c+UubfMtxP$)1Dd))Uu zZrWMKtOi|$S))+GbSZ?IdmNp6(xK*nE)tF#6++Dw3e0x_m6lL`KU4@lI-oMa{X!w= z3!oCgJ);nObU=K3kTB0H1pPb5<_4Rn5H!N$Zt}QC0bMMmnsKg$;LRz7G0)>3@VLsw zc+Mdl8HM00D}-4zAf6tPFz-?bvuHpSg1bv0%%TBJ65JOQ!Ymq4x!}H~5WN4S%?-9h zA!PVOA>?n6CorKyC^14TS>pjK@9eaf|A3GP9Iwi$V!= ztwMpBk+QL9BZV*u0qPWvdlgEU`xFXHSv_8ibwL%HAMj^~sm)cm&R~1650_qlyTNJ{4 zRiVKA5)e-uPMF^)6qxOR4iwy96$->*trA>$8lO!7!a4(>se(IDA$WLzm>WDig)lmM z+?^ixG@x}-szv8n2)0R~z&zn`PkP+UW%iue3NxY*Mi+$w^LaoAOIg08P+-0Z=n%nu zMsjX8~O*9E;Dl5PUd=0<#6s%cU&W zDioNv0y;`?H!Fm78bC)1?t=;i<`aOpPMa{FRtRHHtIOj^g)lmMT!Y8m2&h*|wM`+6 z&I$$Qsx}*&Fq;($%maY>gkx&PLRhs@C@>cSnl5F*=K}%-<`O{12(DkDz-$6^wBTN; z5N4Htss(qwLabq26$;D|?G9J15G*U8eks-63MI@v3c(UCx3RE<3PC#o4G726 z3c>eL2sUR0PIi*AEKn#g=K|tM8wpdZ5I$f8bgbZ76$;EnfMy7;L!rQY9T0O%m~SeC z^-hm_&g0Hni48oZRM#qmIkrOZ9#+{{tamB|?-kHx!f~HMSnpIQ5I5#TDNFeU#t?!X z0(6q#4pa#1oq$dd+;oMo-U(=?;N~iX`7a>mmN2&}1dZ^xhdge|g?OSbrCO;FWUmlb zDm`we$1R3?GAta|D+I4zp}_nE&}=Eo|0oogUjsTtaKBRsG6lrb`4Z+ig)sJ9WX#Ee zt57H~mjYsL2{WJ&<}Mz0o5wu?XhceNGTakFm@O)VxrWC*>TyTFDH#=x4GLk_t59G* z4QQT}<#P%_et_l+?jeN&^CLiW1@}{hF!lhNBe>rv6qwhqvAHG8R)w%O;&JzS+)hB3 z8;*lZJ1hhrT_N-`k9*eR7Gd~*rEqLf2p)h!@FM^%ETJ^Mp-^Cc0Ej2oB+QQ$!pH<@ zk>H+GC@_Bp#J4~a<}V6iehz4X;7T#96AH|S0kH%L^D%|s1AE-}J#L%FJ>hXrd)zY~ zx6|Y35-{b!Oi>7HC>}S%<7RqX9R}%Fi!^Rj2wt;7@D4FFGZx;VLYOH5+AJJ*DTJAl zLYO12x3L%l6oM}R=xX73K%sR*!wfPOW4uDJAb_qH4w^hdSUpk*TIX>$dfWqm-Y6VXVf+ZeD^Lg}@VGlX?omK* z5{?-#OoT9-P$)3>dfa^;_Y9yLgyXD@7D|}K3ZczC?qQEJSKvHM;b>3@ZLSc!O^@5= zaZ@+hH`*{?Pzdt{g)q8!+;bjx@|DKCMe?{pA^7qNVTSPv8;co+LV-C8&|8J$T7@vi zD+F6|m5qfhQ3(DEpqqr_4u$Y6P$Bp#FlCHIpHT>U0O)PPagRa?bFV^J19+8VSNMU?Of5={S<XST zNg;SpfNm9z`xJr)rBGl>U=V9d$T3MFJg)^*C%9<}1?DI~HG(@vp}@=rloZ@Ng|G?% zh`FIu3c-)?xJNzi2$IFAlA^47fQi7YSP+;B; zh`A-qI~0O#_qc~VZVJrwyQEYr6@u@m5Z1Ijj^>hd&}TsJ7LFSg!sx6JdK3&IW6`4& zLXQIU9^tq{A@nGP&_iJm84LTO5N3gZZWoUG6-t-~6oTwwBpHhlLLt~mK<^cfM-{^8 ztPo@mBgt6IW);HBAJF@R;~9l8?@;|_(OB?_SgFiebvG!#Os0{W@vbz?GZ6 zwGPMpA)L}mp|v8aEbw0anEJRk?oonPGwEP*@9|69`nn|ElH9(ZnS3zc@(=L)F529; z0os)?>&NzJnpk^e^-HNS)d+n?bq{u|??zs%6ZEPM z(U6{YVKV9u(56oVg6nuqf2O9xyh+c?#hn<*gK4>X^7~EJjrj?$q+4cYX}YtOH%xyF za8dd>N`jp3)Og%6}zoY;@?eRzl^>X?$2wpcvGF<%+ZM*bY;nP2fr)BfZ|;l>Tplqa2YPsG=?H+xH637@KS~qxF=d z3TV(9NP{wORoa^PGRyWSb{8=03?aKCO3q{Pn)e$uy#jt&Sbl!<2Va-ywh)@;4UziX zi2G=L-b@+KUy|)Rz z1)nluGZlQo%_Xld++U7KWyl?l7>$*W}C_MS0}#{_c3M6 zM9WCO=Qd5h9qE4@>6g;8%KM7i@4vq^y=19jeDVGHcWfsO_Hm2b!ykv-7>OTe1N~w& zwb)=c!}h8%6$ed%$)sQLZqy@wr!HvViUqMzXeN;{_ZXp!=RpR4%9HVO>IZg-vOeqU zL4z&B`SGym&~>=Sj(EM@9sQ$&ONItU2QB`3;HTu_YdiWoyL)Rp?7^8%*Qn=HO)EBY zsq5|4Jl+J}X(kCxg#se$THPCh?fh26VdvkTeti0NrHyqdN_p6pN5HEfE$dWmT#hY6 zJp)5MBb#jbs6R7I8#YEW+i52Q$nd?Och}5(Nrpb7AJdz2aS$f;>3v9tvTTGb*=H#; zJHC}prMw(W89A7Bb};McVAg@~aq;#mld7@4JpklxZS6-qzxBgki+g7qIcD9(c$Dj7 zO6Tk-=~&hrZK?TxN_)4`I^U4AtPAUqqc1a`BpuTJ6ho9doOalzag_hG(taj}mi5l1 zTWaoA+RsI3osUXd>z|gIFDUJON*nc$zZAlAthWAXZXR%AysYgv>C*fHdU=0U(>omg zHu@sA9>F&$z|nUu!;f25v3z!3Gs!$addTSO3?U=JlExP9NNwlllofh&3%5DiFwonD z4S2S*T$optJ_J5@Vg49ft_ya-_D<;Y#EtHg%pGDczKJq?3%|or5Z3J&DQ|8b^sv_L zV910~590nT{HEZSFOPEbUD84Z-($F$u+>{PH=r!pNQf|Euzc z+#ckBgyAM#?Z#X-`mE+G)<0-5SzKIlRorPsTm-vSWXV znWg-*b98z9bBITub8X?q4VR7`qsz=ZO=rHQ!#t=@EQ!nGR3B&8*;r0Dx3_IoYEIL1 z7AfuYSlGM9t8A|^d^#^RZM*6T(ai{a0i7Utctl7Sv{xGhRxD5lNL+VeH zZi>)#b!-aZrV0+OeP}&;8gZMtJHot&61Op*_XwfO$5j*8Gu$;iVlbvoI%pp#%2}v~ zyJjFhT+hAlqv*yds1N;c?p}Kieutm{Y`-(5EV=eujC=NF*UuPFI<_I(xrXuR^R=F? zbgHxq^vCgVU#2imz49yx@i0B=+`QPf5AVGs&Lt~h_hN!JF#q#3E!WSN;ht^Ee63!T z%GbrDZB*L$H5!++Z3WH8>s&K=QBL=K$jV{l^03Zv{S5kbdA6U5xMMr>DMdS<4_b|C+?_~C(Xfj*YoDNZypck6Y(OJ(HRhjoq4SJ#mSZMj})2|cNUzHgig`w&1LegyCZlpWSaMM`3MzR6- zhdLU`3wz{k7#O%z^@H*`A}-!;M=TGenQjl#sW$l>SWCgXZ3NDe~Am@aVDR~ z^Bje`mNZW6v}=7hWY5R7VHb0pSC8#)xprE?J|gRLgD9J9wJQ7aaziU>$chE|IH(E6 zuaKSGv%bQ-&`~I>%aH#NezPH~{Y=?G96P4tHwB+~o)K$naveo>SY%V=qkR7vRk_EH zJ7khADqRY^@w^+AH{RZbGIZM*x>WLaIQHpn()8TC>I&RD-=2OxFOHpM0!=cnAU$;F zD&?ckS&ca7bG}OPZay-Ad-k7KBV@X{w93t9(ju*^mFJhxH}(O$o+DjC)+wu@6y>I~ zqjQ7pqr9)Q_u0V#yQXdXv(RL@U8U>0Y)6c-)E`M}1o!aUY`+iL?rJkU+-tYZ6}rno zH^X#tuS~h8TxQxnC;k6Q+@EZmknI@oO5o-g?rkgkrwQF_fLnmF>Pqf*+Ck`0={3N+ zYf)%-&N!P(ecS?i>SHaKC^MFaeK&sn4SK*m)3xmZN_)raOw3Uhdc}e;24dcO_L}VnYi;K*HzMyhrsH=I>~+CDBKvi#IuJ(j*tc#{U5xK9Vq^2Sigg;Ld(o>^5S^lZd^^%}{pDs& zJN}tyDDB)y8Ija|gr;9Q^;S*u4Q1ATz8?4Zb`1u=+9lf4-qO*2431sdIo6)h2Olim zFu?hz_^Y@dDdq5)yT77zuw!_5qxYrAa~0C*xgx6@b=&lb-&_h-Y<-`_Pac7xon5+H zBp*2_$NE^HzqV8kyzw;Gmv*gnHv0`I|Bau^1AHK)x1fxE@xvM{g% zoMSOhu2J1v+OcjO_WDJQWgm5izaRO^u@*hnk0b3vrI6`Rhb^F%o4WJ;(vc0=akwk1 zw8T9EnQ)KtY;Sk}`jHJ%AC5hbmJSXKsVqsityGUuT8GE3S}x+BaB}MG80=Wv)7vxB zgFWPJxtY$BrP!x+WT11P*Gp3B#JH!luAKv;m}TU6o_1+!w_{yN|BS=;;@pc-`!1Y| zd$x3A$51~uI)wwy)QEo*BoOIBM80X&!yt^Jkc?$V<9OG{TEo~UT9KihVAoeQ9YeUEH#pZ5 znhO6=?4*5xmWL=|D{zpgeq~XfX_5IK^La1uhZ;8v<(m-Knn$mhO$*?v6Na1RA`o$CNx`Lk}grd(K_X-Ojyt{d&9t;p6R%MtuHI<^c)Y)ibaTeFkplRcji@JuGzV zOkx|e5&FO)_xJT)?Bl-F^oRdL&fbS}`T0rcxk<+4YS&Cw=I7-R`@49aL0xalFCU-I z?GZ9@T*{CFWLVT+wWAg{~M8x{qFJ4CG1}NMVz)C_`>G7ES!Gcg{)(z zPeI0;@HYp7vR$$c(ni?&4(D*Rm2vwii9Smn@P5wmT6?qk9`iEhA0OT9_-}FiMdrTt z=8Uv+_u<<1xQZ_#tl6C}rP5_Nd>OcKt#=aI`B%sXId66R;n?s185?T5KUxZDs57?) zPm#I0^;Lu^iGY(T60hHW4S4&ZJr|W3cFoFbhnKI1K3#SX_s|^J8@C?u|B&YG`1>gm zX1-ES?!%t|yGH%)1kLQat+^4;^(4ispTIZpZQ+@lcasjjt)36Q79Q3xR`%mX>2cAw zT$punAR#ZB-%0ZmE+9ussKkF zE4X$yGT7&q=)~rdcQS0($XZwqy4|6zb6ySqhLUfK3?eA(WxSv$bK&??>J-nS`AE5&mVF|Cs-7QkZ;%&Gxa~unkyyVSV9PiG9Sw#H(5eiP$t-slHVXM`;~|FCQR2gT0Vp-btfAAf_9u8p$$~H`yp?1kLg4f){c{E*J>mKe}$EmM9G_wPlnU{Y+Jj~0_AX4TH z(_`N3KnLj^8NHvK5Cbh3$F`k|L+0p-IEZm^JnQ0Md~7q){@mUW=kLf9=o!yr*@nv^ zeWNWsS1ymRJ%rIFHjsL{dv$!uwS@}hA2QqcC*aV>KoPa4&*6KjeDmbl5H_E5Ov*Kg zX)djB4dQv=7f>$8$M1zc?HJEH=4)O1u(3JoZ#~{wln-YF9^dq=Q=5K?eAIcv`3VA62=H~?|rt#yzq;atVRZW;&q_;QaP#dWb5i*Ey^F3sb|v^iZvbgyS#QJxay#YBX&UzuwY z#S#n5OfeRbhxs)L@v@El9NA*yW3x9luHu=BeJD5biT8~&pT@E;d9PB1`ICIG%I8bD zi+B2%`J#P2(`KIV#&i3{d6G;Zkrzpl&jY@v#XOjZNXOO-&%%W^I}v$`hS-^3eE*gC zHD^q{UMFLq=}@Ln-*QNxr}ZuQ?=Xg$oG%N@ny)xg&sorun+D#UBQ3fG71j*P5-e1)3z@3$xe+Z(rjgL44> zG2hs)Pr}S@K6OIAo#u2aycebRr-+FS(LS%vaPisMu)=xuI-W<9KI1jux1aSHVZ=c# z4AGJv_2v`3)SH9;!t1=whNhk}jSGG#NkPoamxWFbmbvcPw$*pE*S0Kc&edk>s`#p{ z?AQJ!THMgsn3H{0jt|JYU2!AoWsV z+te&ThIm~2vvr@{n9Ih#Te``J#X7eJR0Fwc@i!j@a&mz_gX<{dDUDJhLvQAN3G}N2 z-F{Y{o;!bdmY4S|Q$9e;GF^ZS3&%iAJ8b(6_-0w1&3`v3Odi5x+1VnG=EhZ`FoV=N zrq|@sNZMH`QAw9}wgo))v%aNpv_TCo%pmD9Us@3-^QCJCbv^YQZmd_5;PuHmeTtPi z=R2jC7oz(cT4zhksMA*F?SZaV=Ej{@DhDmK=gF8U8(m-gwWm|h9WcO}Bu&vXuA4hl8EB0ZMlxd=;L zKb_K*>4duGC>P{A-^sV5xscoW(T#|F#X0vV!~&^w+_cK2ll3-FeNFTM@mv#(UPG>} zy{a9L#5T9Lgr(cCrQ4s|6YxB#I!ln47uFqiP*k^BnT<%Y~2V;8^wEJ zi_O`{QyRtlF*avg3%vcT%!*}7P=Li)B;Qz`>ku!?^M|SOq#R*+UVv|w=Y{-tlfvX7 zJXSpp-yV+}bAW{;jJMClRmd(ee%hr0@Yv7nQV>(1c7R3v)RV8FQ_sIZ&#~+)%mioV zx|hg3vjRq-AcxaqXbe4U96M4#j~9|I_2Yxp)bAJ!&c-SaZVKe<6kwem8^_SY%H#C~ z^ax@K$|JzK^0>swTMv0z&$xCK&ap0Y>9cMegYh5h*;r#Fc^W);J36jwDT>o?lZ(HY z-Q<|FG}_REWia1YygAU<+F&a7K<5<2>Al(Mz251qbIW*56f6*Z7HU6B8jxx38JLWI(n7U{aWbGJ>V$MheM63=!adwE^Nsc zRWVIRDy%DSb2=8XBTSQa`*AB}~-L&$Xpa_s4`f_`x(`inT zajn)>$#cK|Rp#n0<$=j7`R71qTldLNGF^`O@=)JvoxTqz>Tv8g@@^;ZSbe^DD(I}J z*kVmF7N0Ngap@E)Yo^Vzes7?+m36U*1MQ2k_`3W)mk0aepuX5IbWEZB`hb&dtok6k zK?CqX!PCScqcA;_Te27~wq)&GM(leG zzL1`)!EHRT9I@}Q@?~@8eyroo*zXv0A?0dYnlpHlbnu0qkMNz-&Xa&r->bruW!V-`u0gzmWA7cg}_?# z$NCf^-q`$`_2|?1v+*plIrX{2_9A*esdphc4{Aw^V7L*e=fZjI3H_(@J)3)hnhwu z_!qzj3e-rqx z_xOJA*GNBt8%nUluGuKOO!t!|BLmp|?B*Stp|3N`;70f;cl(`hO_x6NpDAH)tNFw@ zZY$BPQn;Z4uYB~4xSjsi-F@OFPT4*O+3qUw5vuc$lbia`KfAkY1j597ytg3CeI@3P zNk?(-`6oJj5%lkstoM2HKuPD|U?-l856%WL?gvY_cPv;5N8CfykHu*n7G$AacsUx? zmk_W0;LGj&dEtjtq#vSv`7*-LzTAU==A*zi$o_}FGNYPSN9NSu7_<)mThdSz_MqwR8n$z)zJE7x)#dHkgOY0cY zoQ^+oI_?9fF^r$4pa&|E2JQbBwynYLZtH>yYg2G{mA2|9W9Y*?AmeG2V-S>Q`F9r+JmS9N(u-$L2ZEtdQ;$RpctEG||$n+hr@va{X(%H`F$$Sd1_ zr2Opf!hT5GL22}B>WZ@cFaEoUuf!LxKXfO@iTu1;lfXj~#`lKt}fAe zgPsSE{j4tLM;R!dPn7gnFaM0VSTE7h?ARXX#}gzXRw17QDKXEsr}PT#l-c8PdSQ*I zW_lHgb*Iv$ekF*L`W*-TPK?IMeEkU6zFe-e3)9`T7^A!U`RP~5)sr_%))}_(|(aY&+alofwi$!J{dPr&*vNuQnvpnKw7k%V;iGf_7;tJrKQKo)!o6dRe(;J2yzVm|i~bh48fJ zx4Z>f^40i#-YMZJ%%c+d1GLXGuRoE{-QqC)fEL{h@8ws*Q#c>|o#f5fS*pK8N`*iiaO@w zJ+O&1c`fj=p5b-88W=j8Y`glE=ZI_57^ejkSN(b66xn8?~FDkPI)Jlou9&<9)8%pz_? zPc6?ZjZiPHBQ8UD>jRb-j*B<1`EgoGH{G>NX=eG!^N^<3bm$qcUzSF%4bokiOgD%# z^730;Y5C6!;>i_?N2HJYomhTdoRd}EWWit`Mg5e=V|;99Tr}@XqE$h9T|T{3TtQv6 zIMQ-=2l1>a5RZtB^0WFJ%grV1r|ZgxH}H%SwDP%PrFFGT2H0k$N8Jj zYw}vWp}clHBrT`ayHJJ%FVZ%iFm2-*D^0A=1obFxbrxS-=YkU-+G+}>>Emk_GMA;z`%54G3>KZY&&^Xpk>|xO|op zAL+*OV)X*;!qT|Jr;!)l&)eCCl5&I%@QEJQ5o6)#qVe+=)I81^5lJ9zC?VU9?NC) zV)aFQs8hn^mtk_OfH!9XSw8G#iQ@{#8Kk z%Ty%ZqJ3ym1`#%}UvWDVAKsLRah;9pPs~?1PlR41Pjq7lL=I}{?VFdL=^Lk4I1JOa zx*eBC9~4w|XNp|{OP!tzL#NojOP zP$qXK%Os4qSpGO3&7b_fBHx8FC8Zx9S|1(Tnv&>l$Yb?ytCy`voPn*0`|^BVkra88 zUx#FM-#ivmV#ayNeuMi3%*Uj?E{*Pmj8^9Nd3p2W4cn!~mu{EeL3pdT-z^-Ms8U1^ z^Fqnf;{Z1vw{*k&zCV!vKay!C;-maUWHUaI&B`ve9g-J1X-r9G@ukuYc=-;5u0y2q zLwO{{g7ZdtqK-95@oTfGwDZFRbu1-Ag4gO;5&hkuJUM)~a$!4Q{R+$Fr$Jr#S+ZP$ zxZ*Vfiz8j99uDI9MWJ|H9u|>XJF+6>mXa&rjms^SrtcUzm&msrT2}(Ei&V<-+D0nv z{0SNAtF_CN3?Z**KQC`BOXNs752Qpv{NdcCklz5yVp23A`YrO^^7rv%85Byx^QPoZ z@rvkP$GE+@-S3pR*1yI!HROwY{~Oy;M=x4G{62jurPxlyX(f5X{yt96^GJ%8U$I`n z?s+Oj8-rMXGLRbI{~>4t|LgNV9ba5$W0?XTmk;^2H{5bg2^QGQcpRC>?`?iOehhiE zoQt%TkTI2b+*VRHE-wtr!`e#9#)Z5h$QR(RtapA_H#FC_wP)!!Uys|sGubxAqki`R zt*WLb)7qYEYG}%|q0N&%J__i#fIC~2>&P~$pL}UZYpiNs)KRs_eDNoQH2C6YoAHQ( zi*sT~YprT)Th@{_U;jxVt)nW}+ORy+*rw@~rD!!RjV)Oh=RP5=rA^*#-8aNhh8*O> zP36>UzmVqi&NSDw@V0W(y*%V;ZE0)I)wHxMZpc{P?Vm^I?d6hvlEwicow?@n{J;?3 z(BRKURD}4t#;Qd*=6$ZcCD&4YHct9m_=7^e*7mHj*_*~%ZU=`v%WJbZE77p1p;_cQ zB&6}m0p8BuTGd|f@^W%W&$hJST7nuWbtnInkj^t64ONY~x`xI~P{xObJgwQ5TRO*0l}qN(K!6gL%K)!`}A8IYMa{h zY%(s?Z*IvpRk=2R_d}Aj%rePiydRRlLzC8HydRRF)n=>e+FjmbM<+pRXh!BO z!WI3l4NOSUGqnxAUQA5UvYDj~5J%eaq!bOYw$!;a%TlzuhGwXz^=SJWlk&8**Js$~ z&O{mUO&9i?yFh^`Ho?Gt)+ z22INvlDuFbd2TjPc#MoVl5ZSn)fOH+YG7<3kJ-fhv}#(KT5&Q7hviK!vys9puaY-5 zBFTVJ%hl{w6!s;Z_wQ(M#0>fe+wTPi&6#fNMLSC+J?tu;F;^qNK( z{D#`9rBw}$Rn?8wCzvf29(F){ktb#nSPRvN#V)j+|q-@$&z_hn!vhw=7 zl&{%Z;X%G9IW&*V&c^X{w9-_DWn*?$c$91)SDC*|6w*;%12&14(u8t@!Z;ruh3E4-RUGp<``Y;0_)(VS7er-tpKHj_y2@Q}vL zfVNDozN)#l5tf1Ze?-V5-BNRVZ9^M+P;?b7%~kE~C_5+rks&XNvpti=!N8VmyXoNg zriFYpji^C2Rn1bro6-HW`!;=4$k))(yto{ycn+C zSB7-y*J?BE&NNW>qeHrmE3z0F`SH~Bkgmgt#9JlDB zR^Mm6q9|WurmC%8%H+hNJhYaJvKY_`-$@~#%d`4yrp{!anV_HA>c+wnc2-DhLk6Ov zy5U}4zMmZO!m6}2w6((q=drUsyfWlX#@m)d(`#84m*?z|SIjIMPqxMS;!_fIkdSE5 zuFM#UK664|sl*t(w>DNaG&eQ0HC5rY9jzayhJ39Z)r}2p=-}f9LmlRZJWQ~$Y6XXS zF_+qnSA~3SZH*nvb7*?iur7lp=4Qbu`!TL+~XrerZ)!&{FQ>V?0e0hsCZ;eLM|Kt>~5;+N)YyF+X?ZG$9Vx zRJA<9KE@=u*Pr=wfXg2zoUff0;|rX}_IK*6Nb==Cq*Z~xo8id!Ls!2sSFOt8+60W8 zTACYhCqlzHzV2eaDzv(614hG*er%7qs^C$5JF={*!8!)!szP&11X{s-{Z^WXoSc078xAv$rYe=`0K+xJ?f*cBLuE%lt9%s>=ZDx% z=7TJ}<*N(Cx_Ypqg?Vs@!}**+JZyVdrjWLGFv>cIh9)_MF(ccitdyjXX8#TWKkeUx zc;qGP+YOokp4P)UA&fMwk>=sJh89b2&8W2;1Dn}T#8 z8X{qv^wr*dt39AiJ`{Ycvy0$3`+F}_4W<^0GSZqc^}A9#k6gVC4|wBEN<=A*8t;gFO<N(Wa=>6^<$t( zA)QtNWyyYw?@QPmG5Q*2e1c{q_x{PZ$bj!+Fv)1|?ckzWfG>#z4})oF z%M-!7MxnS;<@Jq#Z2-dyDbts$UJR6I1coquD#6D#FdfBsKi)&s@~q2X?2^TWH?j^4 z11^tcTAq%JjD8NfyBrD}gCiOMXKSE?3r|azlc_pJ5K>piCuwaQWg89pxNytRZd;b| z(M$|^#JE^Hnh^73s=hZeN4Ni@&kJ<*!Qocu{V`*bW=2`%YmL=-`?Kp z*UWRaIG%G^Wo298`P-`MGO`oU-r}|kDDy#{&MMzlh1m^dMo(6=*y1?Y^YA%X_LS(1 zWIVbphj{+>s_JS?m#VWZ%Qz-=c{$nBWfCa)GR5PptX=kUo{eQ$%nO9? z&^*4z%%UnResBbaZ0Ee(!I>nIqrg|P&4`!*8@oZ{peg}r+ywi5ll%t$Yn2vVN z?zsUo`7F|QtqoJ~_PFmZKr~x%48pSyf7KDi?vup*E~_ub(-J*hIk`TD(emo21QOB3 zerRumAKM5zZrhiw1k5um$0Hq{%{_ttZleE#`j84gIOq>SUrneMy~6RH=y>mk-L?A# zqKGdB_ODq3mqeDM;Y$S{-zi}DGTb@T)jzm;2r?S3Ji@h#@_K2EtBBtw5&kgl$-$jV z$3dp4k!A+tn}P3{5s&slE|&)1K*BvtaBa~04^9G)yn)??J9>uJ^$mjWM4XrB{>Mzv z>?iMF7kG0LXR&Rs;|1NPEvdV^v}YmRlkvxQzwY+qdwq^Mv%IxIm%90!vW`hgBBiyn z2WY9w$uwGr6Vgt`JGxu0&Dmb4wYAa|okI(wO>i{KV$ni%&2FN{q2XfMZ)3?x7Ee{P zH?S5@nWJH&5Swh7c5DlK8?}$4VRE1w5GVuMw|!&0Gw7LGX>pFeUrg6lS#E?nSIu+rNRLmTYH+^`f^8)tl;GnV!r`J0NdR+aTi!@(_zdi^- z+rje$yk*4RDSI_&v@;X^7zp(!*VdTH=sbKJbZf%3_}Kk)<5zxD+gxq6D|?Lbg(s6; zA?1YeJif6((pZ}lBkRUT7|R1+gRDWXkI>9JjNyT+&9=10@nPH!oYiuze`SKRyZcp^ zeH6#}QX8gBes6AH!Mi0K$XeH;{QC(WEsxjvJK4(@VCbvYQTgR-`$$MCgceg;Q9#dmHcNj5f zvd7|8w!>q3O=C-&Pv?jj58IUSx*w@{boj1uIbEj3{BrZ7$$OOGYpXI%@%ZCqg6nAJ zo(p!Y{QU0af|umb@B2p@q$T%0o{S?B&DG-;?(2e->Nv_<}Nzx^23UQa{Y z(5D;pDPDSi@vT~!Clw%=jW`|Qc(?gkXla-$9gHhX73B&BfwS1HCd_Ioe&LLc_-W3Rj2io>9TKVF}9F54&Sj@T^>p-|iF@ zd>uAC9lzZnD)`zKY@FEKKai=p1IiWMSo^rdY!8Z2Ckd|rgXmVk; zh4{cu{3*n<9_29RuU5I94QWmA#OY{Ks>`G2Lb@2NIPCKwP0%X)pF_MZyU}e=?7?3` zn!58jI}y~mMVS^jPoT%s_@Z%GV8SxE>-Jdvq(9C-IfUak3Y8Tzh;xO-QwuEiC#47VKNYNMV$ zxfF``(J~8M{+|O{J>HS-L7wyOIIiWt7C8Gg${U!jf~Bu3PNJpmv0bi2c)o{u8Y=!Z zzMov$p37iyVuji*tmn7qg1!lB`R%y|wZqU9uIU_b1L=RvhjC;>@@^ zTm^9rx<`MIgu#cS9jxDT?E4V?o@?KeC9LW=MQL*96VpFbXt6wpDIExvZz{i+wqV;> zzYpg(W?O9?jb4W%h=aebrFSI1xolUJ%~rXxnMPcVBAD(`{HEtDUIoK6(fbO&jQGY@ zX0+tb%k_I15e#=Mzu_=M&uV@j$8U@u!t{?PuEUTj_d?>hLKut>s)!5vsA_&Ap-fei z#9gD`E!Zmd@h>92rcTnT7nuHEs&@mwm(m9ZOW$1i z6RA{}?FTYGpn^U-su2Df%+V#js1n~n{znTLW(B>5M5dBW(I#Lxn5SomgelpyeLHZN zlVNGn&C4V$hiR&6qr;1Y7d(4iB2hPvN54DQ^}FYxt)iOCC`88Y?gNc^x98eJc(1m5 z^~w!$`L~;E=aA0%_&Wa| z=J23%Cy!GrES+G+%=9pa2ObU)@D4$|aD!BrMp-u&7g@L&iQ|Np3+DIW$LtG^8I5%) zU!A1NzDbUCpVL@pH!$x9FXnk%VTU(|sEEo!VrR`BcxSL4-{)9E4WEJ-@HHCkZX#Njhn2j3Q(j-g%2Fgn6@&*VI;nJsog4J42j9Fdno6@KhyuQ1`Kg(+OInH^(ite>NfaRFmlg_ zI*j;Qm#G-O?g}oH1ND~a%APd$FZXlhuwKi7QKH=~)oRH_Lx-TvVm<5wUj_aSMpj^M zFZuK;)!>a$?Fie z{mONGlw*k8aBut)J?`doD2Vm+Q+sUv9ciFCh@OLxV+em(ZuRH$_w}~YzliPgU`3Dz zIgI~qa%Z!msAI5)n@+F|@UE$e=HG>7|d6OwfADyDTXp;tXlPl>#fl3{FH zQ)p#r8crlJu6^?Hvdt&U;I57Bo8(cFYa{z5Y4GZf^)FA-+UVlLtzTO|-9Jg^NK995 zUEBv0piAh&bXR`jfGYWaU@|=ODdCToqSx}MoGX3_Uy%&Ybx6sxgOYgF%jMOhImg3 z+nU;tqtJc^FgvaGb`}OM2fqZ|va0RCeV?lHn39O!FrZH7@$wCRn4r)%=`zR!GX~~_ zTZa3N<$nYCXxC0WK-U;XF@EBDgy~X+Z`>`~hmA>(WB)MR*(d#j`KG+v>lfS&0U52& z=DX!O-b&s@!93#H##>V9o{Vq2M8n-w-X$XTwi4-L_j2O^;vHixBZtk%)tEr9kJmCh zO6(@nyAnE6&zqdh-hyw5-K_!eyEI}Dsk)h7D`fkoi$b)GSo{Q-p^pB`eZ~9YR zCGt{cu2sky4pr8dd;A)XNA21EV(4PuUyMSIx8ZL&7Rt`?{>IK6b0pgUs}9FZ?ge6t z5_^ZV^B8l&_f*dGxOxmfRyE;8!=Nt_w|DrsxG?Z>-9Z>}GH9%-iRYKQ5+;ZJk4#qf z)#@6uF!av$!H0II)5V4krUdzMM4PtnC=zx4;5-&>e<|z~_BCYe_)p019R${K%nq1P zDPD-bGR~f^U2XfGZ--3pz~5gmPRF`w1>blZhjLo|{&4;EUmV|i93N@+W|q<3>uKuG!8ndVI&nND(feIIA8@=(o3iYC zIr-vn9|AoL_hA?AIv;La1>YE>zG1k3ONG1Mg}cFrE2$t4^Ck@U@2PMfbKySjcx`Wq zIx!FP^RhJhqziMS3q$#-Kc%!hx+$PBo{;vLfW|$vkoGx8i{}Qi-^p_WXfj+h<48M) zbJL6b+3Rsp%ma_>Hh3#=^+5VK^l9yQkxs&6(^OxkqwAGx=l3M(JZym}MYgKR&8@!~ z&}GRZ*G3O;8Ap68pdm`7xORMRK%;9F?F#oJ&1dsw=&9R|T*K`g9(Iew!G2_d!1lzs z!Yv5Lccor~TtnaG>pbztATQ&(G(P$w^Ah#$OZ<0}jJf45!tgE+&3_HY_JdQw(N|o! zTV1$2-J1Nn@r@CMK7a^)*dP5XaHWyEBFEw02V5EZx73ii`h)z)!`RarcGtu8Z__?d@eOe9-w^C?2*1+p@lGf*eKR>`@ z94O^L{A$4`->3UB@aqK6w$if-FT)8x@x8Ktki_2x{D9ykU3t@lK7?Nd-hRU}wz(Jy z;YL{5W=U@t6riCYvK@X6@vt3!2$9)ca|=0NmDeufdAp4-7m?=BHf}Aro+wvj$K%rD z5w3T&j!SJ^&oMGFHa`A3B!nW~U zgyFpP)tI;195r6&k-b)5caMp6P1t!`bN>PQw7m6Ld&poQzSC%1AwG9mzqON}q1^=c z$PW#4Zs=oKuJU=y?q3&aWz#IxM!svzDT{@1y%*}>2W^)r_1MmIbQpDd&|}I<$HF4UC_=D`Wl_@O$K!9 z*q@qcbFEF=;n*(cBNFF3qsY)0QMo-fEX8{t^O!E@54fUGPj^jSbFi?Od*GCR#`y-J zuDYaTKLV2~vpa^D`IhHLopt>15$6tu+bel=yx~LHbZwUDKj!JOEJdkxP3Qy*r+7Pu zX!{KhA+KSV9FsRp?mI4%pSm(RxiX4==IfOmVu!{xi@D5xglzJ4EmJ zg0piN$0lhUQ|6pAGRl;?VZA27v#7lR-uGswlQiaio1S@NERYNChR*d;ZFq5h8C)Yx z?m5`J@#oOnxzP>rkyrGm+_@LWhhR*Lm+zBA6@ z3Ato1S&zW*G$$$++$nL=PxLB6G`)U>@c#5F7)uBahjOc|o=7!9|9TUfU z#STA?{E)Fms~nZ|jhgkF5nCBP0Y0u{_LOKD^4(*Wq3y~19yFO3U8H5m@6w=5bx%gi zlxHAVe*Z0D7|xX+mo6y*9i#{&@jbQ&!}#2I<4L6Z6#foJx>g6cPK*lIHwXD;{WWnI z#t&RP)U&oPz@O~<4DC*gpJP%yWwBP+QD!H)`dumeRj8J^0gUiwIa(VWQ~X-{B~FRaVkz{~OX>kt#$)mxE1%Y?AK$!_Z& z&w}?k{BdrKyvMI3dLG~8{WJeXIGan8k3P8euDbG%kG4DhXo~WG1brmiFa2&YLig`_ z5=Z??qn@E$-w2lDRcEaO>ifhtWPIhi1}k$J>QsSM7t;O$c(R)->uhYz2wtX^jQXktpG242ulwI6Evfh=Vey(x-CBL!X%@^MNe)k~~1_b;_BOLb|vKWJe`3ckL^OJUQ4PHrQ8@4=5&A)>?MdSHN!MVPhpV<1r z2YkJ-yJDlKvZ%vRw5de3vH#1S%wSI^{7}1kdoVD{4fKwz#byys;#iG#&W>q1>NoTG zNW{u|bGozB(PgyOXwIeE*hx*-;W!WpnwhvO&DngBXFq#3wy}Jpt0F zFV4#l$4$uF6A_K|OYBqDbgmkrJXt^HXvJY@J0jw}j%-{=8jovv0>`o#6B54+d;IW4 ziv5&0&!zmsNb_i;I3(H!LjdI2ZR=XSDx%1@NV^UYW$t1fJ(}JKf$dzssXeK0AlL99Y-Ky%P9}Xaird zmGJ<-Cp$jHYC3a(pBioG#9Q2O=)q>LCFkOq3;HzO7skS@w&T-)!`ir7dMED!;EoN} z%g@9&*2gif0dAzrth!gYUL=t4P! z_N)`mZ_Fd>J5qgNxY^<7V`Hps!7VCY&-onFcY5rK0xn; zz}Y+tr!+YDhJI)`qgRm5q;>tr)BS18TorG8^*yM_Ffop&2p_yQQAZgk&huHCF|S8q z5lU3&5nr3Pdt%HVoPoeOzx?=wPAxPJocYV=;ZnDwdsYn;Qr36c{?y)Ugqh6?sCpTZyUn}j#5r9AA=9K#8p){ zG~#06c%hx(%m0QQHUAXaSK>J*;V&Mml|~oPzQWF4$bUD*Ydc{Wm7fe z<0p;0VgE7UXxKaPXTaIVr2iO}^=!Q^Q{-G zAb8kh!CTc5!JIy@!#-~Aj#|0H?s`1aT%6JKk+8Q3d`)ow25fAS=I)k+ zZB60j(n^sHHZ@7pZboRZr%9T-w+!|(jh6^nhOm{M=5kRT%(yY+@(FgaFb^)=GX19) z+yIVSHI}0xNdZY5$A#(O4k338Nv=Gi z0dcR%_z0Z)D}rgFa`;0e2KrqO?x=AC)v;%sMQ zV>P--*VYCcooxu04C3@-d@tMbBQ-1=fLMuITzl-s6f2Iju?s^|v$|F*i*pLl^uimJ z_q7Q+C1$p@)@NafERL0VJUXC}6PAI$;<W-tnXuu9JrqpQGD2InVu zVjH6dvZWcf)e2vy%P;0gSeI?gzA6z9_r{sC8n!Dz3)0XE=FjY|PVmX#S<>!K;5nd5 zj;Gcn=vGZN?X?M-4Cp1!bqPG>RsNm?-VLUmeYzk)i|+}#FoCb*g?l-19d+S)6Lh(Q z#`PUK2U}l&F5_U{^618CeF+}f4b{6AU0L@h=x7mm6iA<=()*}t-FRvQV+>t;=pPX0 zCml}77O-M4nu6S11Gxyi98X=3af+=ia=b&l`H<=uW_+}fV;792F6O@&OWB?p=lz_2 zbG&2o+e;kprH+^3Y`;4U_Xf}zj{kCA{6-gUlM5H}j<_`VFL~eWcsG0AvI_3Og=-X7 zIGX9k{Wy-(F!q#m`7g(PZ*_59>G;F3W#KTT(N!+Ys0%|qMkKx{Iss`==c^r!Fyjfw zpv>2|gU-KrtcbU*83z3CbYbIsjpP02fHsgy^IZW=*FNHK{}Rwt_n7vtj>fdFM43`n zTT5j;l;eHiVgA0Kyx{vl5TDV$?{xo=qhWpPVE8)g9ZARo@-Z)XPaeLjd!%Pqc>!2e-TiB1 z&AkJ-a)(nd0QJdU-Gh5S-M;8D@KogU$l5d0TmkxIN2hnja5r2P0(qud*q-j*)k+mv zUyE?l613RY`-3Q>N=I8CJNf%GXMujKqlcTMl;>Q;JHyeE9_yM%e?r)qMjsjO=lu&k zPFJQo+tJeaxeo7lRGp4YZ@#1Tc;|Udi#jfFG^PF}~Kvh21TeMkn~| z9e#M7+^Yiz{Wwgcqb1gpbMb!b8ia3kJY3ID^2z3el*xY3zuocWdmU(cy@+eMUvXh< z41bZ-r+&~@=FznNy$-bVUEDo=$Z@CJFz~A_&7odw5~;sG^JrZlGftxCx_SoIVGmej zJsq<4Iy&^}TieZjc=i4N3GC{Cqan8t&}~tvnr2{9=TEo5gKASWXAFfp<7s+KWWm zCFs}sc;(cIlu;+}?{RoJwZM6wNM&OBtg|1> zr(+MFj+^1xeQ?*a5Q@UA)~u5bZ!4lpgrhlw7o)da$FADLl&plUZIK( zB}ngKqpA0ozkBR02=_>Wrfyl>AEZ3&4<1Xp>Rh9H#H!N9@5Gj&B^0w?*^?rN%L{`B9AM4oW6ayNtMd`9)zFlc*HKN3yyC? z?*)BoK0VQfXk(_0v*qr<>&ofPJgE%gaP3q&2kQPo(2w=ut#_dHUv;r|Au8*K!8fBQ zpW5Aj1J6v)16d#`G}kKNP?>dVm!I^eoVr0X!N@C-gNPQllt{p z#L?>FkdswXOEmtkB3ye&v(pnUzwQEkc}TZYSpj`zNSA?}>UT5JJwK0z-mrIMJ$-Rm z{)~Th$dfQ?%JT)pvo7QbkM%h@z6_q;kVlT9vNzW_ZUcQFkB<80=>HG&;gB92k))iY zZ_J~^<&QTlIvIWdT`moIg1a3_+Z58&TTt?Vw97+UXoOwdkAmmQkSBE{lQP}`8Q&K2 zsCe;_OBWaU-VyR?e)?M%8Q0grb8X1ueCtX3259d|(J+VNb`nJ%i$i-KOEA1 z$D#CZfqs3OE`xfde;f3Vh4i>nlJvg|`i&voPf|2I>7NPd$w9i0I%H99dz7(4&ytvWbBIs^k&~kUm z(D6jBW~iyQy2`uQar09n?pCgEp%Vd~<;6Ryjg7)bb>h1e#zmSz4AIn3kBwf2$u6yO zd03L7XX;~GS&D{zpN1OU6>@DxbQc|RQqGCIQoOu>s(6+=@=EdgHeR#7Nu<6}VV=0R z^Nf!5|8~4%$AhEpaXQy-SqFTa+|SB2@!BfhS;H$bMb64V54@{zcCNi1XMFWq3FdWF z${ja3|D>DWE^fuU!`4cHzx1RjXeQFe9!9&#b`SJ+VnS5YKUlwduz6&C_h3&~ZTFg< zKFpBB7>vb%7KpTH&whcpc%JRXs@Q*WEdNB_r-U^#@tM38cF)FFSO*nc4RE>j7kb-b zKAGP@8tF3!Yuu3o%3^0&PlNqdTNO+`>^x7H0mE*8?3VsSB8^d zm}ttlkKg6Olf?19Xr|4+oIH~woL}nXX^R+#yP><+xbNvmc^b|t$g?{x9C4LcYuRYW zW*mM5_+v#*BWRq&&+zi*(`KsNMiAK;W_B!p9!>6Y4$c9Qf4=Er+<{!U!?}A+0sO+$ zd7xVGb@kxBDmUk5y!8=RtuUVK)42xE2Q@}=EL3FW`g3b=W{3Ul6x7?t@IU*t$7gnQ z(u(>j_lV2xmY`5UwSN8v;n?5i5O@vxQZV$(zN!& z^AMdwJu)r{aX`s^Y35V>Sb?@Pv_UVHuy(T*aRq1LFXmE1*skI`)e;j6-U|uIHkClE z;1`UC`Y;8Jk6>9zxx*+4qUg%8#Qz{hjwS4#8T#;J*5U88tVA6tl`~~JR_1q^eCPa} zp15-Lm(LBr#hT?sT!r}B3(B_*+$kfvl4m+nnhKuvoj5&%|8R0m!V+J&?SdoK7RY;S zv;k|J-MLjk+n*uroM+@PT?*R&%mA;KxW#Q9XX-8-&Y`gc?GNv0^{>bLa%d>$h%x_s zr?a{JTYX=kdK=p7z7Y7~!HY4<L3u->--- z@e?zV`x(^TbtQ3y=lR~FVZZ(Wy#0Dh&^}Q0t>puhy3hXff5BIacD~QJcz$q&@6%*; z)UAN(xcfNR&u~Av4>EBd%J%VCmfRnG7V)xeJ;#4H#ryo^W8XCbF5BxQ|DPTIUmX7z zFow3eG&A5|;PJ_^2+p`*ha`SS zkFw!h3wKS>WyJB;E3VUICSRk&4Rj8R{Wlp}6|cK4uI`c_{ixh@&U29cumQZPIb17b z-Y*y1#49H^;J{?kcCr1elzYAOeqn33=N4$U=gC+GG4$Z&3zGribEq#i2DI?!Tl)*_ zL#N>a`>@Jz&K7W=e>HCM9A4MIdWbJipgQ=ppzk`pm#cI2YT8bhmym(?MRkq9SmUYN zbyh~euZL``opKB*H#~>~*LsnVlmB_7H-IzAUD%q!VlOI0ycWG3wBaO;TSsC8`8MLl zB+d6*40maY7TO%P*G)+}E4^GM!2J6V;=Vi>Kk@wC4A>tyO8eiHek_u+?F;Ld1OK2Q zZ<9DO=NRfZ*rY)>hT<6=O>H_WR*I;vLS8X2ieWZa^QQ8^gaeOB17U1nnmOl!I zIBfl5C1nfl4C6i5mi|mHW4H+R^i!{QWx_TcxwH0G??-?^x%76g$En~T&&#A;JG`s& z07Z+cR3-7)<7;?(t-}P9m?!oqi%n(rX+?n7Ijp`@!<3kXJ=a})l zEdI0)B@VS9j6}xKXkH~#ghsl|MdJ685<_LnPunj_5PiEn)TRAe#AWsCe$>-kuCohP zt*3ugPA-vP{XM~rBdk3Xo^R`%!OBSLs;vW}jI4dhIqlwl43y$}of^Y%hu7EnCYCiv zrb7eWUGwJh1tVV%F7tI>cCGyx$T7~(=eWi|ovw6k(%MgIj)QIoqg7mJ0iPzxb;`}- zn4unB-96$5V>-L_3DX+yEEJjlxK53?8|k@Af9O4*f)b;=$3qI*kR8scu!|jEo0P5# z38JeDU{haz;O;7Ccu7$VKK%@ULp{T$4H;= z>240))j80)s;3u|0xT-Iu@d+eM0`_Tt(@yPB_C-=P86BIgdfI2as7{n)Mo0PES|8? z=KLoi4z{^&#Bo40ehSCKln+0@_QbNrO3f*=A(xeHY+uE5!tG;<7Yg=g+zOf1Rk@!>`n0%RE%!3G`%0m! zrB}Fp$9HoW-+%cyWX~kETeg$&VLW`Yx8Du8*sjgziLM#f^$&J+ul888i{(b?pIty}DPf9&#tV-Kv$`nk1^TWIrj4VLkg zMO{NOTS7k5CJ|R2tmX0>YqEZx#W*l`#A`qUyyo7AnTlQDp*B=2@hr{hN-1+9Y3+cg*NKBA!Gv*tqc`M*bCMpvOC!vP z2USjvM@o>t=LG5Dj-|M7P7W7*MbJ8zAWEI49Itixd_GdPI$m@7$_|VihE}e|l_D!^ z`@66!g-OdwH|m(>inD)kR@bakPo919X|sj~yH>6m>FHg)^3*x2dWKi__8^laS++^k zUy&H`whs2M9qe3RS%*pbQ00t`^XI){Wm8YrVE<76n&HZ&Jwqd%y_IdlBY4WK@|3wJ z&tAE-W+gmVR@OA03`ZTbm;ZHf&FZS0)qn_F2DQ_7 zr*hUgudbZc*N-tI)LM2b{+7?GoYk@#f2(HWe;4Dc7H{R8ItTyqk)2vRG61k154huG zou1;xH?A^prx5Ycj@K@$Y5~~6M0YhTH`8CUayly8YOI{BoE~tv%XH8#^mK*aeb#l_X z^)+*WsA;NNoZ(}bIP{HVYr9vCtd(SQP1QAscF}t1pKY%>rE*qNJ2Hhytr<8SyB1wN zLue@Hbe+C|_9-_k@S6U?Hry_$1oXk!hDI2KYp(isBUHQI%xH^Y>*RSa^dw_B(DwQkC%EdjfaHq^(*`Ou_ zAS~M{v**mkzbi*DPv7ZC=AV3uk7Z>2P6VTkJR&MR6!Weq2TOTA{yOou3V&VrI}iD> z8vm+{Vf4Cgyc0>}2Sqy+ot8&Wo#XO*_w0Ub6Rd;C$+cN0cTul5yr8%X_bHZ+?na!9 zPJ5-+d)MbU`~Y?mkgwyBujeus@wWzlYw_2Ozo(z-7=2>N*39$w;kWrRI2ycsG*h;D zel&d8Xj9pe$50s2mdx{;FMB>3o-mqu{_*`rJIb<%HrGnMCF$VZ^=BoCG*IZ%wtDY!(Dlqx#rbm}t5RG<}kCwEGl$-A=A8jh%()8qL$F{qxE5==&d9rmKH5_f) zw)u`q)fP;Qk{ky`qnT}YFRX~D{u>Se*WFbIjRR@4#J6rc#y4N$dgvVwj~~6#xHjLJ^DM~pyQ6W)-KH|ce^qtamE%sm zJv;jCRvy=+b3A^_&)IxeWsu=zSV-63liRm%m*rM`J_;Dg$*&)$qcG3x#@5pyyo%%e zEZdsd#xGa!c^SCvz^~OGbj3GE+M&$W>g7KZ{jOu2DA4jZ-9hzyc8PjlVfq)|dB9le zoqGFk_#%bmV};~nreaHVX)^aqE%#lvPeK`tMvwPs?n_Zz)}mr*w(nT1JAOHS^vx#x z<~wp;a@6I!OPK4KGDLsXlCmo+SgXr|OfD~2A9ptYmhHLx+lsku6d?;gvb$N>8)jj4 z&t>7(5=v&dIJ%^4%UHPx`|!8ep4UiwZrg+HSqsdX^k{Y2mYr$R@7UEg{WqGQd+npQ zGXH?~@mSYiKeWqT_OA+e*-u>6QE_F*liDATySnL#CE9U!Y}_N!1`SzS=L4SSs zIQAeNWr+T&`m!tcE!b}#o9I%kjX#0Dx{T4{_p2TB+tPXCf70InD*X?o{M+n*DA_Lc zKQoqHec6Lw#`7tWRMh|ZWZnqKhLArmTpu4B?Wow&@x*9mG6ter*~VSn@mN-CWoFyv z+bew?VXc&*BgUc}ciM20V@nJto3@RPd%Rm}(fHJrFt{Fkitcce5{^v2& z$8yGj-_OUWo4ZsW_l_qEk0<~3<~RSh$3uS=`}lV>KHu~Gx7f=)(SMtz+++Rs)^Tq7 zB3<}sec6_s>B7C8+|@pOm+a-<`6HGKu(lLf&7GX@)K`waQu3| ztaWwf(N?Sq3F5_A80wdvd?g1I^_2yNn7|fYKS?Z9P~hYW(eBMC4}AGY2@33ZUJAH8&?lfRfG^>?p*&0pF~PLcN7S6O-86HA=Cu|78w^P>m840n+o z&X0alcz*PV^!Ja+{OF0%rm5kg`y>Ci7TqyNnimxhA<>$QA>+gH(cyjM} z@^5)Oxwn4qt)F}Ar))(8TMyzmEM6UB_#f@vzuZ0l;lC^Y*S+?0ul@X6wx4_bk%}F; z_&+os`a4=L`p2k`Toc;SM$g{)xw>$?*sikqjvH>rOx8EXu8(q#ZXceb+gKlsRQMxs z*zEctikQCQ)%D2}Yh|PL^_x$lds4@vS-2ZTf6!p9c{g0Rj zq5lzz?OiN3IZ~j<*2;JG*jmnce!p0`o~))kJh>C~lV=!MGpE1{PEV z^jxdY^Pa0ud(YLs*xqyX1-<8rmto3#u0GFu4$A%Y>}xtpt-h+i9Cc0ASC+y~)z|V= zeTBW*D!czE&^_rd_fnKcvOd%KW9RB~(wf@gjlJi8_n!Ynn@<>q)Z+Z^o&O!X|EC50 zd)O~>JL+;I{lz`My7#<>obcxb1s!F(;jdX}KYjDY%4p=M(Wc3`k)VR-7WF_HdIugv z{>?Ua^|%|Mx-wN);im0IqCc0BDE-(IBT+1KJ|?bpPl#(>e5m8G-9D7rC*z~ns#iWP z97wsn!WDk!u2d-IIgVM?n5R4Tz&^Y=)D<4DN+uQ@ukQ7i5ADnD_Wx4Z#~9Dw?4nP_wDVi&*A1)zH!-G zpJ9FM@<_Q|aR=k){4C5n{*vB2wtJ{{*0-A$WmnfX_S$E?%yZ28TfDDM(d|7xj-VSp1S>e%o3Fg{J{mo zxUnQJkcg5OXmm;G=3kZ#PuP6V_Q#vHW}e_(grm<~oq3}5>ZWZ=)=k3Y1M9YLrydVw z6Utt3y9S!d>=-^!G6${*Tgn*Ic&MM(H{{Ms+;i}CT&FC*Z8$$}cMJ2bBZD6bU_LAt z4drkVy1p2T7Y+TjxoA)H$iThJ^~g?SAg=tKcJ9}0xm^2`@~xR?h)G{d45t^|o%j6c zL8EV$%Y5o5Z)rm5KR;SM4c74a(Ir!17@r@l=N<=;G?74-E3!G`tHa^9*yM z9v3Y?qepYl%f@HtW64xRu?M>@Uzv(hDx&y{w6`HmWd4?FWXLmGo70K!WO@k)BES2lsIKA!E=3-g6p7hfDyCob7?0)uUZWpKTXD{0+uc4GWzj+(# z8cY+eyO%3TJIc2#DaChik*VCQ72K;k2{j5g;V+d??q;n;bUw=bAHhH3)xE1vn7nxR0a3DD zx?kX>w!eGZ!{6a~N7lN3)b_B8{o9V_Lw_Is!p;nZ{(O1MOzAC%J?6htaDKE$?>qWO zuJ6@#x?#eM1S$BOtUo=1e zZqutT*Y)#4Eq@o3-pTfvnh(4Fb@0eZc}d?z3calfZN21rBv!Q&3Yo|;N*mu(qd|h5coCHWi%=fr+0cjdv1f)6nJwX2?x;+F)b8;Hq z+12=F0@C=Z0cm_K9ybi=772SXAkE1u0BIW60{VhbKMd%L0^JDcO9D-rXcANcqBq^d zXeJ<)pcjxza48^_;2J{uRsi~{ggpXK>tsmcL2IwpvM8J%+CSRG!DY! zW}3#!04c5skZO4aAPw;@PyHky4e=$9`zaum;6y~BTDAcCprrd+K&s_?0cm`n0EGY0 zE^o&_8sE1)?rA`GNZ3CDQY}ldkFIG<26U%TD*=67pqYT~66g{@n#L#~1VGItCEX_gsg^Sju=o}L()hA~G`^h2 zT@L6Q5_SuqPl=@O0(6r=*8{p+sGk9}RiN7d-6PO`2U;3O0@5^20i2d1;sg^eY z(tNqaQ||?&As+O&KLb(;&Vk#2YI!lB%O%|_0I8PW0HpCf07xbHEg+5Wj~+MepeXvL zggqLNYB>v#rm+Cfw}e^`=w5-^0o^CiCjn_1w*t~Mz7I&#_?gG;f3Rtp0i+>10BMK| z0cnVh9`^x2DnWFJX?ZxH8ztT20I8Pi0BL-e0Mhv02}t9+&g1R|^lb@yFCf+OKLKeP zj{*9QP@e(xU4htjeNUiOfHaK}K$^xVAWh?a9``LkT9y;x%%UL<2c#ih2}nbn<#DS4 zsRUmEq-FUdK$|7qUjtGtkHZt+8sA(%8sFJ~G`?jXcPXInOV~F7QZ26rq-ne#(EURF z7@+?U=w?6<2(;f}md25QG>uaLX&PsG+K60cnT_J?_tdRD!donwBGg zMpaTks^uMkG`{ZxQVAXfr13rDafcorML&?RM*>nUX8_VP<^%enP-_AGr$DWM9u(-4 zfHaL;0cjfF2c&8I%;WYw!nCXgq#?3^G{ibU8e+ub{soXqaM+P}heA?22GB-8lcO#` z8p{wMjb#fUjpf}QcPpSDN!Z%~sczo}q%l7P=*L2R4A4&mI%Ar}ycm$i+zCiy?(?`0 z0D8U1@&iCB%db84IY1hs>?n(679dUcDnOS=*pCBxo1}XSAl2;;fHb~R3>j5|BLHc9 zCwN>Vpob*v5PA366Xn;jKpNjdKpJ0@#|;8{M8a+Wq*`7M zNYl6$(65F1VL<;S(2al|73euYs^xyiS{g?K(lk!?xN`ximhS?jA#U*0TLEc^dpz!U zfK-A-$C;Mr1A2?3+Y3mwyb+MbcN-wp@_s-X-_Jd+^!P|Fkee9o14y-;0!Y(17SL}b z=GlOLE6@T!j|(&kNYi*9AWh@5fHaM-dED;+sg}o`U?E-wNJA_Jq#>4j++~1Nf*%9Y zviuXEt0mnDGfc}2AeEpUkj8fbAdPQ>$GsoW6B711K&s`Z0BIVx0s5U#?*a6CfgS+# z-vXWV3QOY*K$^x9K$^yR9(Oe$)$$vFRH`3%>f?Yk#5RvR>O_;^^?+2%e+Be*N%sao zT9&^Cr13oiNF~_!B#ZAbK#E%c=t&7%1xU4Q0;F251oV_p*8zH3pkYA&BhbBoG>xAC z+7GzN(Nlm_=D&E{teK`|Hy{l$0!TxQ0@4ug@wl%7QVEWjWm=vF=pB-729Rob1t5*@ zT0k1#Cje=DU-Y<#06imNe*x%IBI)k{X&TQ1`h!r*PL87g6=*V`KMHgqAWh>EK$^xo z0cjc^^tf*Wa@OaS7Geq@4RI164Kd&2&INRn$nq6HT9!Wo^iE0l*ML;Z<7QiYa{+05 zX9LpsmU-NzfVN54Hvv*DuLh)PydTh?g!(Z+&kA%ipyveI?-WbpNI;s#DS$MMGd*rS zAl32)K$%aRL3*GjtOfK^d>}9-tC|9s)F8pp)iV8fO5~G?oC;G|uz5s{yH&-vFdi{lHTn2c#jk zdE8O2HVM`OLghh={}3S6_e+4@D*E09NcEjG-(o%-kjnB(KpOK|9@h-0RHSbMr26In zslEe%CJ6OXKobSJ63`@pehEmW{{tXRW53fZjUxdmt_qOqdl?`N@pezW0gy^{i^tss zNF^9|dK94|L*Fw2slLkqy;=0_0<=-69|fc_e;JUb`&~d9^Upo5^o%Gf6Y2K>r20+) zq^TVXXdj`@2DGn03jpmW&^3TGjT?xQbZ-TuY252^&jNbAQ0FbM5DkDdL=KRK==Zp5 z0jUI!0=h)PMz4vY4*|kTB_P$Z5s*r-5|G9>2uS05qsLtbi0hjZqmKeoEk6fH)3_bb z{zAPE&;bHH2_E&ah}Ir1xU5L6Oc-Ezo$M1NJIR=;|@E^B-j8* zwR{Jle-id2`8uOfsXYVeaG^$ZQN*J;Xeoe>6lfJ7 zO=AR*rZEag(|Di9eG8E4J8_YPI2@3McqJeWahAue2BZ>P2k0Qt_h*2#KK~KWM?~N8 z^`>tfAeChWAdR^nkjDH*kGmewG?D(}fK=aG0BLG>0Xj;k-vjhAfgS?%a)IVFSQ;5X zn#OAZX&M)L+fYZ!bQF{s6vaLQDhk3-q*<85%o!M&<`jyehhb)b(P>VhsEK3OM6bjW zHBm1bHO3M#F$SY1Tw{zz6H8*^y&6ShjT+I|>;L_%wbwrD>~jV*=6~<=ThFu4yY_eW zUiRAi%y&K?h|b1kHahEbMJVe+muF(X7M)G+S?FwNm!R9%n65`R%II!EH`?g>mbx%T zpc`UhH4dE({QBm!Z4Pr1uBt zYZYU>*DOt^h$Kr#Vw)i59oeuVvt*@zDid)I-A}V=&naL zFxH9AruR;C*5`-N*|-cjgmX!+<4G^U54JILtfp&Ms( z*P^pw{0yB9<6(3*jHg4{pemQ%LUh)}0(90zGdkI_vXo=&aAb3T4lu8*gI&GCG^ychK3;Vl}bY!Nznbx(P-%65T|j z>p*A2I18N(Ftk+||hb|1QY6Z_wyv+4a4Ivd)H=q4G{E$Aj2-KXfL z7+uvu7e*sG8^+1#Y#84TWj{w})B8_!HdX@{ITw4Pvo6MmvT}4b1{a|_#iaLIbT+;B zp&M$_`%q}_S#&!Z*-N3UZn5*F1>IWX%XdTB!{~M}E}jTwFQePu*!v9KRFlfSN4tE< zL1$yNC%Qw7=~#5rjBYBr=|)$8ZidnQ9o^o>zwM53ZdafiV`OKCvPaNOGP2i0S-}!U z5+h5Zv*B()muF;;hOz^WrDrv=VszHtdFUn@*^Qy>C3N{l_F*WSd|WK{O(UC!&bqw} z-N{C_0o}Ri2FC6|x5mgmMQ2NJXwsG7D0H?2Cx)^k(9JY?P>9afs|s{BjHT#i8PjHT zhZ@})bcY$;!{}@nPouN->TPs3jL$>an5C{>9gEJoXhvsUoQ}@AxGh}KZtKw55^OHdY%$*{r#5aY&{^3{=xoX# zLU*}I`IG2u%11Q0Fvg&>F_?wUhA}skHKU80bexFJru-Y|Y#8UGn`2BbM^|Wc*P$yi zx=+yAbPPG(g|RO>8^(lCb}TxZ@=MWK7uScTccZf|9t>q~qO&oWc>-gPN%`bU~SirZ=OrvDz5Q{)*1VV0tU#uZjHvbXIl+ zy3t0qF_dlJ7OvXRS$n6T%Q5!8AIjc9muqB0+MT^6=!P5F$)W5KbUPW@>!Iwh6WvVf z7<4v_ThNU#_8typlRDgpU5U=xy8_+r#@@zI_7S>0jBI45vsZ_1HzVr_We=enX=Ja4 zvhiK45shpJFb5peI=k@tYCR#UDt&C{O|OM z^;pS-hK|Piu2u9KW;2cbF}nVUn$Xa=tb4_nYKi-D_3Lxylbl@W=UWTxFy~P?va?iE z$x99 zhGfejzT{>k`O|&L19COPmuyDz*i2vY5t7P7eaUd@^7_Mk$rL184)-NBNb+a;&J{M!5NkN-$=S(CU(j+>Q zo7e8!`8|?#X_9{+i80ws)r4V;itTBVX-GDwNtPm6${Hf&>KjNlrAe+tlE(V68A=#298JJ6ajB;&xuMElf49THsk};*_lk)LHv&R0gUknL-HD|be2|YaLynG2g zJZJoTiScJ0V`{oTm-`aq&t1O6__M*67=NB&oJ;rTMPFk48NetK+A;oo>f15?bkT2y zc1*fX@g>Het9*&^=MrCH{K=uMru#F}ml%I$`V!+$zArKUtfvO2`*Wi&G5$Q{ON>98 ze2MXA2BnzpPk}En{?z#rH+~_!8sK4rUe?)D7cLe_vw!x!la+{Q9%r zml%Kk%a<5`Hu@6d&r~zh^Zhx@ml%JJ^(DrinheQPdwA(Gt~UFUX{x<%_!1NPN;5z7 zLvQyb#-H!_5)=BlzQp*W?aK7h8SG1pKL`2}<4>M1G5)L@9rfpOUt;{Z%a<5`Huw_b zPu~7ff5!R}<4=h%G5!?z664Rtu~C0E`4Z#L^S;FR^OP?!{wx|7^=GLsG5(z9ON>8j ze2MYr!-J##Xag?HdE?K%zQp)5(w7*2E~g6&UCmV8Sno@WKmX-Rj6WNFiSZ|YO4Oej zzQp*m*q0c8Dt(FZXOo#@`}OcaUt;`u&6gN|Hv1ACbc;1357T9Q?(!wZ)uq0~r2Twf zV*JTFH0sY-Ut;_z@g>He0$*Z6zsJny{dC>$OH8_6@+HRSXMBnAr?S9{j|pp$FEReC z^(Dric3)!BHL}q2$M~G*ON^_yFEL@w@Fm8dEs3Z#CB~o4zQp*mZhq9C%YBLQ=PqAj{Mq13j6X}tqy9Ab664QVzQp)*iZ3z# zj6W*s&s1Mx{HgUN#-CDOV*L5EI_ghut809TN&Dr##Q1Y=Q`DbzzQp)*yDu^R+~`Y;KRwM+f6nzK z#-AVg664SMP(o(Kj?C4sRd%JYBuz4*qpN;QNf~*{2}`biebfi`(XCO|4a<+fm9Y~u zu4=5Sf!OQK)#-sNV<&b6cgbW^OM5a|-`3j7&V0e7$xgDOu}dG?ZENo;n4Ir~3#;RE z8@o#DI=d1b9c>*27__YIJh7Qw^Omk;dq-n?T}Pww#1l8JX{_(=YAl$VW_fvISN+O} zth1}FqcO?%e7l>wB1ZMiZJkjsu-F*2x4fgV7auwsTN{$iZLKSk4Ru|01+)P_?yWp5 z$Ot*Bu&%qSjYl0VO>=H_K}^(T0VXzWVXudM5+tM6*$yT!yi<#=UX z>x#x?cV}aV7psoOy5_K0rcf+4N2B@B*i5k{8bl0K-$Ld0Z2JD$dLiU?{;BHFTOQjh`9NLx~ zlttLctu$ga)g8EGg&}xG5l5*$A;Xbp6mjG?yuevlQPa$#?t;F?1r?^pbwbhH4tksn z`%WJ5U;R;rT_cQGq?1l>`x&k>ZA83KZx^@<({5xDdlVgEnXV+XXJiq3Ubhuk5BoXa z$hZnU3cIyv2q}X|FcfO~@DO#GX(7W09Z!;!trZJ zwut)X+1#g3pn||t9h-?)#7@MUFm6Guu;Z+0&zgR9w%4t0RX-U@)@qbblgP)W*6v1x zb;N0#%}i5iXDJC&*Cf4cL$hod&lFy=u5)c`y(F5j2ASU6wmQk2waZ!5nGq&5 zWRE(D?#^~i8i{syOJj0nTiXfFx#{+Zi}BcGCa##-wbnJKS@C-23=65|m)!%?Li{PC z&GHO?QX^q+{*Z>PMI^0;X7|Id8`*6{GPIYtX0?@?Zbgkv{R!Jd#;}@^6BiBywcJJ8 zvvFXj=UemAw-NO>k;ww6&QI+ioXKYl5B&GkIq-9EKRC7HFyPK#~= z^~N~13pezM{is6G{mj^)bkcRW6O%(}|3U$M=oR|ITrk`N#@$5BLkV87WBcifb#`O*C{4TI3+u8gpBA{onGb%U@s7<(R z{;?AotHI7M0()d%R{!*3$5YtJq0FR0|CV)j8bR=*t-z@2iREt!>r-GTdvoxsIPg#T zQjn8h5LPhHUL|&FGVE!KEU*MrPR9jyoU|aPvVaOVu_#d-uPv=9EtxZGRCjk%!-VFh zWuv~77$=2gHANB26{SVx@v=nqs63_OZLWK`z8ULdwk`{2EvaQcrgKR{V`KZ0qPBV_ zX02VFOIqqWn(7*s9ZWZ`DOp>`!Sx4EnUFtW=E0pE^-Gp@H#IjbnKF4~|q$G%GvYtV!tC5*;>)K>%cMGQqhpXtasndt^YSWP1!I&ipiBr!U_8yWu zl>2Tj(%s$C%6Q-1+Qn({A-VFWn-~TL_`Zx{;Gp}ET&3eu{8&}j+|6IHjX*RKQ9D;_ z<7)c-4$aQ{#wxJ$4#IpcroD;IYOa&bA?5ai+sjcdPp7JjKb>){?`l&gnz4GmPnf4MH2N*AqjN<*~HJw4Rcxo4o# z_AHFnxi6Dn(K_enSNE68uYaM=Z8gW#tX0Hby=x_mtQGG|=hsU?e!U#z*Q;6bi<2cr zsgIG0*01xB&5pEDxl#QZ!L_v4{AygolY-8Fp^Mwut6Hun>j=80jCQ5CMC%F1W=-ET z3o4F>!e~9=>)mVg?+OL!jrSF1oZfw)%HV%)ZU2b;4uBZ=XS`{7J z%v#e8Y6`+Bc^xPQwH;zZNnxnAej6PDb6oYnPdoG}+thgUxRt;=`EJLM+ztF0X&zRz zL?op{a&JMw=1#DY+%ROak*!i_zf^4ZE9TH7{=P> zg~~zW+bx0o2J&0^bPF5{Z-tZKkDajZ@XIx`)>Lsdl;V-+Q9yVH!CA%SX!UXW>TYil-D<+`w{ zC=6AVzQgI8Te?iuS(G-hHZm>Xm+{R7R?wqq)We@;_1!RDMrG)z81eN$^>y z`nee%1)qnipS%{J^Bl34;7RZmcshIyo(umDuZ3?ytpVPG_ropl5AbdH4E!g29li%Y zgYUxah|>p9S@aRq=VCsF`h3PGP_Mat3hUwLP#M&B`&ds8fYEj_iug&nb`c#D*JE~Aq<@qfjSahTE$X#hXw%zu zk66s6vdsCj4~QeFC#u|<)!WVCCU(>tJM5?tolhx#stbza7%r)M2itM-mr(Kk6^!P^ zY-6+cytoSUBO-YrHwtGO*D+hqi?EBpYBrT6H`HQPGT|V(^^Cx#@8=IY>z=84?MPMm9}Uh`yS9TO(Zt zoc}oSRhB$Swf_RorovP@iC%1KAU{18>rp(;fIGu8;YfHERNR>NWYht@*p@?Eaq-cI z_z#E;Hup+zCxtyLQU~Pb0L(;vPTQ*Je4$<&dM2&%-zhgIPO&|r6ML4HIqd1h2FBPy6qR))dy_$*_eL8DNE z8?V@<(0wWQ{ip=2hx^rCBC$4W92J3`Sio(k}_@_3|$zF1Fu zOt&2j@H2Dw>1!;+<}ugUF*Y;zs^I>h;C_bnz?g??zy||Ma;mnb_P&7Yo7Yc0reS)CRhWHhfCoJa2afcC%`ti8lDKxhMn+o*a5GD ztDxqqya?8FCtM3R!c*Xr@EdRoJQcnNPlKPsGvH+M>TIa_(z$RUJP+!{@^8ZicmdP~ z@jBQIFM=n*OW^77yYL)%IlL8q5B>yR1%C;zhL6Gjgnx$X;WO|Ws6U3e7QP9uho8b9 z!W}8_8=z{=&9Dgm7#8Yij@*zu=4X^?uj9_~oo%gOam&z6 zJ2ud6jq@)*=AN8m=UKd#*E5=UeG?u8d!XWZ8jPl0W3m)kV^lQlyrY)TwF z)c@%GT5j?%6Hn*GxIs_cz0+^87N)>pRUzq$yxK*NNS2U5#c8dyFyc=ZrYZx|c6E zKHQH$qkMB?Yub`kz3)|AD7B57u_m8*xU|MB`vf|aXOoNfzn>7*5F;}IS|4Tqu}|i7S+16I{uciJHRAP)%P7N zziMMEKTJK^0%vgr4?1Hn(g)>n{|Z#Qd<`B8{|;4~UWcc{H{dz&AMi%_7W_5b0)G$R zhEKqM!Ve)Y755xO*zZAoTJC*#82kV(fgi$l_z_$KKZeTPPoQ%63#c)U9O}{MSo*@( z;Q;t990*5}-a&9891Led{y3;70f)mfI0Bvu^WfQV6x2sg#z6gH*#xNh#6{JSb7}O`q5i;Z1{@7%!f|jGJOmyJXTb_s1CN4d!z#EAR>R9-4ZIW9 zLVcQK0ek{3gj?Vus4?qks4?ppxD#9g^-+@J;O=lK+!OLTc1E9b81D1QLN}HiIY<>L zwTAg7`54{vl$%{~Bc8g|K1XjXm`+DQIOT%ko+VpktrF=DqH}sq?4{e76rIygiq7dL zMOO~Ih?L%g%#7U6Fzr;)RBkpmo8}(vFtqdv=H32`_A^|mj-#}>`UbX?LrumHP3YB% zd8|t^hUC5&n07X;Xf+lznRk7PZME*XquPN}%6GNVaa;|7ypgh1nJkCe`(FVyuU!c> zpFJKP15bcUA%BY1b0Tbo--2!MJFp#o7k0p#VJCb5c0sk_Zm9IFf!bGH3txmM!H?l7 zP#<^wCe(*Pd*BRsI@G7q&VUv0EVvS$1Np>O>|FRgcpkhGehXd=&xhB;3*gQ0Kj2T` zh44|h4*m&V0UK$9>!A)*Tnlf3H^3jm8{rms3w#IO20wxu;3x1WPy_ZIupj&xjE>LB z_af5hD)0{@ZAE=jbYIwSE2nR@tu(ZC^QwqxEegab7Z~@MttHZUwtgFFIEO@AQgq3k z*>IvmZ)U?uZ&1NxSrZE4Z&2D`o#h_-nsH)Lu` zX0A5Yh-GB^Ftw#oTzdxcUr_dHOLs%HrF-C5crR4Z{0gcqZGw6Z_+M}xybo$Tz8~HM ze*>R_55VW(Z{dsZA^1=DJE#=>0q#WDkHWp+V{kfr92UVR;9~eks6F35!Q_VwRyN4^<2X__tG-Em- zb_rEiv$y{Y?i+*qUwikdb(iKyPASh-zw^0*z+xBW*k>J=!%4`$2Q}aOK8(Yw;L-4E zxC~wcHL3goJOy44{{!9tFM&70Ti{Lb7w~3y5BxEF4BiI+0&j<}z@Nf@z&oJY!Ox+Z z>RoVWxDn>TyP-ZM%qLlT^g-2M!v*j+@L2c&)LzJg@HF@k)E>ygP-*==ycGTc{s2A- zAApa+XW--TS;(I^_Vgj2{tO4hzd*I4|AA^p&%j;bU*R5bGt?*fUVxL}-{36x5}X5H zfm*A*3Kv8E60&Crd>uyH(|1U}rWUT7*Lrpj?p5vI=F(W4h_olUk)1QRcI~x2xsxZn z>Zt8GdlX1PWl^SO*+o)IE`$CgQ_p4D+)g&Pn(?R_FnLMUwRxUzikIpd%T}|`AftDf z0w}H@KsD=+;4;Wup{ECa3Y8A#O&NJ}G4e_-mp2t?{Juu}Ytgd^a-+URJb#;cV@`TC2kZl&qEnDA5@e!B87VQS}A-AM1xOTF=Gsf!s@x|GM;an*21eMG%dnm>d4 zz|Y}W_yrsf`>@xb{hz*2b3q=j_Ef?CuoluwX5_u*PAY#_VWRc&M$Bf%im5CqB{wST ztKrO4-g6SMuBEBo9fjhIVI!Lnyew_{dKW;-8>6E}Ml;j(*MB8Yb6n4yP{_ghH;^oE z>u9O#GLBSH^T=_Q)TX9V2mQCuV~VHpa4)WRWrpIfolQNR0Q0$@2-PR@p~Rkfa4M{a z)8X-O22^912{kjB1`GS)LN z$=>F=lq*`saw9wXMEPO8ma#cOmnvgc5GFB~!7AStHOxJmSDqbp6?X8^|$nPf2 zitD{F5B?G!1UJDMkWW?iRKxpWJNyk)**yS%0)GpifWL5{a2|u&w|E@tlkQJI z<;NdkG>=tggK_Jsx$<~t?p+>lL_asuj^svmKE=;Nd(C6hj?9Z5;mcd<$rM-?WqSCu z>5v`|%W~#(a<`?cHe}9H>*-GpR=c^_qgv6mk|^4}qfLlHMZ8r8Be?DeglCW^O3Rrr z5AuiTJ^R74;Y4@=Y=!IKmGB}cw->|BkiSju*@1kx6zcrdRZ#QvtD*Lc{u63WydG*D zc@6v(ydJ&=e+acFbR&EV-V8s2{PlW|^7mF4Ei;w9lwW53xZhft$&Ku6;5wq$GBfQW zv&?XlP5u8>W^25_6mON8(%KxzKP69;md~KZna|;lu>U~LpuhpJ7V@X{J*UF$;Z<-b z)C_e8_yd>&Z-u!~`7#_v^ZGgDm9onv6&>UCY%CsWA9ADdPCT~Pyw;hLw3eY@oKjH+ z%H;A_ICtkiAU3OtuvN8o2YW?oR&ENQW~R)|Y-Za1RkFLenDi(0R8}%I7aihYtJ=uE z(p+IZj-68eY~jK$^Vflr59hp)@@{9S@oxk?814$E!I4mXY%xCc}pxfj&Ar@i4Z zFb}SR`$E;H(eT@F3|t2ffS17o;d*!wRGkKELtZKmj)Q8K zOW{OV2dBV#SPC1U%5phe2vR!vpKX0$2gc`&Yl2hJ*cFzCNsh2%c51fLxRJ?aX{Qe-zfsw5qZ+EX% z=wwE)KIrYW3RxXVp0sn>w^GzObebNcfO8XlhtrGj#)`5~b#V|f+0}EWM&1!OgF3P< zBjY~;bSh*l0#jkzbpDRsOYgsE6Z$lKGf$tA?ag(q)H)7}1a|FKb`f_9Qo+elDfc=Y zq9_E1g?C4sgIFbR&XP1VHglrHY<8@S@+EXvP1@X1mYid=b>l_T+!#J7*R7fH&zSj}L$fj8 zk+~vDCAS6dbnsOkG51P6&wJ5WVSpy#Ivk@tb*Te``!_U@qXq}}oZB;MXYSn`ZlsO2 zk*lq$pXuS!GbO3dhuX6;U%(06_uIklgYwbjo(k>d><#rtp8LSja9^lDS;>Ri2O15v@3|j53+@lU1rLPU z?>PwG1;@dMAfI&Zc?wQ|e}(z*WjGCLjyMbMKrtQ)hr`3*7 z33vu9h8M!QQ2VKTFxot8m=Cw79Lk`c1D3*>umUcGm2fevhTX6ho(dPhGvTrD$FKo@ z3Rl2^l+8*w1UAEQum#SCZSVxx4o`(0P*t-F-UZjdr{PKPP52G?0sJQX6rKhLQ1{M& zs)J|4$?#lw7(5TMevN$_vObNS4_TMS{sXRn-+?E?OW}p^yO4Qy>@vt2Dt0-18(sn5 zhgU=9kg;oEIlK-og4e@i;Sb>jkWXp%d>7sXAA+~SKfs^B7vLT6efTr@3H${d#xt6` z;lc2i@I?4u@ML%&?1A^go8WKYPvHY_GkgfX4}S+gfe*uxw4X=dA@KLG82$k+hL6Ec z_-A+){0qDcJ_R?yr{R0>S@;Ef4)$k){Q^83z64KzufkRE?~wN-VsFBWwrBqyu4deQ z3!VbEz#HKwu%3y*=kRjam*?WQz z%y2~d%-u56jhX#`d_+zuO!Z?5cT6Dc;Y_>kPlJlf=`fnUQGwmw($|goA(8aSjr`q> zt2Jx-!u?llWK*m`wwXe^=i#SO;YQQ=tssrxhKkPxS<5>hA+VN@NIYvWG^~)EgV8P z*Fo*^To0Aj8(_4K+=hKAMO-S{2ELDMS|tDEMs?%{u7Xtl>B}k^*@u;E%F8~NU78ds z7OIu@jIo_%xYs5nPuq76^S9CqL2*<5(#4tQ+cK(Tt*-bU1xLdwSO9q!%AAX>g&Nxz zK&6SlV#&xS`6uPqGx_Q2nbscBzCvzfhi)adb1I+03DlS9D>PqHkin7c&ak^sZZz5M zBBQ@hxY4%sC#FG)%ac&?`7?YEy8Z;M*>4nkOQY6s(f(o>GWkmv8yk@|jbEa__!6m9 zJId#BO5sM+$TJj^#%H18!=6D#8b<^k^p-~DYc!2=qckdcyQI<>RK|Z-ubc<*1N+!=90V1g z?cjURud5TeSKHGirGAU)gSl5<*u)hrN4b%maa_B3Y19iU$!0zmks7_7x7hTR*KKL^ z=E+Ua1T)&8!iuIVmvkt6_I`U52hK@kq$?l!*3xwX=Fzf~8~Hn)YxiE#6_(vsOj)$N z6jn4{dj#oXFWWq$??aw#_3Tdk8X$c|Y&q0?cm<^0#MtlYp^n9xAayHt0-O$8AayF%3ZwOA z19G)w<(`!4%^uLTEzN(U&s^k2cEr86S#QDyreLzDZPuKOvxph50pznB2%o%|zfSu1 zR~_v&b`T zhV(x%o{yUSv5TP27+eb1!OI}B*yS)VDLf*A6U)O7if!E2MIDh1ZAcp zYI94uoKhN8u57=A=WKpN{wQ5HK{}n-%`gw%0t?`+a0R4J^qc^1hu?rdfy#@Y!f5`E zB;U7{ztM3{ZWNF0VcypAH*ALgJ2|YLS~;x8UBN^@*sr!{1$v0HQ%ZyKS8I;0K==Up zqjdciDt{k@Q{h7}34aG=_hGmWJ_6O({vK|IkHHt=<4}F)6L2u${1GazI47Qw|8ub? z<#H&xmOl-%M5KPpjmGo@*S@LzkDPM~*5k|8b~S#Pul*?VG|p=DGLHnjgBFNXKij#S zQXG_j%CCk%xS8}RUe80-+ZSLC{2Sa2z6kT+OYlJWGR%jsz?tw>SO8yxO55LIw7$lX zOZAptXJ8gR&muR9*KDp)UoyYKs*9U!iq2uHIi~zt={Zy!lwbbb>`l_Ac>M#aSK)k! zSs!kJdvgCa91Y)r)m zZe&Lsoyw=^+|2B`xh+%YKhAuWIl!immeV7nXY{20ArW(p$F_c6OUn$WTgo-{r@?f~ zouAG_l$yM08l_t8Z%{=iX1dpCtBD$`O1nZ-89v74l=4Mos64tq5Dw~V*SnnCHD~p= zgZp7N1kQsz&oO;6XXfm)DA^(dBy9aol|)r;-N z%${5{b!A`73nFzzZj?@O%(m)E*q9WGQ|fF2_5VU`@#kWyEqdQWjWet*wvY7di}EH~ zUk)Pwm2czV!Eii01Re|*!HMu>$hmH_E}IO$%l#DieaIiLo3rlIpvr$b{1u!DAAy_$ zH_tK;h0k$+IArY*I|4HI*SnfM%=u%S6Yp6I3*k2)?<1P;^%TP!xStE3g7aXszWg44 zrCbR{$E?+uMfX+ZMtz;y&3>u+(!@7``9wVbn4sNw?cHOZO=X#ksT9-!xFvG9x7_Y| zpm0?N{y23FX;NISg<5m{0IK0%2Q>~|51ZhP@Fe&ncs{%d-VQmxYrgSyD^z-Tzbhk; zjzliiTOOT>S#)hIH;PxBYyVUpMaFfLWt!L66ZP25ro8-e`J*1xbePyT&-;~O>f_W; zIi)x#zXoz076|VleTvt;Fc01j4~4&h8h;*uiZk!_WaNY93F=4ud{9|Prg7*TuEI#) zA~&+5vN)jEd{|Z2k?iJVRnp9GOx=;ES(KL-qcPTM%Ju&m7xdP1Sa&Kt_im0e2w71e z=e=7qM|=_vNA?ul1O7Lh0C{i8oMU?$D*n&FX#2Sfxe7v;l>RPzPjbZN$xo3*^F(em zC%B1g?6&hHb@tf>f;$s{i1PBp)eqO6TpszyK~~~qhH)4kiIFuvh2BNp={N{)x2Y~I zwU*4U;;g!~9aoK!FvlT3ln&m7G;7nhp*(&M&WG zhsz~3I@fs|v*><;+-MwE-+JJ-^OM7zriLk)EQ;K8^OHPEQS;}teItKDt!$PznzyLx zX{qSFcdNtAvXX7Qk>B?H!th;U&cHVlr1yeDqP-I9>b4iLc0xulKHj9+0^f+GI9+yvE69 zj~hq*yj1+7dAWeRQJOe&W!80kFUZuPW8hNc$HF#v98|iKFq)T*$TgPgl2Tso3|(G! zqK~#MxsjcPTnG1>m!0WjsS5x%zVhmpddG+<-pXHsnTjF6NrJ_4I~qLt$i5U%PEYhbq?=mU@9HzRH{JxM~79-^S`u z8ZLw5Am1A?{puA^cD@JI7OsR^Ctn4>1Fwck_kY4@+ZfYl>*LOWm`C$cZie8WnBQw& zQq8*?lNznHL{ZsfQRL;;A4g?;86@K=!<5Lj$F@Fj@YT0b+(U}=t!mXi? zjb1{PM=D3nd#?=SeA~>7j~n0t$bJGf59U0+dCti9V|tF`ej{87?}lf>=b*~*c__dB z27drwhMMQS3N?THJG>8aj@X>p{Re!Ud%io<^9KAU)U$|pVYEJUAeZvnmii;tw$4Hy zofpcD?5I6Y>a{-DZ)JFIkzzZW@_Nf?ZxY9T*n8T%uJpW6Je1e|SlqY29gF)xjm7<; z#^M2R5gZ6t$PHBd2g7KdT!mbHrJpBbxOaInh%%1u^~jCvh?BRKCt;7HP_n3VzQ#Kg zUvC)q*E9LVOvgP?nz(B-=kZ)dT=!w;aDFt;S~9;%zskg48*_HOM|rawJP7i=Bl8Z- z9IDitYYASU2=lAb3q^5Ne))BHJo%vbPlN};DNy~z zR9FrVfwgcNR2rwlXuchST*?jM(fRecm__qVZq%;Fb4~3v-`Hy5!O_3euCwHu8w(2v z(<#M6c`|@&Y9K5kjfz_Wj)uihb!jeCeCNSv9&ALeGV$w<##2{!^!zE>j^##n#6x<` zgP`t&?O35?QJJG%WbljJe%-cf8)-K&(LaIfJW;DXzN@*o#NjrM*@sx;MOo=po-41K z1NlPoRC%!&s{S1fRUXH{nJ@{}_UqtLa2Z?#>tP*ifSs@ro&uLcorhWhqh+-paw)&8 zRNk(vu0=4{yON`i`I6$d2MQz4v_5Kk7t2{P5+wM9rBL zr>%bYAxnp-{3_sbN^wUd){TlP={-N9` zoRhg`e2IJtt5omVqj|F!xztz58@W+9m0XAS znm6p3HkwC6|0{X3l(;yh_$hC;Lwn`wCQjdlim_uffUi?@;?= zuS2Et4H(V4%063f$2xbHA9*$+H>&^QY%lNht@JN5-HVLMkpq*_&s|Q+Jmr@D96$Q; z+poSL)ds>~66DrLuCq;FpypsBV}YtV-NWUS@8x$B|HTF5zc^bz*(>l{ue-o4BG zU9`WDn|-mX_c7yMxdz`Z(reA`-G%VeMGC_y`5h=TGYgL<@(o_|Ji*Un<+&QHJJ#0g z>pD8(qFT<1)19aa-w#*n!a}m|fh$7oT*2GvbPB0in|*CtONPGm)9yce^nKD`385F& zUk&DR`U7!$RFA(~)@#ceTr|WuiU9`)2OWWt#_C?FK3i{hxvuz-hJ?2@8(K5^LTJSp2*2P&!~)=z`a`o zYzX|2fy!F-bPCsXfxLx!v@iFqa1!i*GhjEYgsb4ua5dEUwH7L?Plo>qPlMON)8P&9 zEO;k82X2Jlg7?91LycMAf$zhM;ivFYsIzLk-)jCJ;0ma7zTboS@G3YP@*gAS{{XIr zI!~}39uKd9oDYrN2-m}#Am^51w?fV*#eNJwhZ`W761yF87A5vm$Qg*(9Z=u0`#IFR z&Ue8^csFc^_rO!&y>K1;B~-C)f;@+g-3Rr~^KT%}x?&GPo@vE+Pq$|m_vWm;XL?9SOfnA)dru0(RR%lYqRFcA-|+fVSpIvwQHSQo*L<|-xIp`lOy(3v}V^u`ps3%SM@mP6zm_askzFVY|T~8*lVt8nr`Kk z*);tIq*`_&7fKOv4?^5di7Na<);KmTXaLGMDff~;+IP5alq^unmo4aV5$+|vN}emP zUV~%d>+mr62GpGRP1pe6f{M{Qum}DV{s_JYZ-cypZT1d7fX{RP5quf)J$v)*Gd3i8 zbpEX$oCN#BA~*o5oCd;Z**}MS%>@)cspvOi3UF5zDSNrug-a|uO?8B37S6-=q->O@`@sES9xQ^RpvLw6;1W0%eghr|Plw~+58y-?EnC$!sT_-p z=e2huFNk~tQ*P)cV*79veVMY|#w_+rm(W-HKjCm+E}wWhrMN3!75_1Ta1QyR`$DKR z6=%t(QGs3cJyOwqx66=4zr8Cr@^?3`vTfwkSIna9f4}C=fQEgY8G=p!1ID!%7r$%9>J=kiD0snl<&oc_0>bf#`*q#uwQ)mgDTl?VDj7@Jlc_^{sz)6)R8 zc|V$8qs?!`O~Dcf;oC4o7mJXbku z&8B`q>I%wL<#8oE1YQjn!u3#gu7M5kTG$MK05y%g9$pM@fLFjD!uOzSLug|?*IN6M15&zA?K$=snf*~7sXYBP-p?op z<=>rf61)pm!(YJF@NRfDyca$VH^I&Dzo7iO561BK*HGVdd;rdbzlC$)gD_goN!+O& zxN=rssQqLW$lF|(az)?yl^fYPhO5#mXZuc4J%4%6gmBvj>$mp4w%bPQCWuva<|&P9 zIIDs$mDn~i0}DeS9E%j5I5*kHZ7u6HxK~W0t(o8Cx}SKQ9j8-sQ#b&`0OR zaw9w9QK`IG-o!hg>2GJr=Pc@+ukjo)TGw^2zD~KOuOMoAq(_1kRKu{7Q>U1!lLcOs zlm_LWzpuNQd{X*efOFyBUZGaz#Uzll17LAnI!HT9daku?ew9w;@s3=l7zy)y@=$620Lu3dVLtpA9t!zp zlG(TX43=^KIXo7A0Tq+Jd|O5RLqB*r><`a|1K>q)5LCVnhS9R({n=Qa%($dfR-+-A zV%q;sm`A_CA~&)lR;S9!uk+!t?mX;eQD$%FD|{@px0E2 zvnj8cwi8VK$_{g8*mYRAR!Q2f$;@+?dcG)Z<*&bnnohbDpBYf{nNaUR918Q`;qY*H z1T2NKVL2>-N<$n*^M!Z!%)HojHJTUakt;4=4#9jkI&q*>B`F+GyOP{cb`Ia$BMtZi7=2DgaGs)drSPm0MLL=AYWsp=u~GEx{C& z-zUz%itO@D7B<4$;R<*^TnRPKHNii^6QIIwhVQ~wsCQi3q53|)LudX= zrVFY~t%3z`HLQZ)fZgz$P-~_h$ouHA(_pl2X{{#Z>Q;2!c_n5uBI|RxQ61lnYhkKx zMfP6Yv3@LNQ(nt+J15x}of^~Q*MC+2={HM^LYP+`@?tPSol7i3_pNcuY3fn;m1(> zs-MCn{0y#ybpAbjk0aJ6%XgJ0AaB5mt5f$dkMZ|2WFGx5SIM+~78`r5Q_W4h8>IaV zdGC~0wKA(yq;_rn)^*aZVY-6ur2DPw=%`!En$)}>W+o%re9R+obF4uNDE*nV%Bab# zk#6KJcnqbUeIvKt_j>&vTW#}xn;NaP^naITSg`+@lv*EbbSZ|)C)J^yxo!#MCs7v4 zLk3{8k9iuL$o=VX8axwLz_Z{&cn;Lu^<20NehX^0bv|4R{{vnEFNEKR-+?#5i{U-+ zBB*#@3e}Ha2LB2#htI();Pdc%Fxvm>Td_+pbNw&#w|Ss*aek z-M*Twsv%#U@~XzaacFnd#PtWdS32~FM5DI0oYZr-bNM^gZU(D7Ufx`{!pwx9p|mxS zW6{*AN4Q@`eG5l=x2Wmts^gQ_3d^m&Tbk@-+HG%XvroGtzr_oM-P*_}EbX_lJDd0u zWVzM6L6u9>0lyCJKz{!iIZDK@5Q${^SIv!YOOj7 zE`|HSbKzL1Il_TZb?P9fxxqN7@F&2#;6(Tbm=FI9C&L%u6sYgQOoe%HI#mBP6UN~z zcqBX&mck>T;x-$83l_ldz&TL;a1p!-CZL|t&V_fwd2kaffltCC;q$N*@-2y2IeZUR zzzKcXdx5-99jk`CCmpMWHE;nu7A}NIcr?`ivK|Akf=eLp4#$pzcfdOM3%CqE0_)*R zumMKf&~Egr50WPuN2G?cA?bg=eih{tJp(8=Di^UW)rKN-nBe>M^=*7pU2RICI7LHs z>fhL=w%##+MboVwR8T8aYdwudrqA`V)nS{fnnhiMT1<0yODpK+8|rEd>SJA7cTcEv zZ@vrPV2=yzi5;~$_i1|BQ`7ECD6*%+2^u4w3K~|Exzpra!5(kI(M(_VWml0>S70I) zJ-MJrX(?PsB=pQw9zPaXJ|V4H^Xg?xM@mrIfO;^nw7jV!wQsKFg!|*?R43zlfM`cC z9^am^J}Md-)?B}*oV|zpa8T4}c1aLqYm4dL)^HnkZ!$j@fwpqH>oRD+{^C1oE3`(`t*i!0GT- zSPXB6irbw~>#B|LVt5z44c-lZ4Sx;QN8S(r2mS{B1O67O&>w<2Z}B@g4n7VG;S;bN z{s}ICPr?=OukbAREL;blgWrXl;hpe#_$&A-R2BF;{0Dpo^8J|DyYLJ6KGc6ye*l%% z4pO(=(6Ap=pV=SQ!-4QJxE;I_ZV#`6L*OlN zC{*9M1H20kgQ^+BA@9`3c7pvVp`GDixC_*Ij@_WD#9okhabtVKO1LlNJ;K;%xCZVA zd6z790K5*4gS?v*I~YC&C&FCD{>f1Pt~>?u4nk}ioB^l9A~*vc2WLXge#Z`lt?)2- zB0LOik->L)Ie||ef-`uc&wZC*&T!*{g#v5==`AAzO6pKrEQhoLR)U< z)e6cfH#Ot_^o(WNSL~6uw!NsWQqn2d4dslXsLuDBsDI<8E{xjHM9h6Rm%!LXqH zd%xrVZ>-c?o9fBk(3Rek`wrIQfNy3x6mO<`#vX9}t%T)257(#F8lj7aub zLVA44h)V+hP|7qnf~AstW#EIq1@{iNSK2sPm$X%l4@Yt>3FM{p2WrRVP|wS%psGeS zoClAFNw@^AgvUS?%5m@vn1tuS<|DB%-7jl0(RDqlcHEx^-e+bWqx5EqIUGPH4x2A$ z$Tx*z--Qd|Wv~T)5AvOy*p={C@CQ)kc|Cj$-UQ!)H$$DzyA|#UZ-e9E?Qk0W2|NP+ z3?2pVguEvo+X&U)-vv*BzksK~U&8a?Cio+GAN&>kHGCaD0N;hbg@dR7zk~XJna3gT z@Wq~hW8t6RB=|?Dit=YTAO02A!)Kw!fz9wt_&mG?{tf;Nz6@W7ufl1}Bi@AiZ;~x= zA$$j}hVMfDYcTc!ybOK_uYe!H_bAUXTu$vDXmSEZ_dkDyJbFG!Zb+{AkI@siIj+>T z+O6!)ZinIdoMtg>EpxOr8xnOtZor~9n?qjzA~%l>FjU;cNg+%6c+ z2Cdp7-)jt&%2)022(C|Uq+&yJ?7l2@(!7Ja6P$wi&QNo^kuVN-gBsuWfOT+BxE$^c z*T8+@sc;lL6YdAKygdM3568lr;DJzkY2)C-@F1vsoB%(76XB;Y9}XvulcDz3WqCJRI`P@7NJg&jMycWq2H(2UkzHNjeVJk)vpX1D~lK<%Zq!EeBJcq;6GXTWZF0bB*w!PQXh ze?6V*h}fXuiBO^{S+uyku%a|sF`v1)759my#ETQvY~Kdfd%j2+6jxN0#cO!%=*&J( znU$85mDJE#I-}20MpcRGirT8e1p9-|^wX4SQM@M3$q{GrNy?RaHe5v!uX6ENZT(#`X=2`(!mX zadSTO&9GvORd^pWg!GBcDJd_S7cVa=P1G!|OjIX}5|xSaqC|P&VpGDGg_ekaO>K3u z82jX6SV5FlS?X(i3M>^?l$R$8Yn0nctIYfP=2eNJlB&SMeu0JlzJ)o7xr9SaDy@hY zh1E^|4DhWv8w8YQX`pY3GR)TK>fg=Ou~?D=HVqMg^9J_?D{i5NlP5qiU&8%tWn6 zLw!4irSap>&x{8qP5vo|4SYLMc?a{hxXdFc))s+?1B?>KGQ$xiK zW4DKIo61u|ua>B+sH$;kiJG9N$_paBuWu(_SeU4+sfw4+We9ei z-6-EiVMWFKl0=fGTN87A&**duWtH*5nq*}~X-VPYBpqX-WC6pYOZ%8~%htEr%1Zj+ zYOJ|Bv0pZ8blQnzkX>P}@87FUo0`z#0liwRN*qb9gcis4YLPrFtE^$&VhjAhUM-d; z;??tFt`j<_S9|Kq=T^mw>@cb-KF+rrWa7N4M6nr%Wnp}pg(;QEc?sNCg{5(@Z(dEV zQl*)Wn2ZifV?vOE3BF}Iy6Tc@wT2A)uBa#a_R~GDPBMyAETjxw)ynrRo4!|#t*W9l z=7OJ;W+S5|x~@9rhNH>8eN){Ni)t!M<0a)~CDlv~X|}FxrubGXnM9RT&!Zy`#}QZ2 zruz2O3zWterw1nph zONxsVMahgY&$Z_nzU^sK=akUQswy;nsWx+4RgW|~44yS%#hK~5#*N}ul*|v!XJs{? z6q+BJ)qHYjeppuXDWUn{SKB^eC{ZOxd*Emca{*3;*zl?nbD5(T$7@Tik1`Acli|GirDeRz&jP}P6|_&f zk>ZlM$!dmI=BpoN{+V6DH-;SS;OM0 z66Q&zi$hn;R*b9aL}6`JNzLLU5e^Oe2ZmJ@6*WZ_g|%fG3^j3+mjeRB&_D}c84L^z z;^l?&SQTlqCh?#^Z01*qWJxsxT!NHU+95$!20Je`;W1VM3z`&xPy7dtv}33D8m++l&R zsG^MSIn17%Kpal(G}%#*xy}=pp znOIa=VkhrOv({8cD)YX9xt5Q~isGdDNiFl4_n2vq?DPxl1QWz$I0078l7;>e3tE7f z{R|ln2n-py>1yYh;o$+~ePS$~=9bPOYMN?kY%Z!Ouc%4dNoul~-H1}ty5!5i&=*`W z_e+>MD3d`h@OZgKp^~|pUuvX!pUuWTv6@OMd}-;Nc;S48h>{9Zhs(8nVym&d7#w&} z%Q&8-c`mG|ns26Q@}ggMFG|W6(1MD>2yPenLAAB3Ju~>r_w7?A!3s0MLcFHRt_5Xd zNXmwFOFO3PsjLh-5!o5)$I;jdgWe(K+_chE-tXv{#Eb0?gFGANdp3`mPDRz?;)+sD zp0o{hHCEWXp@Pk4mTfmTv<)RWyEjf=%!ZF{Oh+d(_Hdlpf;c@9M$Q@gIL=75L#t+! zL2|}cjx#GMt7NiVQbXD+<{W9-)j-ot)|i+i%4^F^yONNyHA1FxbbFz=Zy+wKD5_(dF4at&lm#*v5Ev9zn0biVz><7mAgBD})uD7yAgwLe zI!%rBjN!^grcvcg{sCd;2I4+e%qEC&FPrqhvRRa1%O+)!?pM#2%M!KuSLNnloP6GSdwvv6)m}Z}~ z4!e~mv*e_o2_^1AQO7KCe~GJWSVOXlsJ>iYkuhmr6;;KHYfL7{lz}PDw4^+o9;$TZ z>j3#$Tv<$qXFOJCCZ`NrX-?VGsxcK&js}{jELJAi4NVCLnP^uoOwUn9xio*O5(`Sm z9v6Q`yEJ3sS5X}1#NfcoApf)g{RtuQ!Gr|cbyalLbF@%1U5&OPoP|E21v81EE-kS8 z1{x3KL*LMXhB@2U$^#YjZ8ij2b#g&TRZT4g?VR;XcUG| z5c`KtnUJx{qb+F1mTkm}aywa<2gFMrFf(!PHLl5opk<p%Gbo43PP@^ ztgS4Im&fNO%p^qpj_eH#?ag8LV*&ktwHX{_HYhZs>1#_ZS*9_Or3o|5W0t5LIr_J}z`;(TgPQo9IV|nwR8=h0KCBtt6zhADYEGPJj-tW+5tR-oNN6Bo6bL@AS%RE<^7CO>u$Z5AgIL|DD=kC5{i&P?pg zI7kG_5@mB3@m)jRBXnj~@+=`LYmM)0^i-R?l_yNwQl8ksD)2`=n`|&vq-^lCNVUW^ zI+@bPrES~0t@RV8z3gE+~c zpEamq%g0QECF^fxg?bjkrljd!O(JDDAP9inS5|P$#1mDtnS_~p$b6u0ZYqSNgRGP; zp-{EitSafcYpvfd@`HnbE6PmdRSD&IJ1cg@8^&|{ba~RO6*PRw(U6E?aaDY-@l|!} z7A){&x2#n8BxgyNVH$;G+9%D_WRG*$H_eC^YP?m;ki&jyreT~_8)e)--MFU6%pGMi zAkCz*#LSG|#(*t|#*S5u9r5<|=BE0(F1>7{9IK&1@(M{qb7S?&?yiQm)q2@rQ0|2| zu@CL+)68HivznfHQ0_e#QVna8C6mMZe&&9vsgiQ+p3|AdzuoRNn{BrB%Z7VWXKYY& zs^a0=SjO%-oiS$0Ik%Rf)XY|7>K@M-Q`hx}rtZ0%F?HjC*=14G2P>*`NSEn|dD{NvGz+fz0Jr7XAycqt2}5u1GoZKlYMdwORh%@&NS7&!{EWRj_ovgjV&8H*(> zQ1whk2JTs%F(@vL&ov`*vZf-KONQxpkLzr7YO1U~v-qdKapCT4!nJ#b^4>j-Gp-gf zxUtgaVQ*ML-J>{T?&c_F|Hb8#dlF}C1UpKmin@YvPvMLOEpbZNp$m7$HJ4FD+|xK? zi@s|STUNnbg{HPcuKr%Ys+PK>`^ft;K1y*wZ-(7n%V#84G`2Q&)HNsTo6OLl(jKEM z2v(n}boU`+j4i2D<(;1_)}aT@LnUX}M6TLYt%vdDJRvj_G?_7AVpg75NL6&pI;Mry zjJnzzlNClyte6#g)QSs%F;Ko}N~T>wmeDn_Nr7_)In2zyq@44B(mqZ!Qx)?_oX)~@ z@n&|T5E{(pRE&&e!cy?&&w#2OXtyqPw!A~8u z3|RA91NVF(G-27Fa-z&JVapB6errMSC2miFY+$g;t?buUf|2P|xhU56&H}+vc{`6}o61gLCbxuF00Q zohLT)+Q}Nc?a=>$?1Gtw%dWZ=Zmg_X+ulg-3^ogRxKZ&tsaBjO&!>rUs zM^D1S=;)}A$tyixP~WPmMbkEUwJ-5ntqzgA8iGH%*TRl5))rD}Vi6N>^{cck{ghpxnpuQQa8LYujYT^_!6D-_1#!R9=K>7MOkShG_toy_D^wudV%$}8iSQnsot zX@<(j#rd8U6b{<&eEtp~w ztb?aIz7{-FR%ErdQU!2Nae}=Vo~PEBYNUd#=AlZm#?*`|6}h6+-dN9qcW|yY@2VQj zYw4YZZ5{I(I?B6S8atZmiyC=hy|L4jo;)cs*}gwcULZ)#gm@IIPCeVB9@9?ruR`|U zqV&1P?p94VRXeq@Xf_b3v8Hw^S+>xEFJGG$Jl54Vw^JT2yVQd9B3orOk7{a6&M1b| z%wVK4RY6VI9%=LHh{{iPO>3unwH-y)enQP+A63cbHa=Ob#;V4v5rP?(+4RjwjQm?q zu&$vp9jq;*^x~zp3FBHFjmgMqQ%yIsQ;^1L?J@sn0 zsZbuReF23cHjk4wkdvf&^nry#nw+$ud67q3kYX{QjiFrBqNu3cYrPk>O7)_G0=Hm! zsHjCz>lL*sSE=pQQc;T+?C<+svu5@_Cnu#s|DXS-_jAMN(6!gBS+i!%nl)=?_MYJ` znB5c*!NzCSUyVWfD+dL%x*Zin1DqEE1KGsUP!zhy1f#)%=ZUxYwWs9g*_F#l1M-As>GxNi*-Y+Q>? zv3_hosLl?I^d!;-tRJxQojMzFw66biFyshQSBuw7P6Hu5UbOc`93F?%`>X(5Y!wMO zG;=*XeVN+!FZNgVFB!(fJx>AVr&?m#n1zmpm4@oDztN_72#VOOd*=^UflE0020Hr1 z02u^j7~l*s8V)TwoU?KG;$Rw|?%vL3-Wq0GLGC^27e@$&Vr?QUwebWn(D(f6+OpDW z*nTp;z&eix>6Bn>tjnX_^AlbfhG49G?m=qj^~vSk-5oNVE&{oUEk+1`!AJj4jdN;*IDaQjz63~sq=kijvZy};G8xwE~+9Y`SK92<|@Xf#FL zM-!)B#Db!>-_tDzfAbvpg7KrLz66Q3<}jSZq%r5rr#C!&+NOn%eJ}Z*^0B|_!U2a> zg1>jo>KpQQ{mb!ZKKt;r^P4994d3nwzV>VP*8K9|7pngFxewnJeEzMUzHa@{f6}K4j48<_pU-@xt^WS}|Ni;I zpFZp0$2M*FH1r|(+GkeW|El@nmDRU*o%z$h{_|Jy&7a_>e(=(Ve|^OR`%nJ+F`xPC z&LMnE$?pM*b6)xA(EIidF27-B&(AKp{QjwX;F|?M_rUk3erLt+{_BzHQ^(ET#IqhY z34ZF;?Vot@k)5A<`swc<`~B^A)ZrUG!GH6-(;oTZm-ZdFbH&cP&;3FKS9s`Ut(>;mV1 zt=%mM_`0Be{kUr?2)j}(xN2o;%hXwDhKr~6^|tty!F2^oLb&f@^<{w-c!Qo*(K+dTrCLTiLeiS_F)cE-(K>%GnP!AIZK$%y0B!b za0X_!EqA(N-UxHcYR2^0M~v6SGmjXn88eSW6|MeeUNl01Gv^!$_NqZNifx}a(i&FO z3!DahQ(xd@f8)$A8o}Hv=8Z77TDbT~$Z1*4ITHF*R&$P6)68<(d*iyAaYQ=FLbteG9yb9qmVcKV*C-S- ztqKLE1oI81#>`}e0<#3r{gQ*HQxS@pdlkZ4(3nA3T%$sP*#PJ(lH*y0VrHj8IE)Kt zhA=f|Zc!*O4*@w*}Ax zk^`si3luZ2C=~DnadRBB6f>m?1*RGhPp-t<+zJKeoq%|1P0S<}3e0~3BIg*-(G@7* z$+wC-;Boik1P6XGk3w;f2BDbAS191wkY>DazCs~vL<8ct^D&<6C{SQhfQkjzu25k5 z0Tl^utwI6M8PhUw!k9pTxx(XWJr3veC|#Gw-QaOIdE6$CyUXLA#^DrSml{nx)kQ|ebvrx=TQ7AB5JZ`JU?FGd1DaM&OMHY&gOBD*tCXc(zv)`3eR6j^6OR@0htkp}^b<=nTOPDFn`d*q37FE`fo2F1;E&#-{7-BeG&_Z~p5D@QgjhV|8 z3d~|aZxY-)6$%U&=qC!UL!rQ259nmUaT$$JVBQbtB*ERTP+&d|h-W>;%%>DWn**94 zI3DjoC@>ELqDPCFM-@Unur9?`jhSf*!Ja*?*5lskaY>I`<#F8}cZ9TG)-^~3I*mGKvMsjtsZy3$K7)(ZcY-7?^P&f z_9+yY8K>dvjLZ~I6 zO9gj}LV@`Jpt*v(Q=!283!qB`_pb`UzX0MnDKYa^g#z;mphrbR*nku$FpUbu%o2}# z8V4~wCN-Z}Vj=ivg#wcV#M`1`rbVH^bOGX#b1~DaP+-;psutYM3I*miKvxLv4ut~q z5kQv*dtKyVK$6qs)VnlHHTDHNEW0jd<-FBJ;R9zb!y{ZXO7 z{12cC!5vg6FtN8_EnIL#3Sl$_L~UR+RS2HnzNkDaiyICPbOMq$xcbh_iIeW4z<2;4npFQq!k6Yw%S9)BV z$6f1j>pkukk1ILLo(n(DbSQ+rrBGn@dfYybyYy_F0xLS$pis=*rchv>0n{Y*_>n?^ z*#)RkaL+3gm_GvI+5a)~Cxzfer&!K0)2I+)LO@SSY57=DCxn<#A&kx*cbCWAeXc#R zdYpMdp_tjL5XP&Y-DM~T(6NLiv3qVT+_iKd$^WT7$2<}CN0(0YZD?v;yrJ^i>nLNYZA~DYNC>UK!F^jHSUaF*!Tm@fL~ekt5!`--FeYE%>hZEdfvLFA;T9+a>-4w|k6Y_; zH+tL#kGsv|?((?1J#MSV-S2TbF0nUw!-vha5PXU%xR}_k2AhWo@ zEK?|EuJO1{fW9X=b}1Ay&ntwQzul(B%mRf1^DLn6OOBGuEQHyoLV?-rarb)MD}W#l zeDMMtBuEH0q!3!w` z?pFx0UWHACpHv8u3?L97#|DMqvlR-=K976JPn7V6pEP*3c>$*+&+(62J#(} z<6ebgW{X1b_kh}S*hYU+C@_Bm)G4^XD})hyKHgRlT#-V7ITg?njySeZ}=Bg6unl`2y0QV5o)P+-of!ZFRlWvW7fnGJ|1&Be?dg#r@?)FZemg%C#o z>K5FU3I%2bpkBePQV63TAWDF86$;F@%i)Vfs=_NQ6f?yNVa)Tmhdi#N+Mc z3So6-p)0peA&ge__MQZcRtjOXQV7}w#2ZFp<{^aw^G!fE3hqgTFoptpm*9S)P+)!o z=mx?4PNBg33DEU|`>R42LmR9F7(*38-*3bTu%fGb6vC`hA;cg}HWe|0Lh!|aekeJ% zD-<(NDHNFLi)?Dl%vK093_#CHj;9rhnH>tj3oN#&F*8pg^bbHkk{r7ff}JW9n1&@b zHD(qogt~d$dXIY^(2s@7beJ_ENTm?Gg~#plxc)2cd7IPL!p>?Rv~EjDw~RVw?gOvfc{f*oO-o|&;t}g z4v)Lh9LIK<^dYMuh_NF+jHp?vn}y=JSAV5!`(WA({g;D7bA31?Fi$ z?-AS%g|My+=w`v~QV5a)S}(YL3SpKC=-q-d%PoXeD?m31u2>=TWI(JXVsC|z7tk-H z<_qA;2w{v@2tC>39`ZQe+VxAxu}mSvB?<**E1>sFx%Vp+nEwDYB)D%X6qxS;+90?e zC={48QCY|F#k{py{FBl!ZRp@*ay(BBuB{#3nBJVC@^<; z+$N9P3Fz07WAaK1Vf|DgM96?Piu64SAwmXpo8aE95d1TsVZq(55TXaTb8<%Xpb%^l z&~K!)9SWfzDTMg%TAKcNK+j8#0}5f4T_Hp~t88k_+@TP30O-FYM@ff;paX?4 zt^&GUBweKtY|_*1@N^ZOILTbN+@Vm+Y*GlLWS33FD5(%ur~v&=a%@p3X0|GXSfJac zA{J06Fn0rbL2|sH5ZYIvz?Agh40@4tvOa3QQ-U4+-u%g|Mao=!1g0S)sse1oQ#HeL$hWd;-uNg8OHM&}#v)M({%l z!P{PE%xA+f}TC@I*(iDaW{M1 zT^@J0$1PZ6%pNIilS0@*P$)3F0o^V7`)`E;a{$oC1^0?Vff=_JHxmdhrV#uyAacfR zTOmX|*Bi4}O2cJZ0wLm2C@>RlaJY#I!E*unZ>tT3pbdr4Q{H7$(Nh${>I|SiNRGP| z!Wy?if%!S0Pl=?zQV4bh=pMoCQwXbcfc{x<2NeoTa3kJL6x?wN1?EkFJ}J1<6bj4~ zK%WrY`3eOX`m9uln-s#l4A37%(uWj+t`x#93ZTyjmzn3Dkgo8V4S2%G_tbIhz%2!0&U ze&EKL0}6q&LV@}4du(dVd`uy%-FV#79=BxBzDtT)Duh}p6qsKF+LFU^f2&YnUIg@c z!TnhwwDc{wg+p-p3SnFT^e2&dl|q>Jc-&@>tGg994oE%jRtUDM5IDcrrox64LgWVM z&ywSQg<|Fbg#z<3p!-CYR~5p((EIFL&e#`HC@?1j`jXJSS)st31?Y={J69p>!~yz( z;4W4uFrNcN31a4p3SpG=xSbxieFJV!5J`)NEQB=*g%IC+++7~`G@!pqj*0KL5c;`7 z*v$a+WszmMLV;-q^bNsvDioL-0DWC>Hz^dDVL%TG?w=IGcnRnM!QG<}>LCb+*S6quZU z!d{W!#wdg}3P3Ckb3cV(&v!Unp+Z;#_yBI}6{((82=8<#1poX&tgQ>@^A!rrMS#8~ zxVZ{p4+GG*1$VhZfoTHt9l; z+?@)+GXQ!*aGMpv3<%KUg1b*4tp0w;))K3~3I*nvO%8XgLV@|9$9>r29`(4#J?{4& z_Xm&ro5%g#r}3u{nP%VQKm zQ~>A)f}5xi<~V?UD7do~3d~GE&kF8Bg#uFwXouk93L!oK^nJlKDioNak6Ec=<^+WT z)9i66j~n*5fAYA8JZ_uEz4_yg-x&&FUB%;;c-;0+;6@D5M)4;t1fQr7=8YcrkjL!< z^s3~z^ivkXDv3hyq8@jb$K~H+%-Lj^Sw9s1VkH6@tG9 zv@=Kiy+YU{1@u$FJ**H$SU~?NxTh7uy8(cHCb*v|gm(h~{X}rTR|xwMfPO5vmlX;S zdSQ)6aQO;hmI{cHVwS29-g@!4fAhHSdfYP}_p-;m>T#1l?f6Ym2r=fPSmBd0PE`m! z?+L5{h%Dbw2)+)`F9f$!AWM_(-R$Dd4%hb#J4K;+oSzb7k(Ca5`L#ZlCiKu z3PhVbQ{vW|%L+MTj@3BZ>Kj7I2?DyIG!dTusBxOv}yzH-}cm0)pH@Jl~InsZKp9KEnfRFMY zy^L|Z#YoEFn}O_aPQJI|d9wbp>tHNzIFh{QXU(sZj5QZ(-itJ^E01N3R^G*$2e&wh9-S^o zPd#SOH^yA5`Ec8lv!mi3$mrVm9g27SC_im$9)8*UXDR8?U&}NfVc`KgarK~GSKyb; zuH%}&Qu9ak#y&v3WiNZIS)h5VG%w5U0X=Qh$$tgXsE_RBk1^HEi+l6c|?&x6y>G|$p3d7NyS zzUG~p2RCksPL6|4Fm^~8>9o1Lg-hy?R9aVm+6~)nblr{Rja`y=x#o5CVO>V6Ppjrh zX`ZOgm?vGnJhMXSS1LVy7yEvm#vr&2Onq8zaZG7y4sYB~>e&M$hRevo1Tx;xzB(i2 zzXj#H{?@Jdt95Ma!867-H}JN|XW@UcV>)9NjA@$Ixjcz`f0MW_*l0R+jWJ!*JNRjN zYpSPtMGAFgolx)G>x4hc;Av)Q<9|eK^O|+ynB5Cr9J4vwbL~JMK{@#g4?OiS zz<<{hw&T|-Jd>^q|57V!ly0rkIlhi3`A7Nk9dh!0R|frAc;=5jCrZDLbfCY9|5`c3 z9$b5@_xRjm!iA72a~!1o(8ma0_$dBORKB-rex{L*e=hBP8NA8E)sHa^>&P~gyuvrn zykGeaYu+gR&A?^SZ&do*mEQGTHwKY6^YARGJCybVN=v;kMxb6?Iecc`58=nWd}i<2 zqmBV!QbQY;G^|m zSv?}Lor`?h(^$Nd;WH8Z_z3;KW#AqCXCrvl#rc!ZNAQ%{;lB{#C2re{XX>a2G_?Es zm=67K4e5$YkmB-xS@BNK|BB}xq?3oWvs`mOX~5$vO3S*Fhm-khAzoy-7thSk`cj4m zHUHN`x?=h&C&NREcQSkq&&(T@;SuHW9~nHH43CC*kzos-nO}lr$nZ_gzdfWYo)nSc z3B@}ZK8|PRjmq$p^7vK;4=2NSLcGZEMLaV<+lzYmuIB$;ipBG4j`s`L(tQH_HxU6@Y{HDskYBoJlM5{=I^)!#Nf0ef>C}!o>#vZSlSBtDE~7 z4_v76z#jxpUW_d+9q8(6?o72##Q`*zNf3~RLEWJ9!=C>~j~nfj+H{RLK?ishL^g>a_wU5emrN9u`yFd#wLGK{!QTjMexsM^pkdG zlD|P@LDl>PhUtgCVPyY{q`~o&*=`}h9brb&U*n3AL(!DuO!7vySD6`iBG#^Q84vs! z^+-G0&WX*|Sv)&y5}HYL{1?^1Oz7YbX*ym+`@p$!Hm>}I=(Ua~Ac+m_!ZQx~>_|0t z4fM?K?H=f{_}>6un1(NJ?rKSOl;h08<;^XtoUPH$i%mUNXDT{6w2c2k-U+4@mI?zz z(dFG;{i(G$-w8VXJ<@PkdV3cRmAJvCI*uX_+wxRII;3TtN{lP9uD89rw;lWKLPz_V zY#MMxqu!H4#mfG*i*sWTft<`z?54yKMA z%sM-mb#yT6K=`ce{;M%wX5()FDBZ>_{O-`^w{i1x;Ng5D$E-Z2L#}+KbAFU`lr^Nq z#nwtYPHA1NM_Sf}bqMM6%rQzIWZ@n4X^b@ZRV3v&HVZB59rDdJMM}#6gmrT=yO@)- zHr~uN$1Cj#O3T>hIy9_{+fR((IaXVIbp6WetrThG%YRArCgppI=65nMJ)Jh!oT{{^ zWufiYvC8tzmG3{Phms81dEm<*W#GTm*(BwAW(F;Jxp|c1`&OkrD+_IDh741b_8g_9 z&KRdSot+orB@Q|t&!Nt9%v8Kr2^&Cr&bKaXyQreV z?8NcWk@xa(6mA2po6Pb6+ldfrooE*)1w zTzg+D&gI1#>zEUdfuUTAdbq#INRQU@$ggSZ0bQsM{omVB_GS2;3<21Fb48Z0{pR60 z>YtcSI<_I(xs2)P59OXNw^-T*_5-^V`{U7k(L9x!XMQ9P`O)TPW^McE!F}S>SqXcP zAFP4p^V{mEon3)vwkgZCc9Dy-9Vipl1eG>>Z0uOuR?u?1&DAn5Qgnkdihv+qoWPH{f?R1o%f}XM0fg zrZm|P-5xBD$1SqF5|ro0A^L`Feq;&g*e*-??|QbGU6-V-rTd&*^G>B*rnK4TD3QZh z?QvtGV4?{-n-;_Dubfmgg^sjV&fVcvjw!Id|VQ1nC4Z@u6mLyK^ z>rL@6Iq;#JsDAD>D9im7M-PpC4LKt=@j4DobLR;1w7Tng7@YL|X2`M}zuX+Ff7YA& z$6VkT`kwVod8V6rz_TZk z_X^GH`a>tu_>20qKF!x3$=9Z^D>I2_+ADv|YuA*jDcejI(?&MO_RiAbF% zI$T99?s|^14y45;i^@}va98{okH>w0RlF6`(vJ=CxDJUIK3M+a((o2n;Bg_{F&>9< zQ5DK@Iog8rE4Ib@NL!3J(l)I{GE;54a2&W9JlJQh0>3MB?0P^6`VGDiPBn9fA7yg> zM_j(?>g?fcHG(TJt^Jv}LL*xmsjgN#Kcrn3o9?zY9DkVP(ZdnHJptC#--{D4iB`U( zpQz<$(x0j_Wa3L~nZkzh(k3Pwway6NDMnBKZs{I?jxNt$%eejq&i2u323LRe#)pyxOJaC@&{W)Z$52AcgpOptc z#9yZWcpvhRegpqqPv4Sv;#T~pYPR8^38PDftJkQK{zC7dkLOi>DMaoOr zs1GM&51wgJA5a-Ts4`|>XN^P#X@|Fm-Y#n4a#)3A1kwY0H!BW=pa`et1_`~+xOU)qLSo21P^1JZ}6U(ytqwT5;=z4AOI_cuKn zul)mdLS5ejJ}kQv%xE_(H?z-_W!QLQ#&c`NGt3@+%*M*^0zZ!P9N(?&=bC?G87S*s zE$e%J?80?7*5xN_uW(~mh+B%g0A&nce=tPiPQ*lMqvHP_;&C}FE?<@L%dCGj#N!Hr z+9q71sAH8`|4Nv~yR$t0e?q+8mg8<`pzpI|Xh?z!l4@`<60T4|pmdHWZNbs9Zcvl?y3&3_X zV=fSxC*$&~<;@*l2hTu;AK*6|lPA`PFLts%t`9}~J?*#$_2U}pkC2D-Kjyy?de`6R zTS#xm$vm@D>3^#9Ok-afhraIm&(AcCd^t8+z1qISe*bg)n9ue5Uyug0zf{@}yK!Ls z-^0sia9wKxH^A{8GxhzMY4++y^~uqDYiw3Hb)A3YMDDZ+)53X2?uc}o#<_>vANv(# z6@MN^8r# zu3uB;bD@!iXHQ>j;7$hMz|=pGW`e=mVK-(tierD7sJLWLb1&DF=zC~qn6so-=rd(3 zk+ns8!xrN@t}*`?@a}IiYU-T!vY$ES?;7d%;K))^usKDY&SjJ?-TdQmdEO!EMQw-MZq7z^hnV+`w zXN#S7It=F?I+iqPI}n<89tx2pY(n29P<{Xo1}EkHeElGHbz=#&-rGu z=6S2;VL8;TlaFoYVAnrL6ZWaxVz!^7as7fcY(Iy0wjcFl>?@hR`EAUDywf$W(@T`r z+IFs)skE~q<1;e)Z&{&fPM@yMj+fJayYjl$^RoIReY#ENnhvGy%;4?p*zvY zJ2Yu5k%pY-Vu@bmb%VyfwykkXUR$`1Pu=I6REO+)_J#9iyH~3C$oQCTuhfl?*dOJ! zz};=hFdyq7a|FoZ{tzpN_aVPVJvf#OAn$VM_hN1(a+ZM z-}Owh?ZiB8ys&MWYi>~5cPXv20miM=m+Mnjci2Zz`kR#gT-49_`Lzgu|Dk?znWQ!k zVYCWmTCe#ocXK*>mu!6;SIT1XP1etH^nTfj3j3UEpDW_kaZK6l8XLSpb!iRee|7xk za@>g!RrY}11OEPYTA6maCkTMK3H8YvY&kY}VB_d}Y8$j)S+~}u|+BqFg7^G+vDx9pvr%^{Av zNjleJeJ(Z4EsUku9$cHb6*%`dZ1(uqsaK|jdO6m7O8MTSd?_RQ8OIHToN4pd<09h*_v^XeUx6S0$kWc7 z^37)D`I!h$)`vXd&xEIYhCSffo^Yo zZBaSCpuC*_i>_Z$4wlb<*=z69JX?MFIkN8L-go$N2Csj|v&ewlPPhD*yzW|C{pFYkG~a_hpY_2mR-wF{?{nP$hSEOdX~QydQHHZo+6n9JWOQTa ze`x+~nm?)|_F>U6N@AHdPri9f^L$hDxO$L3>0BRwT zIijPKVf#67Zwl)|kv@78Xf9@@qUTlA4bcG>cgkG zOc6W!UV1sWggmUXOVey=X+O*;4~f2BJ}u1X>*d;}zIlzbnX?zKdr1iUr_(LaqE|=n zb!QVeeu~d``T^SO%-5gDh+Vt-0WEcNyuJK3!H;qL-legps;j-fonH^7+?PS|uGQ_m zcpV>ckH|1i=o(V}j-YWR7air5F*jcF`s>vaB2Zo!tJyh(%Xd5`JbG8M zzR8+g+1!`p*0{tI&i8Rmk4RZpjUN&Ee!%t0$cnV&biRl0qh^$?q%EC2 zB0?+Ah_P*$$wx{F`v%uYBP-lej>|hDP4l`oI2L&$tKjm^p)iQFQ+66*QuIw~cE~n=cz{joDsDh)b^TKkP>iIQkRd=o~ zT(``uGdq`)^R?-$tj^B3F4m47ofIbAK?(cR86)cUv(X(!xxz2A+*u>rMc(h@8cI|??x|*!t1tK2lAU~6>Z^28vac`qTr>FD zmjW?6La+1f!M)TBIy|B$WYA?PSNWxvn}tsKSvqH1+~>|L7w;g+hcQ~Tx7lnwJ*}_} z+c^tgdGYZu+E3_&9qh*S`7C97I_yaHr+V>qZloXla+G=k$J+s9Jdzd_M3Xr)(^&*IL2ycTa_cn zZG1@N<=_C#`p7wmjxX2$xi*o>cL8|0wy1gyzT#@3tLXX&*G9-UTkpf9ZO3&@**slf9tetrIMaNv%rrbAbYsap$ zebry|lZ!q*Ll2Hls^I!b&q%qH&WncF*sc>& zwm#5DWov;v&c<2+XXv5>qM4}P*>_iE^o2I$bA4gO$oi3o)Gm|H>I^>Z$m{BV?Pz?Y z_Mshe4PETeZlib~$Ns`CB6*7=qpxJ72}f5h*U>X{Fwi63x}_VpAo%g@o>A#KyH}^s zd)p4_AC)J4YRHp*G^5QUbhZzm|H*lp&dx^m1H1_g-8p~PKT?lrJY9c4+sHhG`x&rA zMmD~#9~ix^91}PcMAquledAh`pH-jm385X@Ih(Vg8%D}3Qy=z6N5eJd3|*nmV#LIG zsm|W{&2_rp&Nb`6+wr(*WI5!)?=;XyY@gw|1DQP5BcHREo3rz<@f_;t`YG4ZGvvLt zue-|+sH~eSlWptP%^FbO z1@Y2~czpwPV!wTeq?MMJ$LkuC34H0-06CeS7tI@A(pX=bY^vAq5%Z&I*xjAqR65`7 z_l}9CH8sTRYfAC?pyfF>npRiZ(6G3+p5I%rym8UArqX0x)slF1gWXpy$VkH{g|+pX z@0e&>t^K|vh~g+i67u0ANtP3frfI$7_(-v$s%E~cdtsEOuC}2O-(%KZQRTm1ADaXxWmS>?5fI($)4)9C%V^N~U;r_NPZqsR!M^$*Tp zW|kWvlsY&cDs)W^WK~+eAYM^kTesBNo%5wa(|}5Vsy@E3Dc)dxt@ERjUS17{UsX}M zsI;oOlpm*Cd7Lj58V*2>OY7nxk;vlwspUg4oYM&j*dpCCNm~@Jud1wySB#=R=W~VDmQe$jR$X0Pi%%Y_YHO6|#Av_3kpMC%YTBEk zX;cPk%iKr(Gf@AhL}_GLs%fmKYQPAJp`x~?w6PIwr~KX=rA2c#;wzwdU2T1% ztAo;=8l@|*h6R8ACCluMwh^Ez-F7{$5 z|B`6BjB6Em$u0C7Z;7VcxS}4Bk&mY)Mbm9KkwlmAKK#t|^h6y_pG?-(R#%lTO~M7m zs}|wYRF!3NIxRz!WJ6OOhMI;3P)S|invDj-SUjn^QT?7ZDxIx_EA#A8>FVRr7-h<+ zbWmEN&e!*xQR#35XoEdp@!U~q=q=~hBcPSGJ12IN8XBsbmLzLR7nQ-gTp{06lh=i5H1T@4ED4y?-M!^^Q5tPcRb^$o z0!PDU9Y5woX)l~zR)t>U0ww&N(n_S<`I4PD^9kp=qlY(dqBU+WNQ?t27S%Fk(PIG2kGVF;^gp zu_t53kARkO{wBN}d5MqnYicXv$*LNJub7od|Hv_d!>h~*dTGJsS{%l)`l_;~aO}ym zcsV(kHkWUo%NZ}g$zzbf5Uaj>jPk8%tZJlZuZ-7Y`f2MsHkzh=f1Jg^rpxJ^YUV>s z%;=jeQ`=t(w7l9xDC;p6hZ$UxASoB_PGvnEF3G;<3Z`~Vt=7pQAMQ~^V@WMCguQ&eh>|5K(=wI6LV<_|E_`M6U z{|Eg$>J{;Z@+;6M!taf9jK@{tgalSPB=@+r6)?480=GxI}zW?h<-ky`cZ;VIf{6L^VsfYJ1Y{sd=h1S3cvgD zajsi`FU1)^c)jDi7}ze*Pm`bxu~kXu_;`;6I@*r z7s?{|TqAfmM2B{D7Q7n0#pPRCZ{)ObcgDmQt=!C%X57cwDC!3rXS?F_Nt5{ zUa61k+Akb*`2r04PG>pBrC*5!AT}rhqDXv!I%s}+vZPGUnVq(fm!8(Z$l9f$KALYa z`ep56geKfL5a;3g$(WEPUWTRNy4t#?x#yUf5}} z0k;-ZSerO$1YLD}ekm3_7wWW-vA>ldeb8cY@HDLyY|u;+-K zroQY;=;s`Maabqz#Nv%ADW=_x;nAu37qpUHs~PKYXgo|y z-TLl0$A=$*YA17L6lfX@ADb)jMr;RqJ3U6z5CGbRXKkY(#A~OHSBTa%Jr<_heAoa( z$E>S^N!xyH^&({oh4mfBhWW&?IQfr@;L+)XN0H)$#{#rqZT-^9+G=dCT3*Fr9+iQH z+GO2cZDl1E<|W4DScjon#=85}K190Oy7ZVWf^_!q6}5-IB4(T9$GY-bZp)RGBCt<1 zRbz^YWiYIg!9Oylz_2J~eGPeGiXm|rQ~3NW=MC)D;C-s)_%frpr(O5g9zdB7;@8Fb znjh;HH74WeNK38W5L-6dV{h#ki@35eS!LH&5K{uS>m~Vw>n%J+V7sm{mT>t}X`^w3 zr8ih!1$-{UkfwHWjHJ5|)zSpS+0&@Rf5#*bZZOh3g?vV&T2&gZ+a61tTT<0{{y5^? zk-Ca2Ca%h^A&r+jc+j-t?ek3ce1d(R?Vcw{UR%c#ZJK;{L3=()(n5Jow&~)3m_Cuu zi)yi~Ve9xNKEo;+U>=VDDa2tv**(9R&m3Y(>+4IkZB8Yw+#<;LG(L00s=#JUO*meh zPJDG86)ieE!#*!2g83%%84KFn`RDUn`3%1oE&nXyc&xD?t=#j7<7g&FdRbg4ad69J zTDLMjqo8w!T-%F3nW z$z6Z&AaGUH97c7YTFO#PqO^evvXWo$bm~Mxe`moz%vS&K4fIo(dAz16VLgLByb+(! zx3al6)w*mA-}~o5@tos5gmNCn?;VJL-8+yQ@P18lO>-Yk>*=RGx_4rDUu+VuBJm4W zI2UZ(;|o;xr5@xD*Ye7%>KHg(k*wqa+O#pu4T0l+MnePoWes-9tiA+a6JLzAXl*Kt zrSRvv=Z<+H@`+>5nvOXk(m9jl9Ar6zSx?x+iVio$hIw(zGX4b zwgu*hppP%XE>66<5^Xx48w)z3)81>Fd|$ca7O9UaN()2GkSKxLFvSO?mR z?fMvaFjn~lUKDWeMR87=*?#uZLi6IsBI8$LesvjC!S|6EE!yoxtq0n%HX|KjcP;#x zY(ge0vEJ%@^=r_&_CF-Q(we1)XTiF)i^owXjGOb}2}-LmMknJ7FdX2Ghj76;OPbZo z8yHKwmtTtoJ`ShaZ=Qf0PvTdFzT(#SP66D~-6!uxxOa{DEjW&Z#;byOg)b?uhQ0WM zP}k*9SVJQwS`nRoFdq_&__U1nnr_uf$2vhc51;| z$2jx}lvn3VWM0@k=$4YXr-OZiU)^FWhV_@QYr#e3fK9VpSuf$-n`de8oBr?EHX=*( z$wgsgqX_yi+UV1uJ3p(lH2NF2zXG_))u{4UcR;S0@ zbpCL3+?5md;@5HObF_S2Nwj**Pfx?fV7w+e#~PEK?zaGJTcz<`fVbjA-f`)9+|*Ul z3Nq91rWtu1GZHUTISF&MuLtQgHc4$MmY#;)`mp|m>1hpIrseeB-C=NSdO9N*gddf) zPQS-xNtfJOc1F6kpKL6O{)^J{Q%`C8EE(w)d<9aQU-B2H=jR&{qO86D5{ANrua>+HCV_ikmM z=QQAYy4T?D7q`BJ4xhvt6TSqt_O8#fY@DBK_zZ`lb;IdkmLA+vE|HP)T# z;UKinU{CF^%f$*A!m*J&%=&|`#l$WQaozx1S_J!c`)|KO`@cqJJ5Ia?5yy@eIk2@!u&!%N zXp?7wPe-e@N!Led@5J!zVQY_#OKER-=fcltaM!8DaSn!&!?i8$H??^G!jv6raIa}d zFAmg=L5in&VzR{Y#yDEM^mGMZ)uy*r+ZpT9>{LzWu{=l2?GfyO4&etZQ$O0#rl*TTJ%{tEO1f1pI(A?S0c$5&O4(@Jp0ptps(?lr02CagWw^``oG!JhU9kFV+O zcS*M1cvr&Zsp`Vfe(kGM+BZBt(Y&_3li${|UU-Khq{o+0yr+S4OxH&a(oUpmvUSC` zEVvZ{bJO?gM@dA@#Mj|4XSsKHCi=PaV+r`W z{<_ywqin&;0+IS@j1Pj-r9G)D#s1cSd6c9d7lf8Wu)H;(d@(i% zzPwgm02JL~Ob{GiS}ApVFyj>0RKrap%d^0h4;xca-_{ZN2J%Tkjd`!Tv4-rs3;@ zr7E+(!+`h(%>A_A<+-~Jh_9~o`)~PCd?jAYR{Akfyj}-K`x_g@%N280SL331t~p^! zidUbc%?hGvEIU&EG0`+M>de_TPY}gN*5PAOd}J-RFp4LAB<?%%}K2NAZ_8c)R>d z6i>PJ_C2=GU!!T#!EE~+h~n}7ij(=}D4uo{SyTR7G%bN|S(*|yRdw_~(R8+HB=0NH zw8$F!t5H1k%9U;R4#D4}X%YOvD1Lst79V-kJ9{@dSj55WdRW`Xv_YoI@=Xil2DoPF zuL1g@+}Y9Ap6Y0o`zQKrr_ID#|9+(IYH`tFr^Zk*$We&jW!S@VeV?&2&No{jT_1XN zKKD-e*EKCT-C|XE9^Jd>bKCpm5*!?aCg*wo3^<;*8I8p|x>v{?bGN3sxMvFUXRLvT zryutD_^2)`onI`+IAQ1JI?wfE0{vK9XLl=Y%f(PUPt$#4DhGV@caMmZd44EjXNi+t z{oe}Qb$XwGGj;S1dN zusjz(bm9vRWRej$x?&inIKm#&->P!8Ish2Nh$9LsLTA}Z_e%05I4iDke2xDUq7 z3pB*Q>OFjYWocx8&BszqTX02nLj4zFY8x9_e0dY_9H(5&cqVKOD_auTfkZ>)5aGtD z$)ID5d^0+XvrCyvuISVmV`!H=V;ybP-#ySFHuhW9i@RSH?}aur`3hLygBS-m_r47! zO4iokwNUOUV`!8wpXP@Xi;aXuI!(Z*S-O?{`^8@WYEb+yK;_DW#w+c&FV~hJg+j z&y(e4ZX7u%d8?}7n-|n#MG|kVC-J>Vb+yo8z$4tOs?Z1ZNT&7PC_!lWn8Ys@hdFRK}n<@ce}RsezDq$ zS6d?M85XY#9l9=EkAB3i&~I?p3HnBTN)F!WEAQ@I(Arxw(3$FOZ>hk+nq4U!_YOs2 z$3V`Vr-Ii$^zSXD;oSL9{*3FC&VQ7{7bZJbdH>=3;W+x@j4{Za1RNbVc&5GhVjRon z&Z@9S=!d>Y{4GugW4@>l21?dm-MDd4mNNC^TR(Q4NqJXZ-_zaS=GS<5H(I#=)!fsA zv)GeZ&|!HT6HY`r$6i-9&vh2xh&h>CljD8x(KR{l^*9~PV%i$r972N2bB4$(=cBfF zFHg4NR!A>XcKz8!J6GSWR(HB@r*dC6(A|#{>)crPm9)CybRgagkM?ssco$@*{@wbP zlV9rQ#t6vo^dMt!M|XEG__;bISXWv@Ur(y#!r46d)yEr$7}t}uDeC%{&`D;T!=W}> zW=pEQgKgvFQyX*=rqLosnlT-`UH;p_pKEo|@mz5{JjTmzRUr|{=)fm_O=e=u*2z7P@s=RekN^dqf#EIq__3re8OZGWt`?? zkt!@KHLM)yZ|z=#GiR*tuk7w^Nws<`^vw6q-1yx9UxDGn~Z< z-Z#+PQPR*qfY(z>X3U;8ec7V&Wy{;UmX%jeORY^o?!PFnsVyZ_tH7`p&IoVJPF>vI zHEZTFy&uvhy}>%XQC>YA11k_hFKZs?U-`NPQXw$M$+0?o-JF~_J*%NwQQhm%PuQ-n zn+0}nrnYmZ;B|ArcPv&HH$a?{saIZ9GPSE4ehk%GJPW@iQ%k1Sw&J&ZI{tS(o+_|U zI%_8W<%TI3=j5wPXLPI+ZB!a>BQTYO@gt(BlIns z6rpf$*)t{tNok_u!r4L~1y$fZmv{}xljZdY2>F2$cGGK|)FGA_bf$Xtb~d;4r4$`hqm@RLg%5Kxa|D^kk`R!FhQL|Hl5&hJG1>l@2w zluS)DLMbe&t>==S-c(C_Ukci5xnvFfU$S4|w(i~rtiag>+@Xt533-sOvAksJn%3DD zUwmQ7)Mgw>dHoG3Fvh}XcW-a12lw59CC>f>m#Rsxv!AQ2Pcr+pecu4D=KhY(wif3P z&`zUDrEOVqMLRs)jOoj&x>`C0T2lbw*=9_iIUD~j8^9Uuhs}h?<2Wt@orjT)KJpZk ze-hTN&D9tWlK5SNUo(Eo@w*!OXu-c$#wdIHHsE0tF)}Oqq0|ZASYE06etmvF^a*Z& z(8H{!F^;jFg!D7ukG+*C6QtK`%1yBKgEur0{jfqcs|IAn56g75Xqq^1pp6pq z7STk7S!!xb5_POK)%dpt?OKih_;)nad-_o#XSZp?f9x^+&~hKF`UYtQYiYAZ-z&vR z*_V1@#ck3v*mwHTT5p%uirRS+6rIYgA32VW_Im4zqeD)5ANqk3cqIP4>nPFh`A3PI z)>m_!=t6(s(*Ph^y6q9u&06U(>^1y*D-LWv8vM~)J33k^?>hXB26<9;oQK*pHtu~R>S+Zqu-R^ zrhs$cNzMV?|F$@l^$hDY6?L6~dWIhJq7h#5=&-A>PX9aR6QK=v!A^T%nVeI;mbFIx z{y!GkWG^r5GtqJL=!z%O{e!iR(R%yg`-M2VmPg%Mnb#3L)< zow!TIT;pi=5%gL}&^BX9xdZtxIw}h~q^UqMsy28?KXvb6~eh$$$BG zG_=FfBqA^yh(<_kg`=mRjAmEX{$?Jg z{c*--|Bi-srKCrToavFgo4In;D?MhieqajDq`d(D&BE_(vhJnLa@5o}jICW=ORzE+ zo!6(&iMXmY1-jt)wL*F#d*uww;O&2Q7wPC}?`ZwQxnFcH=3=4}tZd$h+8?fk*xef& zRUbY2uycfVY2Bn*g;?c!%o|+YLv0=YOvSAT{-3`(()-;b(B&&msT#-Vy0>Rx-{IcusR4UL*fXW3r0BET|uK=1QkU0})LJE`*s9m6mfG!p2R6z3tDgjg`&}2ZB z0!;z5OrY}t(Wb|m>45lh)mSqdP>(=O!+WnaMPH3itQ$^DSUB8NTt6Hy1YEH21*Dt7 z?Gxwj73ivOKFvSU=lp~8W;i|pEQ`Uu5bO);l=Xyk)*=6YkRJTgL@tc*g}j673eCXD zE30sP$V%2p{-+`o4krp1UTcP%3hEsulG)aGaPN}E8`s_YAipJgfI|N1^TYAtC&|hn z`;$2WG!+cqkZ%UY&Dys6J|>`=8xs#WEfx&L?;TusuUS_x9KUz>?I0Lj_nhf37<}sB z?)4;Zdb;Sord@-NcN8t_f$R^ z--7%Q`>Fa!*Qr9 zzH2yfZ(a`CZf;rrYEk92Af#dkPFWS-H5S_2IN>SRu=%jSp`1OZ3^(l>jz7Dxa7SKZ zS60miqS@W2Q>sMq@OY?bW8q^%i7ijYH?#cVrU!!U_CpoVn;vk)g+-5SyLDT?n9T~$GqGu?`Z1af zTi%zw3GKhJF~?fTCUClg9p93K`hsZ`4;P@!;rwTY6PupMFEG20LF*sdX!;{YlS^&k zFKRP)fJ1>rn|>V3mT5!ck8FRYzwq6%IK5jsbE7}f{=EZiSCX^*?*&4G+kOA0U-OP9 z!VLKrJ{f<7{6H|cHb18?f9AG5=RAnkH>;kZT@Du%Ju+eZ;IH%hj{zm|d&U7^0q>8$ z!rtMf5&wAe-eM3fTDKW4<)t@H*JH*dUmL3`>bsPza35-7#^S3 zv^}p0wrw5Q?$07S1`>9l19`=CNr^3aiS5!)wt{e|>3(V#IqUMz8-HHY_Vb8)dT`wi z^xuuQvTj4SR^$I0H?np^8|UHwdrsWgw0`JLL5oU;ZYA1vO*pp1PI|%3;srMk$9Lw% zw++R2!u;nZo-G=zLeoeI#|<~_Ec#mRkd(8h61bfHlULq&Ts9*@kuaZ~aOk1ZiXPc< z>kpu$Z^FulT!z8}DR`Ape2k1?L}pW^jA)+?T{U z9fzC2VenyTHVji6vPv+VxO;Bm>D6O)Hwv+|Y=3;X>5jQgclVCjeVGVx+uZmjkj&u2 zOB***M<|`@v87L7=>=N)t=n!KvwJK_?-WhnNgbmiL!#B;#4SS`X=iXrLrr%K$2Sed zZyVl7A%`}y^xYqYZ9A>Qr!`UQp+nr6m)M4uKs(HBg4RC*twT5Qhu~}uK=FAC^I>t% zLqB^(TV>}T+z~2fIKk}jZd;sp!|?gSaQyzf`13>Y=Y|t|hc>cn4d2QC5B@%9$O6*e z3X0zM7j%>1TbXun@~!ML!-*GA%yab{Z#@8{v-85C_)EKgcI&*t z^7+~+8{<1%Q4@yZ+lLd|(aUzgJ9r5YN6`6e4D>PZ+s$KFIp~)m$iBQ_p<{)7Vi|+m zg;jhzdh?F7`dWP`t6H*JKvs#u!Mz3hi;7F}zw!B#v-2x@Bt8N03@myRe3Xp1GDbq= zyu_wxF&M5G`DigOfV$|B#01o#1iBwCL)eEQ=>3Ta8wztR0zn&aL#2p|w!;hUfKT$X z9aO(*0{nW3ZDMA~eSg!04HF71V(?MMn?sl9?_P(3o{T?4y^5aE2oH#sis#0Q`_Ezs zwve+OG=V^>s{&gou{nkj5?H@Ke#eIR=b;#6!GMaoe;#Bp;ZZWwbQ=k8L-#{T+Y$HP zCQ<#?(UtHU&_W5Hzx7*1xBe5d*-8yuyfJ6l zjqP)K(N~)$K#uLm{Qz=@vEGLG=k}bOC7}=rQZ{1KhrB?j>E}X|{T=GNdl&w9?b+9! zZH>EdaGSU9Vo0R+0o&T(Y-4&-4TV&8hGl9Wr$_7qk?|xN*}{Cp9Ka9N z!RE4cEV0VdX;W&IPvqxL%CM_FQ?AXI9s#_oq4r62EXVATAV2G*E%eue+t)^%b=w`z zf9`-Uox;lEZ+pbAZjHeAMBvteP8_2m-`n?@@omW3OPXuO{7(ax0@w#2`Zr?y_VKU|ibxclRaRoy;!}Wzj3-fp1 zBk71J(T@s-iifKThZcw(H$68Te-5$z!5hcF8_CZNUVLyhLwL6S?rWK=sSpmStUx*` zokI@zv7v(D`h1Iw7q%5mn^*9uzih8~m(M$md2Mlw`RHzk5-$}k-qu!hLVWL&@#ooT zpNtC!8IsRNY*_S2u4~zRbn^)aiQra-7#O|8V5aG%JwFuU>ku;*JyJ0E^3;Ko!3(W| z(fS4c11=KZ9uT_umd?fVWIFp=gQ;cHJ{a>}TiEbZ!~1RFgD*_~Xx>vN>>olLHLwqP zWfps2&%evGhB^_hu97z1cpjYgp`-4#r8ph!KA+y92^Ly5*?P8}l#iTtvhG$nv$kEE zyV5)#Yt*@|m8Gz~tkC@G&tqo&fYLyF?RCZT%8JaaZF%25VIP>bmrW=>8xtm%zN&6w zt4{=Q`Kcg_@BC!q&WJ0OZvbb4D}kTkONd zFr7X15Wnb=g_AKLz*(^CNX>Q#56HVfKL$|knvJp}+V72TKEF>4#$X8;Gf=Qy=9 z+iS7B^GfpS!R^x{o%0{+L(+dL*nb{+5J&5b>_0F*46CAe^qdz4*S&zAa~JItrsKll z!r@Z*tHR-@oWUat2R3wqTty)|-Zj+p{7~XKM9%1SbIS?_Fe2gU`MC=V`<->{E)&+U z{DR@S!b7sdTyf`6V#jdP4y?Z@J3Q@7WA`W86K93&kP;!7-M=JG0uWfL?>a*;+;s=c zfI8=gNhBjEES2J5L^72fg36K`6)1O^finlu4a+!`MZ~i zSTKeKlR*Mwc-k4m(@3$>70mjUn)yQQa*4wBDr@3@$$RvKA49zMDr@55vo&$|ys8Q& z?j8V?o{DU?mG&2%n|OME(b7kyoyO@!o+wx-b`CZuozi)OJCUi8${H#$-!-TAe~#PE0epBvZ`s< zbZ3zW5he`f$Rgns;K$lUMrV>3d+bUt7vOen%zp+E-<~(iYH(gU&6Dx1R>}!j6z)gA zDIUDo3=}>Yzn9CyyQiR7w?fQi%jY>u$J!&7EwLQ)yewNjk2OhIw)~@1_jxQEBOr_} zUB86Ip1h`g;!a*V*gyW}b)06tdkuo(eRJbGSF<>p$LundBMVs@dsRQ z^=cZkn^P01H@xffSd1RR3Zq?V+=4K3h>MMzb&@f57=fzz6f6!f8kUvoif>arT&~BLg{WNAb#&i3m)9QEMmaUejk9UD%fiH%d-ACxEK0- ziN^Y5{DA$(txwXy)#cA!n7g2oRu3 zzyOsVNONctS|u$B6lfqV4Ios~LsA-=HYEqzVhgDu(h#H7p#q9dQPj@Z8LER=5VU1F zv?yv}>WEsMfT)e>j0K}st<(4Szt`UT+55>;aB$xD`mXDneO=G9{`+2Q-D|CTo$qzn zP6I$I7R>8uC>dh()*kI%f7I*r$DefN46P87W&wU$Y4VTKKcO{^L|PGuJXU||s6X4E z%qMt%_!g-@S>0=?EleDS-c3Wrz*Z8H?S{2EmoxLdWA9sBpDwpV2GWq)aEdj(N&DPt#`RHby%y*|(DILQJk@N(}NbP?;DTd?6(X_a?K zzRUL#?W3COsvpJ1!)n*BvdnVV04c$eVFH8h{O*C=T>~^?zC$k;hk0Y3HMRMRuk_U) z-I$S0XiR=tzzVz+?>d+MM zIkIX|UW4_A+qCu^o$s(hm_-C#A+(+nSqA-D&W1~J8TnFD{v~Be z!6{WZ2m9wz+p9ukorC?J)b=VL8QlY;cMY5XuQ4;TTn>GU6ojQBW7i=0pVK$0d*JRD z2mCUz>(xkxjNSFC(QhTpKwTDDgR%Ob6>m5x`5W8BiF<`GNVC*}IOYx#^u*;Cqs^2qLZf)%0Dj29*vc;*>UKpWM#PAK^B| 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�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ⅅgO>YUZb1U-0Q&`hw%_G{ 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